深入之创建对象的多种方式以及优缺点,JavaScript深入之创建对象的多种方式以及优缺点

JavaScript 深刻之创制对象的各类办法以及优缺点

2017/05/28 · JavaScript
· 对象

原稿出处: 冴羽   

起源《JavaScript高级程序设计》

已离开简书,原因参见
http://www.jianshu.com/p/0f12350a6b66。

写在前边

那篇文章讲解创立对象的种种措施,以及优缺点。

但是注意:

那篇作品更像是笔记,因为《JavaScript高级程序设计》写得真是太好了!

写在日前

那篇作品讲解创设对象的各个措施,以及优缺点。

不过注意:

那篇小说更像是笔记,因为《JavaScript高级程序设计》写得真是太好了!

  1. 厂子形式

虽人微权轻,但也要有和好的姿态。

1. 厂子形式

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

  return o;
}

var person1 = createPerson('kevin');

深入之创建对象的多种方式以及优缺点,JavaScript深入之创建对象的多种方式以及优缺点。缺点:对象不能辨别,因为全部的实例都对准贰个原型

1. 厂子形式

function createPerson(name) { var o = new Object(); o.name = name;
o.getName = function () { console.log(this.name); }; return o; } var
person1 = createPerson(‘kevin’);

1
2
3
4
5
6
7
8
9
10
11
function createPerson(name) {
    var o = new Object();
    o.name = name;
    o.getName = function () {
        console.log(this.name);
    };
 
    return o;
}
 
var person1 = createPerson(‘kevin’);

症结:对象不可能辨识,因为拥有的实例都针对1个原型

function createPerson(name) {

小说能够在自小编的 Github
https://github.com/mqyqingfeng/Blog
查看

2. 构造函数格局

function Person(name) {
  this.name = name;
  this.getName = function () {
    console.log(this.name);
  };
}

var person1 = new Person('kevin');

可取:实例能够分辨为一个特定的档次

缺陷:每便创造实例时,每一种方法都要被创设3遍

2. 构造函数格局

function Person(name) { this.name = name; this.getName = function () {
console.log(this.name); }; } var person1 = new Person(‘kevin’);

1
2
3
4
5
6
7
8
function Person(name) {
    this.name = name;
    this.getName = function () {
        console.log(this.name);
    };
}
 
var person1 = new Person(‘kevin’);

优点:实例能够识别为3个特定的花色

缺陷:每一回创造实例时,每个方法都要被创制贰次

    var o = new Object();

2.1 构造函数情势优化

function Person(name) {
  this.name = name;
  this.getName = getName;
}

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

var person1 = new Person('kevin');

可取:消除了各样方法都要被重新创制的难点

缺陷:那叫什么封装……

2.1 构造函数形式优化

function Person(name) { this.name = name; this.getName = getName; }
function getName() { console.log(this.name); } var person1 = new
Person(‘kevin’);

1
2
3
4
5
6
7
8
9
10
function Person(name) {
    this.name = name;
    this.getName = getName;
}
 
function getName() {
    console.log(this.name);
}
 
var person1 = new Person(‘kevin’);

可取:消除了种种方法都要被再一次成立的题材

缺点:这叫什么封装……

    o.name = name;

3. 原型方式

function Person(name) {

}

Person.prototype.name = 'keivn';
Person.prototype.getName = function () {
  console.log(this.name);
};

var person1 = new Person();

可取:方法不会另行创制

缺点:1. 全体的属性和艺术都共享 2. 不能够伊始化参数

3. 原型情势

function Person(name) { } Person.prototype.name = ‘keivn’;
Person.prototype.getName = function () { console.log(this.name); }; var
person1 = new Person();

1
2
3
4
5
6
7
8
9
10
function Person(name) {
 
}
 
Person.prototype.name = ‘keivn’;
Person.prototype.getName = function () {
    console.log(this.name);
};
 
var person1 = new Person();

亮点:方法不会重复制造

症结:1. 怀有的性质和情势都共享 2. 不可能起头化参数

    o.getName = function () {

3.1 原型形式优化

function Person(name) {

}

Person.prototype = {
  name: 'kevin',
  getName: function () {
    console.log(this.name);
  }
};

var person1 = new Person();

优点:封装性好了有些

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

3.1 原型方式优化

function Person(name) { } Person.prototype = { name: ‘kevin’, getName:
function () { console.log(this.name); } }; var person1 = new Person();

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name) {
 
}
 
Person.prototype = {
    name: ‘kevin’,
    getName: function () {
        console.log(this.name);
    }
};
 
var person1 = new Person();

亮点:封装性好了好几

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

        console.log(this.name);

3.2 原型情势优化

function Person(name) {

}

Person.prototype = {
  constructor: Person,
  name: 'kevin',
  getName: function () {
    console.log(this.name);
  }
};

var person1 = new Person();

可取:实例可以因此constructor属性找到所属构造函数

缺陷:原型方式该有的瑕疵照旧有

3.2 原型方式优化

function Person(name) { } Person.prototype = { constructor: Person,
name: ‘kevin’, getName: function () { console.log(this.name); } }; var
person1 = new Person();

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(name) {
 
}
 
Person.prototype = {
    constructor: Person,
    name: ‘kevin’,
    getName: function () {
        console.log(this.name);
    }
};
 
var person1 = new Person();

可取:实例能够透过constructor属性找到所属构造函数

缺陷:原型格局该有的败笔依旧有

    };

