js 创建对象的几种方法

1、 使用object创建

var person = new Object();
person.name = "Tom";
person.age = "29";
person.job = "software engineer";
person.sayName = function(){
    console.log(this.name);
}

console.log(typeof person); // object
console.log(person instanceof Object);  //true

 

2、 字面量对象

var person = {
    name: "Tom",
    age:29,
    job:"software engineer",
    sayName:function(){
        console.log(this.name);
    }
}
console.log(typeof person); // object
console.log(person instanceof Object);  //true

使用字面量创建对象比使用object创建直观一些。这两种创建对象的方式都有明显的缺点:使用同一个接口创建很对对象,会产生大量的重复代码

 

3、 工厂模式

function createPerson(name,age,job){
    var o = new Object();
    o.name = name;
    o.job = job;
    o.age = age;
    o.sayName = function(){
        console.log(this.name);
    }
    return o;
}

var p1 = createPerson("Tom",29,"software engineer");
var p2 = createPerson("Jerry",32,"doctor");

console.log(typeof p1);  // object
console.log(p1 instanceof createPerson); // false

工厂模式,可以使用同一种接口创建多个对象,且很简洁。但也有一个问题:无法确定该对象实例属于哪种对象类型(instanceof 无效)。

 

4、构造函数模式

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

var p1 = new Person("Tom",29,"software engineer");
var p2 = new Person("Jerry",32,"doctor");

console.log(typeof p1);  // object
console.log(p1 instanceof Person); // true
console.log(p1 instanceof Object);  // true
console.log(p1.constructor == Person);  // true

p1.sayName(); //Tom

//构造函数当作普通函数来使用
Person("jack",30,"driver");
window.sayName(); // jack


// 在另一个对象的作用域中使用
var o = new Object();
Person.call(o,"Kristen",25,"Nurse");
o.sayName() // Kristen 

Person() 函数没有显示地创建对象,直接将属性和方法赋给了this对象,没有 return 语句。

使用 new 操作符创建新的对象实例,调用构造函数实际上会经过以下步骤:创建一个新对象,将构造函数的作用域赋给新对象(this指向这个新对象),执行构造函数中的代码(为新对象添加属性),返回新对象。

构造函数也是函数,也可以正常调用。

构造函数的缺点是:每个的方法都要在每个对象实例上重新创建一遍,上面创建的p1 、p2都有一个sayName()的方法,但这两个方法不是同一个Function的实例,因为每定义一个函数就是实例化了一个对象

function Person(name,age,job){
    this.name = name;
    this.job = job;
    this.age = age;
    this.sayName = new Function("console.log(this.name);"); //逻辑上与声明函数是等价的,并且每创建一个对象就要执行一次
}

var p1 = new Person("Tom",29,"software engineer");
var p2 = new Person("Jerry",32,"doctor");

console.log(p1.sayName == p2.sayName);  // false

当然为了构造函数创建对象时,每个函数都是同一个Function实例,也可以使用全局函数:

function Person(name,age,job){
    this.name = name;
    this.job = job;
    this.age = age;
    this.sayName = sayName; // 使用全局函数
}

function sayName(){
    console.log(this.name);
}

var p1 = new Person("Tom",29,"software engineer");
var p2 = new Person("Jerry",32,"doctor");

console.log(p1.sayName == p2.sayName);  // true

但是这样,如果有很多函数,就要定义很多全局函数,没有封装性

 

5、原型模式

每个函数都有一个 prototype 属性,一个指向某个对象(原型对象)的指针,原型对象中包含着所有实例共享的属性和方法。那么就可以使用原型来新建对象

function Person(){
}
Person.prototype.name = "Tom";
Person.prototype.job = "software engineer";
Person.prototype.friends = ["Shelby","Court"];
Person.prototype.age = 29;
Person.prototype.sayName = function (){
    console.log(this.name);
};

var p1 = new Person();
var p2 = new Person();

p1.friends.push("Van");

p1.sayName();  // Tom
p2.sayName();  // Tom

console.log(p1.friends);  // "Shelby,Court,Van"
console.log(p2.friends);  // "Shelby,Court,Van"
console.log(p1.friends == p2.friends);  // true
console.log(p1.sayName == p2.sayName);  // true

很明显,单独使用原型新建对象时,不能传递参数,并且会因为所有对象的数据都一样而不能添加某个对象自己的特性

 

 6、构造函数和原型模式的组合模式

function Person(name,age,job){
    this.name = name;
    this.job = job;
    this.age = age;
    this.friends = ["Shelby","Court"];
}
Person.prototype.sayName = function (){
    console.log(this.name);
};

var p1 = new Person("Tom",29,"software engineer");
var p2 = new Person("Jerry",32,"doctor");

p1.friends.push("Van");

p1.sayName();  // Tom
p2.sayName();  // Jerry

console.log(p1.friends);  // "Shelby,Court,Van"
console.log(p2.friends);  // "Shelby,Court"
console.log(p1.friends == p2.friends);  // false
console.log(p1.sayName == p2.sayName);  // true

这是一种常用模式

也可以对其进行一些修改:

function Person(name,age,job){
    this.name = name;
    this.job = job;
    this.age = age;
    this.friends = ["Shelby","Court"];
    
    if(this.sayName != "function"){
        Person.prototype.sayName = function (){
            console.log(this.name);
        };
    }
}

现在自身属性和原型的初始化,都封装在构造函数中,看起来更像面向对象。这样的写法下,不能使用对象字面量重写原型,因为对象字面重写原型不会让现有实例和新原型联系起来,与现有实例联系的还是旧原型。

 

posted @ 2019-02-20 15:09  zhanglw  阅读(205)  评论(0)    收藏  举报