菜单

JavaScript 深入的继续的有余办法同优缺点

2018年11月16日 - 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地图