javaScript之创建对象的多种方式

工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
function Factory(name){
var o = new Object()
o.name = name;
o.getNmae = function(){
console.log(this.name)
}
return o;
}
var p1 = Factory('blue')
var p2 = Factory('yellow')
console.log(p1.__proto__.constructor.name) // Object
console.log(p2.__proto__.constructor.name) // Object
  • 缺点:对象无法识别,因为所有的实例都指向同一个原型。

    构造函数模式

    1
    2
    3
    4
    5
    6
    7
    function Person(name){
    this.name = name;
    this.getName = function(){
    console.log(this.name)
    }
    }
    var p1 = new Person('blue')
  • 优点:实力可以识别为一个特定的类型

  • 缺点:每次创建实例时,每个方法都要被创建一次

    构造函数模式优化
    1
    2
    3
    4
    5
    6
    7
    8
    function Person(name){
    this.name = name;
    this.getName = getName
    }
    function getName(){
    console.log(this.name)
    }
    var p1 = new Person('blue')

优点: 解决了每个方法都要被重新创建的问题

原型模式

1
2
3
4
5
6
7
8
function Person(name) {

}
Person.prototype.name = 'blue'
Person.prototype.getName = function(){
console.log(this.name)
}
var p1 = new Person()
  • 优点:封装新好一点

  • 缺点:重写了原型,丢失了constructor属性

    原型模式优化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function Person(name) {

    }
    Person.prototype = {
    constructor: Person,
    name : 'blue',
    getName: function(){
    console.log(this.name)
    }
    }
    var p1 = new Person()
  • 优点:实例可以通过constructor属性找到所构造函数

    组合模式:最常用的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Person(name){
    this.name = name;
    }
    Person.prototype = {
    constructor= Person,
    getName: function(){
    console.log(this.name)
    }
    }
    var p = new Person()
  • 优点:该共享的共享,该私有的私有,使用最广泛。

    动态原型模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function Person(name){
    this.name = name;
    if(typeof this.getName != 'function'){
    Person.prototype.getName = function(){
    console.log(this.name)
    }
    }
    }
    var p = new Person()

使用动态原型模式不能用对象字面量写原型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Person(name) {
this.name = name;
if (typeof this.getName != "function") {
Person.prototype = {
constructor: Person,
getName: function () {
console.log(this.name);
}
}
}
}

var person1 = new Person('kevin');
var person2 = new Person('daisy');

// 报错 并没有该方法
person1.getName();

// 注释掉上面的代码,这句是可以执行的。
person2.getName();

这里就涉及到了new的底层执行过程
new的执行过程如下:
1. 首先新建一个对象
2. 将对象的原型指向Person.prototype
3. 然后返回Person.apply(obj)
4. 返回这个对象
通过下面的方式可以使用new来创建实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Person(name) {
this.name = name;
if (typeof this.getName != "function") {
Person.prototype = {
constructor: Person,
getName: function () {
console.log(this.name);
}
}

return new Person(name);
}
}

var person1 = new Person('kevin');
var person2 = new Person('daisy');

person1.getName(); // kevin
person2.getName(); // daisy

寄生构造函数模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name) {

var o = new Object();
o.name = name;
o.getName = function () {
console.log(this.name);
};

return o;

}

var person1 = new Person('kevin');
console.log(person1 instanceof Person) // false
console.log(person1 instanceof Object) // true

与工厂函数一模一样,区别在于寄生模式使用new来构造实例而工厂模式是直接赋值。

稳妥构造函数模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function person(name){
var o = new Object();
o.sayName = function(){
//没有用到this
console.log(name);
};
return o;
}
// 没有用new
var person1 = person('kevin');

person1.sayName(); // kevin

person1.name = "daisy";

person1.sayName(); // kevin

console.log(person1.name); // daisy

稳妥对象,指的是没有公共属性,而且方法也没有用到this的对象,和寄生构造函数模式有两点不同:
1. 新创建的实例方法不引用this
2. 不适用new操作符调用构造函数