JS中继续体式格局总结

说在前面:
为了使代码更加简约轻易明白, 本文中的代码均将“非中心完成”部份的代码移出。

一、原型链体式格局
关于原型链,可点击《深入浅出,JS原型链的事情道理》,本文不再反复叙说。

思绪:让子组织函数的原型即是父组织函数的实例

function A() {
}
A.prototype.fn = function (){
    console.log("in A");
}

function B() {
}
B.prototype = new A();  // 让子组织函数的原型即是父组织函数的实例

var b = new B();
b.fn(); // in A
console.log(b instanceof B); // true
console.log(b instanceof A); // true
console.log(b instanceof Object); // true

缺点:假如父组织函数中的属性为援用范例,则子组织函数的实例会涌现相互影响的状况;

function A() {
    this.prop = ['1',"2"];
}
A.prototype.fn = function (){
    console.log(this.prop);
}

function B() {
}
B.prototype = new A(); 

var b1 = new B();
var b2 = new B();
b1.fn(); //  ["1", "2"]
b2.fn(); //  ["1", "2"]

b1.prop.push('3'); // 子组织函数实例b1修正继续过来的属性
b2.prop.push('4'); // 子组织函数实例b2修正继续过来的属性

b1.fn(); // ["1", "2", "3", "4"] // b2上的修正影响了b1
b2.fn(); // ["1", "2", "3", "4"] // b1上的修正影响了b2

*致使缺点缘由:援用范例,属性变量保留的是地点指针而非现实的值,这个指针指向了一块用来保留现实内容的地点。实例化后,一切实例中变量保留了同一个指针,均指向同一个地点,当任何一个实例经由过程指针修正地点的内容(并不是从新给予新的指针地点或许修正指针指向)时,其他实例的也会受到影响。

二、借用组织函数体式格局
为了处理“原型链体式格局”继续的缺点,引入的一种“继续”计划。

思绪:经由过程call/apply,在子组织函数中挪用父类的组织函数

function A() {
    this.prop = ['1',"2"];

    this.fn2 = function () {
        console.log(this.prop);
    }
}
A.prototype.fn = function (){
    console.log(this.prop);
}

function B() {
    A.call(this); // 经由过程call/apply,在子组织函数中挪用父类的组织函数
}

var b1 = new B();
var b2 = new B();
b1.fn2(); // ["1", "2"]
b2.fn2(); // ["1", "2"]

b1.prop.push('3');
b2.prop.push('4');

b1.fn2(); // ["1", "2", "3"]
b2.fn2(); // ["1", "2", "4"]

b1.fn(); // 提醒非常:b1.fn is not a function
console.log(b1 instanceof B); // true
console.log(b1 instanceof A); // false
console.log(b1 instanceof Object); // true

缺点:由于“继续”过程当中,A仅充任一般函数被挪用,使得父组织函数A原型没法与组成子组织函数B组成真相链关联。因而没法组成继续关联:”b1 instanceof A”效果为false,B的实例b1亦没法挪用A原型中的要领。现实意义上,这类不属于继续。

三、组合继续
连系“原型链体式格局”和“借用组织函数体式格局”的有点,举行革新的一种继续体式格局。

思绪:原型上的属性和要领经由过程“原型链体式格局”继续;父组织函数内的属性和要领经由过程“借用组织函数体式格局”继续

function A() {
    this.prop = ['1',"2"];
}
A.prototype.fn = function (){
    console.log(this.prop);
}

function B() {
    A.call(this); // 借用组织函数体式格局
}
B.prototype = new A(); // 原型链体式格局

var b1 = new B();
var b2 = new B();
b1.fn(); // ["1", "2"]
b2.fn(); // ["1", "2"]

b1.prop.push('3');
b2.prop.push('4');

b1.fn(); // ["1", "2", "3"]
b2.fn(); // ["1", "2", "4"]
console.log(b1 instanceof B); // true
console.log(b1 instanceof A); // true
console.log(b1 instanceof Object); // true

缺点:子组织函数的原型涌现一套冗余“父组织函数非原型上的属性和要领”。上述代码在实行“A.call(this);”时刻,会给this(即将从B返回给b1赋值的对象)增加一个“prop”属性;在实行“B.prototype = new A();”时,又会经由过程实例化的情势给B的原型赋值一次“prop”属性。明显,由于实例属性要领的优先级高于原型上的属性要领,绝大多数状况下,原型上的“prop”是不会被接见到的。

四、寄生组合式继续
为了处理“组合继续”中子组织函数的原型链涌现冗余的属性和要领,引入的一种继续体式格局。

思绪:在组合继续的基础上,经由过程Object.create的体式格局完成原型链体式格局

function A() {
    this.prop = ['1',"2"];
}
A.prototype.fn = function (){
    console.log(this.prop);
}

function B() {
    A.call(this);
}
B.prototype = Object.create(A.prototype); // Object.create的体式格局完成原型链体式格局

var b1 = new B();
var b2 = new B();
b1.fn(); // ["1", "2"]
b2.fn(); // ["1", "2"]

b1.prop.push('3');
b2.prop.push('4');

b1.fn(); // ["1", "2", "3"]
b2.fn(); // ["1", "2", "4"]

console.log(b1 instanceof B); // true
console.log(b1 instanceof A); // true
console.log(b1 instanceof Object); // true

末了补充
1、由于子组织函数的实例自身没有constructor属性,当我们接见实例的constructor属性时,现实是接见原型的constructor属性,该属性应该指向(子)组织函数。然则上述例子中,代码均会指向父组织函数。为了与ECMAScript范例保持一致,在一切的“原型链继续”后,应该将原型的constructor属性指向子组织函数自身:

    B.prototype = ....
--> B.prototype.constructor = B; <--
    ...

2、Object.create是ECMAScript 5中到场的一个函数,这个函数的功用是:将入参(需为一个对象)作为原型,建立并返回一个新的(只要原型的)的对象。此功用等价于:

function object(o){ 
    function F(){}
    F. prototype = o; 
    return new F(); 
} // 来源于《JavaScript高等程序设计(第3版)》

    原文作者:Lycop
    原文地址: https://segmentfault.com/a/1190000017522714
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