深远之继续的有余主意和优缺点,成立对象

JavaScript 深远之创建对象的多种方法以及优缺点

2017/05/28 · JavaScript
· 对象

原稿出处: 冴羽   

来源《JavaScript高级程序设计》

JavaScript 深切之继续的多种格局和优缺点

2017/05/28 · JavaScript
· 继承

原稿出处: 冴羽   

1、原型情势成立对象

写在前边

那篇作品讲解创建对象的各类方法,以及优缺点。

不过注意:

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

  1. 厂子情势

写在眼前

本文讲解JavaScript种种继承方式和优缺点。

只是注意:

那篇文章更像是笔记,哎,再让自身感慨一句:《JavaScript高级程序设计》写得真是太好了!

(1)第一种
function Newperson(){
    
}

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

缺点:对象无法辨认,因为有着的实例都对准一个原型

function createPerson(name) {

1.原型链继承

function Parent () { this.name = ‘kevin’; } Parent.prototype.getName =
function () { console.log(this.name); } function Child () { }
Child.prototype = new Parent(); var child1 = new Child();
console.log(child1.getName()) // kevin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Parent () {
    this.name = ‘kevin’;
}
 
Parent.prototype.getName = function () {
    console.log(this.name);
}
 
function Child () {
 
}
 
Child.prototype = new Parent();
 
var child1 = new Child();
 
console.log(child1.getName()) // kevin

问题:

1.引用类型的习性被所有实例共享,举个例子:

function Parent () { this.names = [‘kevin’, ‘daisy’]; } function Child
() { } Child.prototype = new Parent(); var child1 = new Child();
child1.names.push(‘yayu’); console.log(child1.names); // [“kevin”,
“daisy”, “yayu”] var child2 = new Child(); console.log(child2.names);
// [“kevin”, “daisy”, “yayu”]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Parent () {
    this.names = [‘kevin’, ‘daisy’];
}
 
function Child () {
 
}
 
Child.prototype = new Parent();
 
var child1 = new Child();
 
child1.names.push(‘yayu’);
 
console.log(child1.names); // ["kevin", "daisy", "yayu"]
 
var child2 = new Child();
 
console.log(child2.names); // ["kevin", "daisy", "yayu"]

2.在开立 Child 的实例时,不能向Parent传参

var person2 = new Newperson();

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

优点:实例能够辨别为一个特定的门类

缺点:每便创立实例时,每个方法都要被创建五遍

    var o = new Object();

2.借出构造函数(经典接二连三)

function Parent () { this.names = [‘kevin’, ‘daisy’]; } function Child
() { Parent.call(this); } var child1 = new Child();
child1.names.push(‘yayu’); console.log(child1.names); // [“kevin”,
“daisy”, “yayu”] var child2 = new Child(); console.log(child2.names);
// [深远之继续的有余主意和优缺点,成立对象。”kevin”, “daisy”]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Parent () {
    this.names = [‘kevin’, ‘daisy’];
}
 
function Child () {
    Parent.call(this);
}
 
var child1 = new Child();
 
child1.names.push(‘yayu’);
 
console.log(child1.names); // ["kevin", "daisy", "yayu"]
 
var child2 = new Child();
 
console.log(child2.names); // ["kevin", "daisy"]

优点:

1.幸免了引用类型的性质被所有实例共享

2.可以在 Child 中向 Parent 传参

举个例子:

function Parent (name) { this.name = name; } function Child (name) {
Parent.call(this, name); } var child1 = new Child(‘kevin’);
console.log(child1.name); // kevin var child2 = new Child(‘daisy’);
console.log(child2.name); // daisy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Parent (name) {
    this.name = name;
}
 
function Child (name) {
    Parent.call(this, name);
}
 
var child1 = new Child(‘kevin’);
 
console.log(child1.name); // kevin
 
var child2 = new Child(‘daisy’);
 
console.log(child2.name); // daisy

缺点:

艺术都在构造函数中定义,每一遍创立实例都会创立五次方法。

Newperson.prototype.name = ‘tom’;
Newperson.prototype.age = 22;
Newperson.prototype.job = ‘teacher’;
Newperson.prototype.sayName = function(){
    alert(this.name);
}

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 Parent (name) { this.name = name; this.colors = [‘red’,
‘blue’, ‘green’]; } Parent.prototype.getName = function () {
console.log(this.name) } function Child (name, age) { Parent.call(this,
name); this.age = age; } Child.prototype = new Parent(); var child1 =
new Child(‘kevin’, ’18’); child1.colors.push(‘black’);
console.log(child1.name); // kevin console.log(child1.age); // 18
console.log(child1.colors); // [“red”, “blue”, “green”, “black”] var
child2 = new Child(‘daisy’, ’20’); console.log(child2.name); // daisy
console.log(child2.age); // 20 console.log(child2.colors); // [“red”,
“blue”, “green”]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function Parent (name) {
    this.name = name;
    this.colors = [‘red’, ‘blue’, ‘green’];
}
 
