菜单

JavaScript 深入之累的强措施跟优缺点

2018年11月15日 - JavaScript

JavaScript 深入的累的多种方式以及优缺点

2017/05/28 · JavaScript
· 继承

初稿出处: 冴羽   

描绘于前面

写于前面

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

只是注意:

随即篇稿子又如是记,哎,再受我感叹一句:《JavaScript高级程序设计》写得真是极好了!

本文讲解JavaScript各种继承方式以及优缺点。

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

注意:

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

缺点:

艺术都以构造函数中定义,每次创建实例都见面创造同一体方法。

和《JavaScript深入的创建对象》一样,更像是笔记。

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 中极常用之接续模式。

哎,再为我感叹一句:《JavaScript高级程序设计》写得真是极好了!

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

1.原型链继承

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

症结:跟借用构造函数模式一样,每次创建对象都见面创同方方面面方法。

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

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。开发人员普遍认为寄生组合式继承是援类型最美妙的延续范式。

问题:

深入系列

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
  14. JavaScript
    深入之创建对象的多方法和优缺点

    1 赞 3 收藏
    评论

图片 1

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

2.当创建 Child 的实例时,不可知向Parent传参

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.可以在 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

缺点:

方法还以构造函数中定义,每次创建实例都见面创造同通方法。

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

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

4.原型式继承

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

注意:修改person1.name的值,person2.name的价值并未产生变更,并无是以person1person2发独立的
name 值,而是以person1.name = 'person1',给person1加加了 name
值,并非修改了原型上之 name 值。

5. 寄生式继承

创办一个单独用于封装继承过程的函数,该函数在里以某种形式来做增进对象,最后回到对象。

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

缺点:跟借用构造函数模式一样,每次创建对象都见面创同遍方法。

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)

做继承最特别之通病是碰头调用两赖大构造函数。

无异于潮是设置子类型实例的原型的时段:

Child.prototype = new Parent();

同不良当创立子类型实例的时候:

var child1 = new Child('kevin', '18');

回溯下 new 的套实现,其实在即时词被,我们会履行:

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

末段咱们封装一下之累方法:

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。开发人员普遍认为寄生组合式继承是援类型最漂亮的累范式。

如上就是是本文的全部内容,希望对大家的念有帮助,也要大家多多支持脚本的拙。

公或许感兴趣之章:

相关文章

标签:

发表评论

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

网站地图xml地图