js继续的明白

原文链接https://kongchenglc.coding.me…

1.原型链

  js的继续机制不同于传统的面向对象言语,采纳原型链完成继续,基本头脑是应用原型让一个援用范例继续另一个援用范例的属性和要领。明白原型链必需先明白原型,以下是关于原型的一些诠释:

不管什么时候,只需建立了一个新函数,就会依据一组特定规则为该函数建立一个prototype属性。这个属性指向函数的原型对象,一切原型对象都邑自动获得一个constructor属性,这个属性是一个指向prototype属性地点函数的指针。建立自定义的组织函数以后,其原型对象只会获得constructor属性,其他要领都是从Object继续来的。当挪用组织函数建立一个新实例以后,该实例的内部包括一个指针,指向组织函数的原型对象,即[[Prototype]],在浏览器中为_proto_

  也就是说,组织函数和实例现实上都是存在一个指向原型的指针,组织函数指向原型的指针为其prototype属性。实例也包括一个不可接见的指针[[Prototype]](现实在浏览器中可以用_proto_接见),而原型链的构成真正依靠的是_proto_而非[[Prototype]]

举个例子

下边是一个最简朴的继续体式格局的例子:用父类实例充任子类原型对象。

function SuperType(){                        
    this.property = true;
    this.arr = [1];
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
};
function SubType(){
    this.subproperty = false;
}
SubType.prototype = new SuperType();              
//在此继续,SubType的prototype为SuperType的一个实例
SubType.prototype.getSubValue = function(){
    return this.subproperty;
};
var instance = new SubType();
var instance2 = new SubType();                                   
c(instance.getSuperValue());                      //true
c(instance.getSubValue());                        //false
c(instance.__proto__.prototype);                  //undefined
//SubType继续了SuperType,SuperType继续了Object。
//instance的_proto_是SubType的原型对象,即SubType.prototype。
//而SubType.prototype又是SuperType的一个实例。
//则instance._proto_.prototype为undefined,
//因为SuperType的实例对象不包括prototype属性。
instance.arr.push(2);
c(instance.arr);                                  //[1,2]
c(instance2.arr);                                 //[1,2]
//子类们同享援用属性

须要注重的一点:不管以什么体式格局继续,请郑重运用将对象字面量赋值给原型的要领,如许会重写原型链。

优瑕玷

  原型链继续体式格局的长处在于简朴,而瑕玷也非常致命:

  1. 子类之间会同享援用范例属性

  2. 建立子类时,没法向父类组织函数传参

2.借用组织函数

  又叫典范继续,借用组织函数继续的重要头脑:在子范例组织函数的内部挪用超范例组织函数,即用call()apply()要领给子类中的this实行父类的组织函数,使其具有父类具有的属性完成继续,这类继续要领完整没有效到原型。下边是借用组织函数的完成:

function SuperType(){                                 
    this.colors = ["red","blue","green"];
}
function SubType(){
    SuperType.call(this);     //借用组织函数
}
var instance1 = new SubType();
instance1.colors.push("black");
c(instance1.colors);          //["red","blue","green","black"]
var instance2 = new SubType();
c(instance2.colors);          //["red","blue","green"]

举个例子

  借用组织函数,相当于将父类具有的属性在子类的组织函数也写了一遍,使子类具有父类具有的属性,这类要领在建立子类实例时,可以向父类组织函数通报参数 。

function SuperType(name){           
    this.name = name;
}
function SubType(name){
    SuperType.call(this,name);          //借用组织函数形式通报参数
    this.age = 29;
}
var instance = new SubType("something");
c(instance.name);                       //something
c(instance.age);                        //29

优瑕玷

  借用组织函数形式,不同于原型式继续和原型形式,它不会同享援用范例属性,而且也可以向超范例组织函数通报参数。然则相对的,因为不会同享属性,也没法完成代码复用,雷同的函数在每一个实例中都有一份。为了完成代码复用,提醒效力,大神们又想出了下边的继续要领。

3.组合继续

组合继续偶然也叫伪典范继续,是将原型链和借用组织函数的手艺组合到一块,从而发挥两者之长的一种继续形式。

  即用原型链完成对原型属性和要领的继续(须要同享的),经由历程借用组织函数完成对实例属性的继续(不同享的)。如许的要领完成了函数复用,而且每一个实例具有本身的属性。

举个例子

function SuperType(name) {                       //父类的实例属性
    this.name = name;
    this.colors = ["red", "blue", "green"];      
}
SuperType.prototype.sayName = function() {       //父类的原型属性
    c(this.name);
};

