JavaScript六种异常典范的对象继续体式格局

一、原型链继续

重点:运用原型让一个援用范例继续别的一个援用范例的属性和要领。组织函数,原型,实例之间的关联:每一个组织函数都有一个原型对象,原型对象包括一个指向组织函数的指针,而实例都包括一个指向原型对象的内部指针。

function SuperType(){
  this.property = true;
}
SuperType.prototype.getSuperValue = function(){
  return this.property;
};

function SubType(){
  this.subproperty = false;
}
// 继续自SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function (){
  return this.subproperty;
};

var example = new SubType();
alert(example.getSuperValue());//true

运用原型建立对象会存在多个实例对援用范例的操纵会被改动的题目,在上面一样存在这个题目,以下:

function SuperType(){
  this.colors = ["red", "blue", "green"];
}
function SubType(){}//纵然没有写,也不会影响效果

SubType.prototype = new SuperType();

var example1 = new SubType();
example1.colors.push("black");
alert(example1.colors); //"red,blue,green,black"

var example2 = new SubType(); 
alert(example.colors); //"red,blue,green,black"

两个实例对象example1和example2的colors属性指向雷同,转变一个会影响另一个实例的属性。

瑕玷:
①原型链继续多个实例的援用范例属性指向雷同,一个实例修正了原型属性,另一个实例的原型属性也会被修正;
②不能通报参数;
③继续单一。

二、借用组织函数继续

重点:运用.call()和.apply()将父类组织函数引入子类函数,运用父类的组织函数来加强子类实例,等同于复制父类的实例给子类。

function SuperType(name){
  this.name = name;
  this.colors = ["red", "blue", "green"];
}

function SubType(name, age){
  // 继续自SuperType
  SuperType.call(this, name);  
  this.age = age;
}

var example1 = new SubType("Mike", 23);
example1.colors.push("black");
alert(example1.colors);//"red,blue,green,black"

var example2 = new SubType();
alert(example2.colors);//"red,blue,green"

alert(example1.name); // "Mike"
alert(example1.age); // 23

借用组织函数继续的重点就在于SuperType.call(this, name),挪用了SuperType组织函数,如许,SubType的每一个实例都邑将SuperType中的属性复制一份。

瑕玷:
①只能继续父类的实例属性和要领,不能继续原型属性/要领;
②没法完成组织函数的复用,每一个子类都有父类实例函数的副本,影响机能,代码会痴肥。

三、组合继续

重点:将原型链继续组织函数继续这两种情势的长处组合在一起,经由历程挪用父类组织,继续父类的属性并保留传参,然后经由历程将父类实例作为子类原型,完成函数复用。

其背地的思绪是运用原型链完成对原型属性和要领的继续,而经由历程借用组织函数来完成对实例属性的继续,如许,既经由历程在原型上定义要领完成了函数复用,又能保证每一个实例都有它本身的属性。

function SuperType(name){
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
  alert(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(){
    alert(this.age);
};

var example1 = new SubType("Mike", 23);
example1.colors.push("black");
alert(example1.colors); //"red,blue,green,black"
example1.sayName(); //"Mike";
example1.sayAge(); //23

var example2 = new SubType("Jack", 22);
alert(example2.colors); //"red,blue,green"
example2.sayName(); //"Jack";
example2.sayAge(); //22

缺点:
父类中的实例属性和要领既存在于子类的实例中,又存在于子类的原型中,不过仅是内存占用,因而,在运用子类建立实例对象时,其原型中会存在两份雷同的属性/要领。——-这个要领是javascript中最经常使用的继续情势

四、 原型式继续

重点:用一个函数包装一个对象,然后返回这个函数的挪用,这个函数就变成了个能够随便增加属性的实例或对象。object.create()就是这个道理,直接将某个对象直接赋值给组织函数的原型。

function object(obj){
  function O(){}
  O.prototype = obj;
  return new O();
}

object()对传入个中的对象实行了一次浅复制,将O的原型直接指向传入的对象。

var person = {
  name: "Mike",
  friends: ["Jack", "Tom", "Joes"]
};

var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Peter");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("BoBo");

alert(person.friends);   //"Jack,Tom,Joes,Peter,BoBo"

ECMAScript5经由历程新增Object.create()要领范例化了原型式继续,这个要领吸收两个参数:一个用作新对象原型的对象和一个作为新对象定义分外属性的对象。

var person = {
name:"EvanChen",
friends:["Shelby","Court","Van"];
};
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
console.log(person.friends);//"Shelby","Court","Van","Rob","Barbie"

瑕玷:
①原型链继续多个实例的援用范例属性指向雷同(一切实例都邑继续原型上的属性),存在改动的能够;
②没法通报参数,没法完成复用。(新实例属性都是背面增加的)。

五、寄生式继续

重点:建立一个仅用于封装继续历程的函数,该函数在内部以某种体式格局来加强对象,末了返回组织函数。(就像给原型式继续表面套了个壳子,然后return出来)

function createAnother(original){ 
  varclone=object(original); // 过挪用函数建立一个新对象
  clone.sayHi = function(){ // 以某种体式格局加强这个对象
    alert("hi");
  };
  return clone; // 返回对象
}

函数的重要作用是为组织函数新增属性和要领,以加强函数。

var person = {
  name: "Nicholas",
  friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

瑕玷:
①原型链继续多个实例的援用范例属性指向雷同,存在改动的能够;
②没法通报参数,没用到原型,没法复用。

六、寄生组合式继续

重点:经由历程借用组织函数通报参数和寄生情势完成继续属性,经由历程原型链的混成情势来继续要领,在函数顶用apply或许call引入另一个组织函数,可传参。

function inheritPrototype(subType, superType){
  var prototype = Object.create(superType.prototype); //Object.create建立对象
  prototype.constructor = subType;                    // 加强对象
  subType.prototype = prototype;                      // 指定对象
}

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

// 借用组织函数通报加强子类实例属性(支撑传参和防止改动)
function SubType(name, age){
  SuperType.call(this, name);
  this.age = age;
}

// 将父类原型指向子类
inheritPrototype(SubType, SuperType);

// 新增子类原型属性
SubType.prototype.sayAge = function(){
  alert(this.age);
}

var example1 = new SubType("abc", 21);
var example2 = new SubType("def", 22);

example1.colors.push("pink"); // ["red", "blue", "green", "pink"]
example1.colors.push("black"); // ["red", "blue", "green", "black"]

寄生组合继续鸠合了前面几种继续长处,险些防止了上面继续体式格局的一切缺点,是实行效力最高也是运用面最广的。

瑕玷:
完成的历程相对烦琐。

为何要进修这些继续体式格局,明显能够直接继续为何还要搞这么贫苦?重要是为了进修它们的头脑,打下更好的基本,为今后浏览框架源码,或本身封装组件以至框架大有益处。

时候有点急忙,没有加上ES6的extends,有空再补上。

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