这篇原本应该是作为写JS
面向对象的前奏,只是作为《javascript高等程序设计》继续一章的笔记
原型链
code
完成function SuperType() { this.colors = ['red','blue', 'green']; } function SubType() { } SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("black"); console.log(instance1.colors); // ['red','blue', 'green','black'] var instance2 = new SubType(); console.log(instance2.colors); // ['red','blue', 'green','black'] var instance = new SuperType(); console.log(instance.colors); // ['red','blue', 'green']
- 运用原型链来完成继续,原型现实上会变成另一个范例的实例,因而,本来的实例属性,会变成如今的原型属性了
- 在建立子类的实例时,不能向父类的组织函数中通报参数
借用组织函数
code
完成继续function SuperType() { this.colors = ["red","blue","green"]; } function SubType() { SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); console.log(instance1.colors); // ["red", "blue", "green", "black"] var instance2 = new SubType(); console.log(instance2.colors); // ["red", "blue", "green"] var instance = new SuperType(); console.log(instance.colors); // ['red','blue', 'green']
一样也可以完成参数的通报
function SuperType(name) { this.name = name; } function SubType(){ SuperType.call(this, "jack"); this.age = 29; } var instance = new SubType(); console.log(instance.name); // jack console.log(instance.age); // 29
- 假如仅仅是借用组织函数,那末将没法防止组织函数情势存在的题目–要领都在组织函数中定义,因而,函数复用也就无从谈起了。而且,在超范例的原型中定义的要领,对子类而言也是不可见的,效果一切范例都只能运用组织函数情势。
组合继续
- 将原型链和借用组织函数的手艺组合到一块,从而发还两者之长的一种继续情势。其背地的思绪是运用原型链完成对原型属性和要领的继续,而经由历程借用组织函数来完成对实例属性的继续。如许,即经由历程在原型上定义要领完成了函数复用,又可以保证每一个实例都有它本身的属性。
code
完成function SuperType(name) { this.name = name; this.colors = ['red','blue','green']; } SuperType.prototype.sayName = function() { console.log(this.name); }; function SubType(name, age) { SuperType.call(this, name); this.age = age; }; SubType.prototype = new SuperType(); SubType.prototype.sayAge = function(){ console.log(this.age); }; var instance1 = new SubType("jack", 29); instance1.colors.push("black"); console.log(instance1.colors); //["red", "blue", "green", "black"] instance1.sayName(); // jack instance1.sayAge(); // 29 var instance2 = new SubType("allen", 23); console.log(instance2.colors); // ["red", "blue", "green"] instance2.sayName(); //allen instance2.sayAge(); // 23
-
instanceOf
和isPrototypeOf
也可以用于辨认基于组合继续建立的对象
原型式继续
没有严厉意义上的组织函数,经由历程借助原型,可以基于已有的对象建立新对象,同时还没必要因而建立自定义范例
function object(o){ function F(){}; F.prototype = o; return new F(); }
在
object()
函数内部,先建立了一个暂时性的组织函数,然后将传入的对象作为这个组织函数的原型,末了返回这个暂时范例的一个新实例。从实质大将,object()
对传入个中的对象执行了一次浅复制function object(o) { function F() {}; F.prototype = o; return new F(); } var person = { name:'jack', friends:['allen','lucy','van'] } var anotherPerson = object(person); anotherPerson.name = 'bob'; anotherPerson.friends.push('steve'); var yetAnotherPerson = object(person); yetAnotherPerson.name = 'linda'; yetAnotherPerson.friends.push('shelly') console.log(person.friends); //["allen", "lucy", "van", "steve", "shelly"]
这类原型式继续,请求你必须有一个对象可以作为另一个对象的基本。假如有这么一个对象的话,可以把他通报给
object()
函数,然后再依据详细需求对获得的对象加以润饰即可。ECMAScript5
经由历程Object.create()
要领范例花了原型式继续。这个要领接收两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义分外属性的对象。在传入一个参数的情况下,Object,create()
与object()
函数要领的行动雷同在没有必要建立组织函数,而只是想让一个对象与另一个对象坚持相似的情况下,原型式继续是完全可以胜任的。不过,包括援用范例值的属性一直都邑同享相应的值,就像运用原型情势一样
寄生式继续
寄生式继续是与原型式继续严密相干的一种思绪。寄生式继续的思绪与寄生组织函数和工场情势相似,即建立一个仅用于封装继续历程的函数,该函数在内部已某种体式格局来加强对象,末了再像真的是它做了一切事情一样返回对象。
function createAnother(original){ var clone = object(original); // 经由历程挪用 object() 函数建立一个新对象 clone.sayHi = function(){ // 以某种体式格局来加强对象 alert("hi"); }; return clone; // 返回这个对象 }
- 在重要斟酌对象而不是自定义范例和组织函数的情况下,寄生式继续也是一种有效的情势。前面树模继续情势时运用的
object()
函数不是必须的;任何可以返回新对象的函数都运用与此情势。
寄生组合式继续
- 组合继续是
JavaScript
最经常使用的继续情势;不过也有本身的不足。组合继续最大的题目就是无论什么情况下,都邑挪用两次父类的组织函数:一次是在建立子类原型的时刻,另一次是在子类组织函数内部。
子类最终会包括父类对象的悉数实例属性,但我们不得不在挪用子类组织函数时重写这些属性。
function SuperType(name) { this.name = name; this.colors = ['red','blue','green']; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(name, age) { SuperType.call(this, name); // 第二次挪用 SuperType() this.age = age; } SubType.prototype = new SuperType(); // 第一次挪用 SuperType() SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function() { console.log(this.age); };
第一次挪用
SuperType
组织函数时,SubType.prototype
会获得两个属性:name
和colors
,他们都是SuperType
的实例属性,只不过如今位于SubType
的原型中。当挪用SubType
组织函数时,又会挪用一次SuperType
组织函数,这一次又在新对象上建立了实例属性name
和colors
。 因而,这两个属性就屏障了原型中的两个同名属性。
所谓寄生组合式继续,即经由历程借用组织函数来继续属性,经由历程原型链的混成情势来继续要领。其背地的基本思绪是:没必要为了指定子类的原型而挪用父类的组织函数,我们所须要的不过就是父类原型的一个副本罢了。实质上,就是运用寄生式继续来继续父范例的原型,然后再将效果指定给子类的原型。寄生组合式继续的基本情势以下
function inheritPrototype(subType, superType) { var prototype = object(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; }
第一步是建立父类原型的一个副本,第二步是为建立的副本增加
constructor
属性,从而填补因重写原型而落空的默许的constructor
属性。第三步是将新建立的对象(即副本)赋值给子类的原型。function SuperType(name) { this.name = name; this.colors = ['red','blue','green']; } SuperType.prototype.sayName = function(){ console.log(this.name); } function SubType(name, age) { SuperType.call(this, name); // 第二次挪用 SuperType() this.age = age; } inheritPrototype(SubType, SuperType) SubType.prototype.sayAge = function() { console.log(this.age); };
这个例子的高效率体如今它只挪用了一次
SuperType
组织函数,而且因而防止了在SubType.prototype
上建立没必要要的、过剩的属性。于此同时,原型链还能坚持稳定;因而,还可以一般运用instanceof
和isPrototypeOf()
。开发人员普遍认为寄生组合继续是援用范例最理想的继续范式。- 组合继续是
优缺点
- 原型链会修正父类的属性,在建立子类的实例时,不能向父类的组织函数中通报参数
- 借用组织函数,则没有继续
- 组合继续(原型继续+借用组织函数) 组合继续最大的题目就是无论什么情况下,都邑挪用两次父类的组织函数:一次是在建立子类原型的时刻,另一次是在子类组织函数内部。
- 原型式继续,请求你必须有一个对象可以作为另一个对象的基本,
包括援用范例值的属性一直都邑同享相应的值,就像运用原型情势一样 - 寄生式继续
在重要斟酌对象而不是自定义范例和组织函数的情况下,寄生式继续也是一种有效的情势 - 寄生组合式继续 (这是最成熟的要领,也是如今库完成的要领)
第一步是建立父类原型的一个副本,第二步是为建立的副本增加constructor
属性,从而填补因重写原型而落空的默许的constructor
属性。第三步是将新建立的对象(即副本)赋值给子类的原型。
JS
面向对象系列