function SubType(name, age) {                    //借用组织函数继续实例属性
    SuperType.call(this, name);
    this.age = age;
}
SubType.prototype = new SuperType();             //原型链继续原型属性
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
    c(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
c(instance1.colors);        //"red,blue,green,black"
delete instance1.colors;    
//删除从实例属性继续来的colors,读取colors会成为从原型继续来的实例属性
c(instance1.colors);        //"red,blue,green"
instance1.sayName();        //Nicholas
instance1.sayAge();         //29
var instance2 = new SubType("Greg", 27);
c(instance2.colors);        //"red,blue,green"
instance2.sayName();        //Greg
instance2.sayAge();         //27

优瑕玷

这是一切继续体式格局中最经常使用的,它的长处也非常显著:

  1. 可以在建立子类实例时向父类组织函数传参。

  2. 援用范例属性的值可以不同享。

  3. 可以完成代码复用,即可以同享雷同的要领。

然则这类要领依旧有一点不足,挪用了两次父类的组织函数,末了会讲到一种理论上靠近圆满的继续体式格局,即寄生组合式继续。

4.原型式继续

  原型式继续借助原型基于已有对象建立新对象,须要一个对象作为另一个对象的基本:

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

  上边段代码就是原型式继续的中心代码,先建立一个暂时性的组织函数,然后将传入的对象作为这个组织函数的原型,末了返回这个暂时范例的一个新实例。

举个例子

var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);      //在此继续
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
c(person.friends);              //["Shelby","Court","Van","Rob","Barbie"]
c(person.name);                 //Nicholas
c(anotherPerson.name);          //Greg
c(yetAnotherPerson.name);       //Linda
delete yetAnotherPerson.name;   
//删除子类的属性,就会消除对父类属性的屏障,暴露出父类的name属性
c(yetAnotherPerson.name);       //Nicholas

  从上边的代码显现,由object(注重首字母小写,不是对象的组织函数)发生的两个子类会同享父类的援用属性,个中friends数组是同享的,anotherPerson和yetAnotherPerson都是继续自person。现实上相当于建立了两个person对象的副本,但可以在发生以后具有各自的实例属性。

ECMAScript5新增了Object.create()要领范例化了原型式继续,这个要领接收两个参数:

  1. 一个作为新对象原型的对象(可以是对象或许null)

  2. 另一个为新对象定义分外属性的对象(可选,这个参数的花样和Object.defineProperties()要领的第二个参数花样雷同,每一个属性都是经由历程本身的描述符定义的)

  下边是一个例子:

var person = {                      //原型式继续范例化为create()函数
    name: "Nicholas",
    friends: ["Shelby","Court","Van"]
};
var anotherPerson = Object.create(person, {
    name: {
        value: "Greg"
    }
});
c(anotherPerson.name);             //"Greg"

优瑕玷

  假如想让一个对象与另一个对象坚持相似,原型式继续是很贴切的,然则与原型形式一样,包括援用范例的值得属性会同享响应的值。

5.寄生式继续

寄生式继续与原型式继续严密相干的一种思绪,与寄生组织函数和工场形式相似,即建立一个仅用于封装继续历程的函数,函数内部以某种体式格局来加强对象,末了再像真的做了一切事情一样返回对象。

举个例子

function createAnother(original) { 
    var clone = object(original);          //此处用到了原型式继续
    clone.sayHi = function() {
        c("Hi");
    };
    return clone;
}
var person = {                             //父类实例
    name: "Nicholas",
    friends: ["Shelby","Court","Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi();

  上边的寄生式继续用到了原型式继续,向完成继续的函数传入一个父类对象实例,再用原型式继续获得一个父类对象实例的副本,再给这个副本增加属性,即加强这个对象,末了返回这个副本对象。因为用到了原型式继续,这个对象的原型指向传入的父类对象实例。上边例子用到的object()函数(原型式继续)并非必需的,任何可以返回新对象的函数都适用于寄生式继续形式

优瑕玷

  寄生式继续在重要斟酌对象而不是建立自定义范例和组织函数时,是非常有效的。然则假如斟酌到用寄生式继续为对象增加函数等,因为没有效到原型,做不到函数复用,会致使效力下降。

6.寄生组合式继续

  这个名字并非很贴切,虽然叫寄生组合式继续,然则和寄生式继续关联不是很大,重如果用原型式继续来完成原型属性的继续,用借用组织函数形式继续实例属性。寄生组合式继续和组合继续的区分在于:

  1. 在继续原型属性时,组合继续用原型链继续了全部父类(经由历程将父类实例赋值给子类组织函数的原型对象来完成),这使子类中多了一份父类的实例属性。而寄生组合式继续用原型式继续只继续了父类的原型属性(把父类组织函数的原型对象用原型式继续复制给子类的组织函数的原型对象)。

  2. 组合继续挪用了两次超范例组织函数,寄生组合式继续挪用了一次。

举个例子

function inheritPrototype(subType, superType) {             //寄生式继续
    var prototype = Object.create(superType.prototype);     //建立对象
    prototype.constructor = subType;                        //加强对象
    subType.prototype = prototype;                          //指定对象
}
function SuperType(name) {
    this.name = name;
    this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){
    c(this.name);
};
function SubType(name, age) {
    SuperType.call(this, name);                 //借用组织函数
    this.age = age;                             //增加子类独占的属性
}
inheritPrototype(SubType, SuperType);           //此处挪用完成寄生组合继续的函数
SubType.prototype.sayAge = function() {         //增加子类独占原型属性
    c(this.age);
};
var son = new SubType("erzi",16);
var father = new SuperType("baba");
c(typeof father.sayName);                       //function
c(typeof father.sayAge);                        //SubType独占的要领,返回undefined
SubType.prototype.sayName = function() {        
    c("This function has be changed");          
}   
//变动子类的要领只会影响子类,prototype是对象,增加新属性和变动属性不会影响父类的prototype
father.sayName();                               //baba
son.sayName();                                  //This function has be changed
SuperType.prototype.sayName = function() {      //变动父类的原型属性
    c("This function has be changed");
}
father.sayName();                               //This function has be changed
son.sayName();                                  //This function has be changed

优瑕玷

  这类继续体式格局理论上是圆满的,然则因为涌现的较晚,人们大多数运用的是组合继续形式。

  以上就是我关于js继续的一些明白,若有不足迎接指出。

参考资料:《JavaScript高等程序设计》

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