对象的几种创建方法

创建对象的5中方式

直接字面量

虽然Object构造函数或对象字面量,或者Object.create()都可以用来创建单个对象,但这些方式有个明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码。

工厂模式

这种将创建对象的封装成为函数,调用函数来创建对象。用函数来封装以特定接口创建对象的细节.

function createPerson(age,name){
    var o = {};
    o.age = age;
    o.name = name;
    o.sayName = function(){
        console.log(this.name);
    }
    return o;  // 不能确定对象的类型。
}

var p = createPerson('zhangsan',25);
p.sayName(); // zhangsan

在上面我们创建的是Person类型的对象p,但是却不能判断他的类型是Person。
工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题。

构造函数模式

创建自定义的构造函数,从而定义自定义对象类型的属性和方法。这样就可以将实例对象指定为特定对象了。注意,该模式直接去用this定义属性和方法,并没有显示的创建对象,且没有返回值。
改写前面的例子:

function Person(age,name){
    this.name = name;
    this.age = age;
    this.sayName = function(){
        console.log(this.name)
    }
}
var p = new Person();

var p = new Person(); 执行含义是:
1.创建一个新对象
2.将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
3.执行构造函数中的代码(为这个新对象添加属性);
4.返回新对象。
注意: 若将构造函数当成普通函数使用,this指向windows.
使用够函数的弊端就是,方法也会在每个实例上在创建一次,浪费内存。

改进构造函数模式

为了避免这空间的浪费,我们可以把函数转移到函数外部。

function sayName(){
    console.log(this.name)
}
function Person(age,name){
    this.name = name;
    this.age = age;
    this.sayName = sayName;
}
var p = new Person();

在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域有点名不副实。而更让人无法接受的是:如果对象需要定义很多方法,那么就要定义很多个全局函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了。

寄生构造函数

这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但从表面上看,这个函数又很像是典型的构造函数。
寄生构造函数模式与构造函数模式有相同的问题,每个方法都要在每个实例上重新创建一遍,创建多个完成相同任务的方法完全没有必要,浪费内存空间而且使用该模式返回的对象与构造函数之间没有关系。因此,使用instanceof运算符和prototype属性都没有意义。
适用于对象的包装,类似于java的装饰器模式。 返回一个包装对象。
基本样式:


function Person(name, age, job){ 
    var o = new Object(); // 类型是Object。 和Person无关
    o.name = name; 
    o.age = age; 
    o.sayName = function(){ 
        alert(this.name); 
    }; 
    return o;
} 
var friend = new Person("zhangsan",25); 
friend.sayName(); //"zhangsan" 

应用:让创建的Array对象拥有新的方法(在不改变原有代码的基础上)

function SpecialArray() {
    var value = new Array();   
    value.push.apply(value,arguments);   
    value.toPipedString = function(){  // 对Array对象的一层包装      
        return this.join("|"); 
    }  
    return value; 
}

稳妥构造函数

稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:一是新创建对象的实例方法不引用 this;二是不使用 new 操作符调用构造函数。
特点: 没有公共属性,而且其方法也不引用this的对象,instanceof失效。和寄生构造函数的不同在于不使用new来构造函数,同时实例方法不引用this。

function Person(name,age,job){
    //创建要返回的对象
    var o = new Object();
    //可以在这里定义私有变量和函数
    //添加方法
    o.sayName = function(){
        console.log(name); // 注意这里访问的是形参的值, 并不是对象身上的name属性
    };
    //返回对象
    return o;
}
//在稳妥模式创建的对象中,除了使用sayName()方法之外,没有其他方法访问name的值
var p = Person("zhangsan",25);
p.name = 'lisi' // 即使可以为这个对象修改了属性name, 单sayName访问是形参name
p.sayName();//"zhangsan"  

原型模式

使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中。

function Person(){};
Person.prototype = {
    // constructor:Person, // 这样添加是可枚举的
    name: "zhangsan",
    age: 25,
    sayName : function(){
        console.log(this.name);
    }
};
// 默认情况下,原生的constructor属性是不可枚举的, 所以最好设置为不可枚举的
Object.defineProperty(Person.prototype,'constructor',{
    enumerable: false,
    value: Person
});
var person1 = new Person();
person1.sayName();//"bai"
console.log(person1.constructor === Person);//true
console.log(person1.constructor === Object);//false

上述p和p1对象的属性和方法都是共享的。原型模式问题在于引用类型值属性会被所有的实例对象共享并修改。

组合模式(原型+构造函数)

创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数,是最适用的一种模式。

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.friends = ["zhangsan","lisi"];
}
Person.prototype = {
    constructor: Person, 
    sayName : function(){
        console.log(this.name);
    }    
}
var person1 = new Person("wangwu",29);
person1.friends.push("zhaoliu");
console.log(person1.friends);// ["zhangsan","lisi","zhaoliu"];
console.log(person2.friends);// ["zhangsan","lisi"];
console.log(person1.friends === person2.friends);//false
console.log(person1.sayName === person2.sayName);//true

动态原型

动态原型模式将组合模式中分开使用的构造函数和原型对象都封装到了构造函数中,然后通过检查方法是否被创建,来决定是否初始化原型对象。

function Person(name,age,job){
    // 属性
    this.name = name;
    this.age = age;
    //方法  检查sayName 是否创建
    if(typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            console.log(this.name);
        };
    }
}
var friend = new Person("zhangsan",25);
friend.sayName();//'zhangsan'

猜你喜欢

转载自www.cnblogs.com/cyrus-br/p/10493304.html