Parent.prototype.getName = function () {
    console.log(this.name)
}
 
function Child (name, age) {
 
    Parent.call(this, name);
    
    this.age = age;
 
}
 
Child.prototype = new Parent();
 
var child1 = new Child(‘kevin’, ’18’);
 
child1.colors.push(‘black’);
 
console.log(child1.name); // kevin
console.log(child1.age); // 18
console.log(child1.colors); // ["red", "blue", "green", "black"]
 
var child2 = new Child(‘daisy’, ’20’);
 
console.log(child2.name); // daisy
console.log(child2.age); // 20
console.log(child2.colors); // ["red", "blue", "green"]

亮点:融合原型链继承和构造函数的助益,是 JavaScript 中最常用的继承方式。

var person1 = new Newperson();

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

4.原型式继承

function createObj(o) { function F(){} F.prototype = o; return new F();
}

1
2
3
4
5
function createObj(o) {
    function F(){}
    F.prototype = o;
    return new F();
}

哪怕 ES5 Object.create 的效仿完毕,将盛传的对象作为创建的目的的原型。

缺点:

富含引用类型的属性值始终都会共享相应的值,这一点跟原型链继承一样。

var person = { name: ‘kevin’, friends: [‘daisy’, ‘kelly’] } var
person1 = createObj(person); var person2 = createObj(person);
person1.name = ‘person1’; console.log(person2.name); // kevin
person1.firends.push(‘taylor’); console.log(person2.friends); //
[“daisy”, “kelly”, “taylor”]

1
2
3
4
5
6
7
8
9
10
11
12
13
var person = {
    name: ‘kevin’,
    friends: [‘daisy’, ‘kelly’]
}
 
var person1 = createObj(person);
var person2 = createObj(person);
 
person1.name = ‘person1’;
console.log(person2.name); // kevin
 
person1.firends.push(‘taylor’);
console.log(person2.friends); // ["daisy", "kelly", "taylor"]

注意:修改person1.name的值,person2.name的值并未发出变动,并不是因为person1person2有单独的
name 值,而是因为person1.name = 'person1',给person1添加了 name
值,并非修改了原型上的 name 值。

console.log(person1.constructor);//Newperson()

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

5. 寄生式继承

始建一个仅用于封装继承进程的函数,该函数在其中以某种方式来做拉长对象,最终回来对象。

function createObj (o) { var clone = object.create(o); clone.sayName =
function () { console.log(‘hi’); } return clone; }

1
2
3
4
5
6
7
function createObj (o) {
    var clone = object.create(o);
    clone.sayName = function () {
        console.log(‘hi’);
    }
    return clone;
}

缺点:跟借用构造函数方式一样,每便成立对象都会创建五遍方法。

console.log(person2.constructor);//Newperson()

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属性找到所属构造函数

缺陷:原型格局该有的通病照旧有

    };

6. 寄生组合式继承

为了便利大家阅读,在此处再一次一下构成继承的代码:

function Parent (name) { this.name = name; this.colors = [‘red’,
‘blue’, ‘green’]; } Parent.prototype.getName = function () {
console.log(this.name) } function Child (name, age) { Parent.call(this,
name); this.age = age; } Child.prototype = new Parent(); var child1 =
new Child(‘kevin’, ’18’); console.log(child1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Parent (name) {
    this.name = name;
    this.colors = [‘red’, ‘blue’, ‘green’];
}
 
Parent.prototype.getName = function () {
    console.log(this.name)
}
 
function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}
 
Child.prototype = new Parent();
 
var child1 = new Child(‘kevin’, ’18’);
 
console.log(child1)

结缘继承最大的缺点是会调用两遍父构造函数。

一遍是安装子类型实例的原型的时候:

Child.prototype = new Parent();

1
Child.prototype = new Parent();

三遍在创制子类型实例的时候:

var child1 = new Child(‘kevin’, ’18’);

1
var child1 = new Child(‘kevin’, ’18’);

回看下 new 的萧规曹随完成,其实在这句中,大家会进行:

Parent.call(this, name);

1
Parent.call(this, name);

在此间,大家又会调用了一次 Parent 构造函数。

由此,在那个例子中,借使大家打印 child1 对象,大家会发觉 Child.prototype
和 child1 都有一个性质为colors,属性值为['red', 'blue', 'green']

那么我们该怎么着改良,幸免那五回重复调用呢?

设若大家不选拔 Child.prototype = new Parent() ,而是直接的让
Child.prototype 访问到 Parent.prototype 呢?

