对象在所有编程语言中都是核心内容在js中他的创建方式也是多种多样,每一种创建方式都有其利弊,下面简单总结一下;

Object 内置对象创建

最简单的两种方式之一,直接利用系统内置的Object 来创建,系统内置Object 只有很少的方法属性,用它创建十分安全

var person1=new Object();
person.name='xiaoming';
person.age='18';
person.sayName=function (){
    alert(this.name)
}

var person2=new Object();
person.name='xiaohong';
person.age='16';
person.sayName=function (){
    alert(this.name)
}

person1.sayName();//xiaoming
person2.sayName();//xiaohong

这种方式优缺点很明显,优点是简单,不需要额外的代码,直接创建就好,方法属性都是挂在自己身上;缺点也很明显,这东西一次只能创建一个,不适合批量创建,假设遇到重复创建那就让人崩溃;

字面量{}创建

这个跟上面的利用Object 内置对象创建是一个意思,本质也就是一样,{}这个东西也就是Object 的语法糖而已;

var person1={
    name:'xiaoming',
    age:'18',
    sayName:function(){
        alert(this.name);
    }
}
person.sayName();


var person2={
    name:'xiaohong',
    age:'16',
    sayName:function(){
        alert(this.name);
    }
}
person1.sayName();

person2.sayName();

优缺点不用说,跟上面就是一个玩意儿;

有了上面的缺点自然就要想办法克服,对于相同的东西人们喜欢抽出来,相似的就集合封装,于是有了这种东西

工厂方式

function ceartPerson(name,age){
    var person={
        name:name,
        age:age,
        sayName:function(){
            alert(this.name)
        }
    }
    return person;
}
var person1=ceartPerson('zhangshan',18);
person1.sayName();//zhangshan

var person2=ceartPerson('lishi',20);
person2.sayName(); //lishi

我们创建了一个函数用来返回所需要的对象,把这个对象所需要的信息通过传参的方式传入来构造不同的对象;我们在函数ceartPerson里面有一个原料person对象,我们就是通过改变这个原料person对象的属性来构造一个个对象,这种作业方式很像工厂的流水线作业,外面来一个,里面加工一个,所以这种方式也被形象的成为工厂模式;

但是这种方式也是有自己的缺点的,第一个有些难为强迫症患者,就是没有new 关键字,对于人们创建对象的固有认知不一样;
第二个相对致命,一个神奇的事情

alert(person1.sayName===person2.sayName) //false;

这就很郁闷了,这代表着什么呢,这就意味着从这个工厂里面出来的对象每一个都是独立个体,互不影响,他们之间的方法并不是引用同一个地方,但是明明功能都是一样的,所以这种方式会极大的消耗我们的系统资源,这显然不是我们乐意看到的

第三个缺点,无法使用instanceof 来判断自己的来历;在前面提到过instanceof 可以用来判定 对象的隐式原型和目标的原型对象是否在一条原型链上(更加官网的说法 instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置),现在使用工厂模式创建的对象却无法使用instanceof,这就导致原型链混乱,这显然也不是我们乐意看到的;

var obj={};
console.log(obj instanceof Object) //true

console.log(person1 instanceof ceartPerson) //false;

构造函数

function CreatPerson(name,age){
    this.name=name;
    this.age=age;
    this.sayName=function(){
        alert(this.name)
    }
}

var person1=new CreatPerson('zhangshan',18);
var person2=new CreatPerson('lishi',16);

person1.sayName(); //zhangshan;

构造函数,主语是函数,所以这种东西也就是一个函数,跟其他函数没什么区别,只是作用有点儿特殊而已,是用来创建对象而已,就像医生也还是一个人,只是工作是救人,所以我们管他叫医生,管教书育人的人叫老师,所以函数该有的操作构造函数都有;
这种做法比上面的工厂模式略有简化,首先在构造函数内部并灭有显式的创建对象,也没有显示的返回对象这一步,
所有的操作都在外部的new 关键字做了
首先new 会在构造函数里面偷偷的创建一个对象,然后使用call 方法转换this 指向为该对象,然后在偷偷的返回该对象;当然这只是简单描述构造函数的创建过程;

console.log(person1 instanceof CreatPerson) //true
console.log(person1.sayName===person2.sayName) //false;

结果很明显,每一个出来的都是单独的实例对象,方法还是没有共同,同样存在了上面的问题,但是他却解决了原型链的问题,可以使用instanceof 来判定他的来源;

原型模式

前面提到的原型链顶端的存在,会让这条原型链下面的存在都具有相同的方法和属性,我们可以利用这个特性来创建对象试试

function CreatPerson(){};//创建一个构造函数,主要来利用这个玩意儿产生原型对象;
CreatPerson.prototype.name='zhangshan';
CreatPerson.prototype.age='18';
CreatPerson.prototype.sayName=function(){
    alert(this.name)
}
var person1=new CreatPerson();
person1.sayName();//zhangshan;

var person2=new CreatPerson();
person2.name='lishi';
person2.sayName(); //lishi;

alert(person1 instanceof CreatPerson) //true;
console.log(person2.sayName===person1.sayName) //true;

结果证明 从Person出来的实例都是对他的高度引用,新对象实例的属性和方法可以重写覆盖;这样做到个性化的操作;所有的实例均能共享同样的原型对象,所以也就解决了重复创建的问题,也解决了原型混乱的问题;但是缺点也很明显,没办法初始化参数,用上面的例子说明就是所有从CreatPerson 出来的对象实例的name 属性初始化都是zhangshan,这是相当危险的操作;

混合构造模式

既然构造函数可以初始化参数,原型模式可以搞定原型链混乱,能不能想办法综合一下呢?

function CreatPerson(name,age){
    this.name=name;
    this.age=age;
}
CreatPerson.prototype.sayName=function(){
    alert(this.name)
}
var person1=new CreatPerson('zhangshan',18);
person1.sayName()//zhanshan

var person2=new CreatPerson('lishi',16);
person2.sayName()//lishi

console.log(person1 instanceof CreatPerson); //true
console.log(person1.sayName===person2.sayName);//true

可以看到这种原型混合构造模式能够有效的解决创建对象过程的问题,使用构造函数加属性,使用原型加方法;这样既能搞定初始化参数的问题,也能解决方法重复创建的问题;他是一种较为稳妥的方法,缺点就是写着麻烦了点儿


墨韵
109 声望0 粉丝

下一篇 »
一个tab切换