菜单

JavaScript深入的创建对象的余主意与优缺点

2018年11月16日 - JavaScript

JavaScript 深入的创建对象的又法及优缺点

2017/05/28 · JavaScript
· 对象

原文出处: 冴羽   

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

描绘于前头

当下首文章讲解创建对象的各种办法,以及优缺点。

可是注意:

当时篇稿子还像是记,因为《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’);

缺陷:对象无法辨别,因为有着的实例都指向一个原型

章可在自己的 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’);

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

优点:实例可以识别为一个特定的类型

缺点:每次创建实例时,每个方法都要于创造同破

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

长:解决了每个方法还如被还创设的问题

缺陷:这被什么封装……

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. 请勿可知初始化参数

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

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

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

亮点:该共享的共享,该民用的个人,使用最广大的艺术

缺陷:有的人就是是可望任何且写以联名,即再好之封装性

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

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

公会意识,其实所谓的寄生构造函数模式就是是于工厂模式在创建对象的时,多以了一个new,实际上两者的结果是一模一样的。

而是笔者或是望能够像用普通 Array 一样用 SpecialArray,虽然把
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);

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深入系列目录地址:https://github.com/mqyqingfeng/Blog。

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

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图