探访如何落实:

function Parent (name) { this.name = name; this.colors = [‘red’,
‘blue’, ‘green’]; } Parent.prototype.getName = function () {
console.log(this.name) } function Child (name, age) { Parent.call(this,
name); this.age = age; } // 关键的三步 var F = function () {};
F.prototype = Parent.prototype; Child.prototype = new F(); var child1 =
new Child(‘kevin’, ’18’); console.log(child1);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function Parent (name) {
    this.name = name;
    this.colors = [‘red’, ‘blue’, ‘green’];
}
 
Parent.prototype.getName = function () {
    console.log(this.name)
}
 
function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}
 
// 关键的三步
var F = function () {};
 
F.prototype = Parent.prototype;
 
Child.prototype = new F();
 
 
var child1 = new Child(‘kevin’, ’18’);
 
console.log(child1);

终极我们封装一下以此一而再方法:

function object(o) { function F() {} F.prototype = o; return new F(); }
function prototype(child, parent) { var prototype =
object(parent.prototype); prototype.constructor = child; child.prototype
= prototype; } // 当大家选拔的时候: prototype(Child, Parent);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}
 
function prototype(child, parent) {
    var prototype = object(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
}
 
// 当我们使用的时候:
prototype(Child, Parent);

引用《JavaScript高级程序设计》中对寄生组合式继承的赞誉就是:

那种措施的高效用展现它只调用了三遍 Parent 构造函数,并且因而防止了在
Parent.prototype
上边创制不要求的、多余的性能。与此同时,原型链还可以保持不变;因而,还是可以健康使用
instanceof 和
isPrototypeOf。开发人士普遍认为寄生组合式继承是引用类型最地道的持续范式。

(2)第二种

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;

深入体系

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
  14. JavaScript
    深切之创制对象的多种办法以及优缺点

    1 赞 3 收藏
    评论

澳门葡京 1

function 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

}

var friend = new Person();

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

var person1 = createPerson(‘kevin’);

//用一个蕴涵所有属性和艺术的目的字面量重写原型对象,相当于重写了Newperson的prototype对象
澳门葡京 ,Person.prototype = {
        //constructor:Person,//添加那句,能够使 person.constructor 指向
Person
        name:’tom’,
        age:22,
        job:’teacher’,
        sayName:function(){
            alert(this.name);
        }
}

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 操作符调用构造函数

妥善对象最契合在一些有惊无险的条件中。

稳妥构造函数情势也跟工厂情势一样,无法识别对象所属类型。

症结:对象不能辨识,因为兼具的实例都针对一个原型

var person = new Person();

深深连串

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 赞 收藏
    评论

澳门葡京 2

  1. 构造函数形式

console.log(friend.constructor);//Person()
console.log(person.constructor);//Object()

function Person(name) {

 

    this.name = name;

澳门葡京 3

    this.getName = function () {

 2、寄生构造函数格局创设对象
    //eg1
    function Animal(name, age, voice){
        var o = new Object();
        o.name = name;
        o.age = age;
        o.voice = voice;
        o.sayVoice = function(){
            return this.voice;
        }
        return o;
    }
    
    var cat = new Animal(‘喵咪’, 2, ‘miao’);
    console.log(cat.name);//喵咪
    console.log(cat.sayVoice());//miao
    
    //eg2
    function Specialarray(){
        var values = new Array();
        values.push.apply(values, arguments);
        values.toPipedString = function(){
            return this.join(‘|’);
        }
        return values;
    }
    
    var array1 = new Specialarray(‘a’, ‘b’, ‘c’);
    console.log(array1.toPipedString());//a|b|c
    console.log(array1.constructor);//Array()
    console.log(array1 instanceof Object);//true

        console.log(this.name);

  那种情势创制的靶子与构造函数或者构造函数的原型属性之间没有关系,无法爱慕instanceof
来确定目标类型。指出足以在利用此外情势的意况下毫不使用那种格局。

    };

}

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. 原型情势

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

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

亮点:实例可以由此constructor属性找到所属构造函数

缺陷:原型方式该有的老毛病仍旧有

  1. 整合方式

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

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

专注:使用动态原型情势时,无法用对象字面量重写原型

分解下为啥:

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 的贯彻步骤:

首先新建一个对象

下一场将对象的原型指向 Person.prototype

然后 Person.apply(obj)

回来这几个目的

瞩目那几个时候,回想下 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

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.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 的目的。

与寄生构造函数方式有两点分歧:

新创立的实例方法不引用 this

不采用 new 操作符调用构造函数

稳妥对象最适合在有的白山的环境中。

妥善构造函数形式也跟工厂情势一样,不能辨识对象所属类型。

相关文章

发表评论

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

*
*
Website