4. 整合方式

构造函数方式与原型格局双剑合璧。

function Person(name) {
  this.name = name;
}

Person.prototype = {
  constructor: Person,
  getName: function () {
    console.log(this.name);
  }
};

var person1 = new Person();

亮点:该共享的共享,该民用的私人住房,使用最广泛的艺术

症结:有的人便是愿意一切都写在一块,即更好的封装性

4. 结缘形式

构造函数形式与原型情势双剑合璧。

function Person(name) { this.name = name; } Person.prototype = {
constructor: Person, getName: function () { console.log(this.name); } };
var person1 = new Person();

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name) {
    this.name = name;
}
 
Person.prototype = {
    constructor: Person,
    getName: function () {
        console.log(this.name);
    }
};
 
var person1 = new Person();

可取:该共享的共享,该民用的村办,使用最广大的办法

症结:有的人正是梦想全部都写在一道,即更好的封装性

    return o;

4.1 动态原型格局

function Person(name) {
  this.name = name;
  if (typeof this.getName != "function") {
    Person.prototype.getName = function () {
      console.log(this.name);
    }
  }
}

var person1 = new Person();

在意:使用动态原型形式时,无法用对象字面量重写原型

释疑下怎么:

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();

为明白释那一个题材,如果开端履行var person1 = new Person('kevin')

要是对 new 和 apply
的底层执行进程不是很熟稔,能够翻阅尾部相关链接中的文章。

咱俩回想下 new 的达成步骤:

  1. 先是新建三个对象
  2. 然后将指标的原型指向 Person.prototype
  3. 然后 Person.apply(obj)
  4. 归来这么些目的

小心那一个时候,回看下 apply 的兑现步骤,会履行 obj.Person
方法,那么些时候就会执行 if 语句里的内容,注意构造函数的 prototype
属性指向了实例的原型,使用字面量格局直接覆盖
Person.prototype,并不会转移实例的原型的值,person1
仍然是指向了在此以前的原型,而不是 Person.prototype。而此前的原型是不曾
getName 方法的,所以就报错了!

即便您不怕想用字面量形式写代码,可以品尝下那种:

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

4.1 动态原型形式

function Person(name) { this.name = name; if (typeof this.getName !=
“function”) { Person.prototype.getName = function () {
console.log(this.name); } } } var person1 = new Person();

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

留神:使用动态原型形式时,不能够用对象字面量重写原型

分解下为何:

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();

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();

为精晓释这么些题材,若是初叶履行var person1 = new Person('kevin')

一经对 new 和 apply
的最底层执行进程不是很了然,能够翻阅尾部相关链接中的文章。

我们回顾下 new 的贯彻步骤:

  1. 首先新建三个对象
  2. 然后将对象的原型指向 Person.prototype
  3. 然后 Person.apply(obj)
  4. 重回这几个指标

