澳门太阳娱乐集团官网-太阳集团太阳娱乐登录

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深远之创设对象》同样,更疑似笔记。

☞组合承接

原理:将原型链和借用构造函数的工夫结合到一块,发挥两岸之长的一种持续情势。

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
亮点:通过调用父类构造,继承父类的性质并保存传参的长处,然后通过将父类实例作为子类原型,完结函数复用,既是子类的实例也是父类的实例
缺欠:调用三次父类型构造函数,生成两份实例(覆盖了父类型原型上的天性),消耗内存

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高等程序设计》写得真是太好了!

☞寄生组合式承继

规律:通过寄生情势,砍掉父类的实例属性,那样,在调用四次父类的构造的时候,就不会开端化两遍实例方法/属性,防止的整合承接的症结

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
(function(){
  // 创建一个没有实例方法的类
  var Super = function(){};
  Super.prototype = Animal.prototype;
  //将实例作为子类的原型
  Cat.prototype = new Super();
})();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat);
Cat.prototype.constructor = Cat; //修复构造函数

充足全面的贯彻了对象的继续

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深远连串目录地址:。

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。开拓人士普遍以为寄生组合式承接是援引类型最理想的再三再四范式。

上述便是本文的全体内容,希望对大家的就学抱有利于,也冀望我们多多照应脚本之家。

您恐怕感兴趣的篇章:

  • 简言之的JS多种承接示例
  • JavaScript mixin完结多三回九转的法子详解
  • JS 面向对象之继续---种种组成承继详解
  • 谈一谈javascript中接二连三的各样格局
  • ExtJS4中应用mixins完毕多一连示例
  • 用JavaScript实现单承继和多承继的简短方法
  • Javascript基于对象三大特点(封装性、承袭性、多态性)
  • js中贯彻多态选用和持续类似的章程
  • javascript 面向对象全新理练之继续与多态
  • JavaScript贯彻多种承继的方法深入分析

本文由澳门太阳娱乐集团官网发布于网页制作,转载请注明出处:JavaScript两种持续形式及其利弊总括

上一篇:Web开发者需知的15个HTML5画布应用 下一篇:没有了
猜你喜欢
热门排行
精彩图文