瞩目这几个时候,回想下 apply 的兑现步骤,会执行 obj.Person
方法,那几个时候就会执行 if 语句里的始末,注意构造函数的 prototype
属性指向了实例的原型,使用字面量格局直接覆盖
Person.prototype,并不会变动实例的原型的值,person1
仍然是指向了从前的原型,而不是 Person.prototype。而在此之前的原型是从未
getName 方法的,所以就报错了!

假诺您固然想用字面量方式写代码,能够品尝下那种:

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
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

}

5.1 寄生构造函数情势

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

寄生构造函数形式,作者个人觉得应当这么读:

寄生-构造函数-情势,也便是说寄生在构造函数的一种方法。

也正是说打着构造函数的品牌挂羊头卖狗肉,你看创制的实例使用 instanceof
都不能够指向构造函数!

那般方法能够在相当情状下使用。比如大家想创设一个全部额外措施的独特数组,不过又不想直接修改Array构造函数,大家得以这样写:

function SpecialArray() {
  var values = new Array();

  for (var i = 0, len = arguments.length; i < len; i++) {
    values.push(arguments[i]);
  }

  values.toPipedString = function () {
    return this.join("|");
  };
  return values;
}

var colors = new SpecialArray('red', 'blue', 'green');
var colors2 = SpecialArray('red2', 'blue2', 'green2');


console.log(colors);
console.log(colors.toPipedString()); // red|blue|green

console.log(colors2);
console.log(colors2.toPipedString()); // red2|blue2|green2

您会发现,其实所谓的寄生构造函数方式就是比工厂方式在创设对象的时候,多应用了三个new,实际上两者的结果是如出一辙的。

可是小编可能是可望能像使用普通 Array 一样使用 SpecialArray,纵然把
SpecialArray 当成函数也一如既往能用,但是这并不是作者的本意,也变得不优雅。

在能够运用其余情势的气象下,不要使用那种格局。

而是值得一提的是,上边例子中的循环:

for (var i = 0, len = arguments.length; i < len; i++) {
  values.push(arguments[i]);
}

能够替换到:

values.push.apply(values, arguments);

5.1 寄生构造函数方式

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

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

寄生构造函数格局,我个人觉得应当那样读:

寄生-构造函数-方式,也便是说寄生在构造函数的一种办法。

也正是说打着构造函数的牌子挂羊头卖狗肉,你看创制的实例使用 instanceof
都不能够指向构造函数!

如此那般方法可以在特出情况下使用。比如大家想创设二个怀有额外措施的优异数组,不过又不想直接修改Array构造函数,大家得以这么写:

function SpecialArray() { var values = new Array(); for (var i = 0, len
= arguments.length; i len; i++) { values.push(arguments[i]); }
values.toPipedString = function () { return this.join(“|”); }; return
values; } var colors = new SpecialArray(‘red’, ‘blue’, ‘green’); var
colors2 = SpecialArray(‘red2’, ‘blue2’, ‘green2’); console.log(colors);
console.log(colors.toPipedString()); // red|blue|green
console.log(colors2); console.log(colors2.toPipedString()); //
red2|blue2|green2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function SpecialArray() {
    var values = new Array();
 
    for (var i = 0, len = arguments.length; i  len; i++) {
        values.push(arguments[i]);
    }
 
    values.toPipedString = function () {
        return this.join("|");
    };
    return values;
}
 
var colors = new SpecialArray(‘red’, ‘blue’, ‘green’);
var colors2 = SpecialArray(‘red2’, ‘blue2’, ‘green2’);
 
 
console.log(colors);
console.log(colors.toPipedString()); // red|blue|green
 
console.log(colors2);
console.log(colors2.toPipedString()); // red2|blue2|green2

你会意识,其实所谓的寄生构造函数情势正是比厂子形式在创设对象的时候,多使用了3个new,实际上两者的结果是同样的。

可是作者恐怕是愿意能像使用普通 Array 一样使用 特略Array,尽管把
SpecialArray 当成函数也一致能用,可是那并不是小编的本意,也变得欠赏心悦目。

在能够采纳任何方式的意况下,不要使用那种情势。

不过值得一提的是,上边例子中的循环:

for (var i = 0, len = arguments.length; i len; i++) {
values.push(arguments[i]); }

1
2
3
for (var i = 0, len = arguments.length; i  len; i++) {
    values.push(arguments[i]);
}

能够替换来:

values.push.apply(values, arguments);

1
values.push.apply(values, arguments);

var person1 = createPerson(‘kevin’);

5.2 妥贴构造函数格局

function person(name){
  var o = new Object();
  o.sayName = function(){
    console.log(name);
  };
  return o;
}

var person1 = person('kevin');

person1.sayName(); // kevin

person1.name = "daisy";

person1.sayName(); // kevin

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

所谓妥贴对象,指的是从未有过集体性质,而且其方法也不引用 this 的对象。

与寄生构造函数格局有两点差别:

  1. 新成立的实例方法不引用 this
  2. 不选用 new 操作符调用构造函数

稳妥对象最符合在部分安全的条件中。

伏贴构造函数情势也跟工厂方式一样,无法辨认对象所属类型。

原文:

5.2 安妥构造函数方式

function person(name){ var o = new Object(); o.sayName = function(){
console.log(name); }; return o; } var person1 = person(‘kevin’);
person1.sayName(); // kevin person1.name = “daisy”; person1.sayName();
// kevin console.log(person1.name); // daisy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function person(name){
    var o = new Object();
    o.sayName = function(){
        console.log(name);
    };
    return o;
}
 
var person1 = person(‘kevin’);
 
person1.sayName(); // kevin
 
person1.name = "daisy";
 
person1.sayName(); // kevin
 
console.log(person1.name); // daisy

所谓稳当对象,指的是绝非国有属性,而且其艺术也不引用 this 的目的。

与寄生构造函数格局有两点区别:

  1. 新创制的实例方法不引用 this
  2. 不行使 new 操作符调用构造函数

安妥对象最符合在有个别平安的条件中。

稳当构造函数方式也跟工厂格局一样,不恐怕辨认对象所属类型。

缺陷:对象不可能分辨,因为具有的实例都指向二个原型

深入连串

JavaScript深切体系目录地址:。

JavaScript浓密体系估算写十五篇左右,旨在帮大家捋顺JavaScript底层知识,重点讲解如原型、功能域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等困难概念。

假设有不当可能不不敢越雷池一步的地点,请务必给予指正,十一分谢谢。假设喜欢恐怕持有启发,欢迎star,对小编也是一种鞭策。

  1. JavaScirpt 深刻之从原型到原型链
  2. JavaScript
    深切之词法功用域和动态功效域
  3. JavaScript 深刻之实践上下文栈
  4. JavaScript 深远之变量对象
  5. JavaScript 深远之成效域链
  6. JavaScript 深切之从 ECMAScript 规范解读
    this
  7. JavaScript 深切之实施上下文
  8. JavaScript 深切之闭包
  9. JavaScript 深入之参数按值传递
  10. JavaScript
    深远之call和apply的模拟完毕
  11. JavaScript 深远之bind的模仿完成
  12. JavaScript 深刻之new的模拟完成
  13. JavaScript 长远之类数组对象与
    arguments

    1 赞 收藏
    评论

图片 1

  1. 构造函数方式

function Person(name) {

    this.name = name;

    this.getName = function () {

        console.log(this.name);

    };

}

var person1 = new Person(‘kevin’);

可取:实例可以辨认为3个一定的档次

缺陷:每趟制造实例时,每一种方法都要被创建3次

2.1 构造函数情势优化

function Person(name) {

    this.name = name;

    this.getName = getName;

}

function getName() {

    console.log(this.name);

}

var person1 = new Person(‘kevin’);

可取:化解了各类方法都要被另行制造的题材

症结:那叫什么封装……

  1. 原型情势

function Person(name) {

}

Person.prototype.name = ‘keivn’;

Person.prototype.getName = function () {

    console.log(this.name);

};

var person1 = new Person();

亮点:方法不会重复成立

症结:1. 颇具的属性和情势都共享 2. 无法初阶化参数

3.1 原型形式优化

function Person(name) {

}

Person.prototype = {

    name: ‘kevin’,

    getName: function () {

        console.log(this.name);

相关文章