再来看一次JS继承

作者: 7天苹果 | 来源:发表于2017-07-31 11:23 被阅读50次

原型链继承

理解原型链的概念

用一张图来理解原型链再合适不过了。

来自于网络

总结概括JS红宝书上对原型链的概念:每个函数都有一个prototype属性,它指向原型对象。每一个实例都有一个_ proto_ 属性,它指向该实例的原型对象。如果把一个实例的原型对象再次看作一个实例,它也就会有一个_ proto _属性,这个属性指向它的原型对象。

这样我们可以知道,JS原型链其实是靠_proto _属性来实现的。

实现继承

实现原型链继承有一种基本模式:

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

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

function SubType(){
  this.subproperty = false;
}

SubType.prototype = new SuperType();

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

var instance = new SubType();
alert(instance.getSuperValue());
上述代码的结构图

提醒:通过原型链实现继承时,不能使用对象字面量创建原型方法。这样会重写原型链。

确定原型和实例的关系

  1. 使用instanceof操作符。
alert(instance instanceof Object);   //true
alert(instance instanceof SuperType);   //true
alert(instance instanceof SubType);   //true
  1. 使用isPrototypeOf()方法
Object.prototype.isPrototypeOf(instance);  //true
SuperType.prototype.isPrototypeOf(instance);  //true
SubType.prototype.isPrototypeOf(instance);  //true

原型链的问题

  1. 对于引用类型值的原型,原型链继承的方法会导致实例共享引用类型的原型。所以属性定义最好在构造函数中而不是原型中。
  2. 在创建子类型的实例时,不能向超类型的构造函数中传递参数。

构造函数继承

实现方法

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

function SubType(){
  //继承了SuperType
  SuperType.call(this);
}

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

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

构造函数的问题

方法都在构造函数中定义,因此函数复用就无从谈起。


组合继承

将原型链和借用构造函数的技术组合起来,发挥二者之长的一种继承模式。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

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 instance1 = new SubType("John",29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName();  //"John"
instance1.sayAge();  //29

var instance2 = new SubType("Greg",27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //Greg
instance2.sayAge();  //27

原型式继承

实例

var ob = {name:"小明",friends:['小明','小白']};

//原型式继承  参数o,引用类型值,实质就是一个内存地址
function object(o){
  function F(){}//创建一个构造函数F
  F.prototype = o;
  return new F();
}

var ob1 = object(ob);
ob1.name = "小小";
ob1.friends.push("小黑");

var ob2 = object(ob);
console.log(ob2.name);//小明
console.log(ob2.friends);//小明,小白,小黑
关系图

这种原型式继承,要求你必须有一个对象可以作为另一个对象的基础。如果有这么一个对象的话,可以把它传递给object函数,然后再根据具体的需求对得到的对象加以修饰即可。

规范化

ECMAScript5通过新增Object.create()方法规范化了原型式继承。

var person = {
  name :"John",
  friends:["shelby","court","van"];
};

var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("bob");

var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "linda";
yetAnotherPerson.friends.push("lily");

alert(person.friends); //"shelby,court,van,bob,lily"

寄生式继承

与寄生构造函数和工厂模式类似,创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象。

function createAnother(original){
    var clone = Object.create(original);    //通过调用函数创建一个新对象
    clone.sayHi = function(){               //以某种方式来增强这个对象
        alert("Hi");
    };
    
    return clone;                        //返回这个对象
}

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

在上述例子中,createAnother函数接收了一个参数,也就是将要作为新对象基础的对象。

anotherPerson是基于person创建的一个新对象,新对象不仅具有person的所有属性和方法,还有自己的sayHi()方法。


寄生组合式继承

组合继承是js最常用的继承模式,组合继承最大的问题就是无论在什么情况下,都会调用两次构造函数:一次是在创建子类型原型时,另一次是在子类型构造函数内部。

组合继承的问题

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);  //第二次调用SuperType()
    
    this.age = age;
}
SubType.prototype = new SuperType();  //第一次调用SuperType()
SubType.prototype.sayAge = function(){
    alert(this.age);
}

在第一次调用SuperType构造函数时,SubType.prototype会得到两个属性: name和colors; 他们都是SuperType的实例属性,只不过现在位于SubType的原型中。

当调用SubType构造函数时,又会调用一次SuperType构造函数,这一次又在新对象上创建了实例属性name和colors。

于是这两个属性就屏蔽了原型中的两个同名属性。

解决方案

寄生组合式继承就是为了解决这一问题。

  • 通过借用构造函数来继承属性;

  • 通过原型链来继承方法。

不必为了指定子类型的原型而调用超类型的构造函数

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(){
    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 instance = new SubType("Bob", 18);
instance.sayName();
instance.sayAge();

inheritPrototype函数接收两个参数:子类型构造函数和超类型构造函数。

  1. 创建超类型原型的副本。
  2. 为创建的副本添加constructor属性,弥补因重写原型而失去的默认的constructor属性
  3. 将新创建的对象(即副本)赋值给子类型的原型
    这种方法只调用了一次SuperType构造函数,instanceof 和isPrototypeOf()也能正常使用。

相关文章

  • 再来看一次JS继承

    原型链继承 理解原型链的概念 用一张图来理解原型链再合适不过了。 总结概括JS红宝书上对原型链的概念:每个函数都有...

  • Js的继承

    js的继承 @(js)[继承, js, 前端] 组合继承是原性链继承和构造函数继承的合体,它汲取了二者各自的有点,...

  • JS继承

    JS中的继承 许多OO语言都支持两种继承方式:接口继承和实现继承; 因为JS中没有类和接口的概念 , 所以JS不支...

  • #js继承

    js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承)类式继承(构造函数间的继承) 类式继承是...

  • 2018-10-29 关于js原型链的讨论

    起源:为什么使用原型链 使用原型链是为了实现继承,那js的继承为什么选择了原型链呢?我们来看看网络的解释 http...

  • js继承遇到的小问题

    这两天在看js继承方面,它不像OC那种传统的类继承。js继承方式还是挺多的。比如:原型继承、原型冒充、复制继承 原...

  • JS中继承的实现

    JS中继承的实现 #prototype (js原型(prototype)实现继承) 全局的Function对象没有...

  • js继承

    js继承js 继承-简书 原型链实现集继承 上面的代码实现原型链继承最重要的son.prototype=new f...

  • JavaScript 10

    js继承的概念 1.通过原型链方式实现继承(对象间的继承) 2.类式继承(构造函数间的继承) 由于js不像Java...

  • JS继承的实现的几种方式

    前言 JS作为面向对象的弱类型语言,继承也是非常强大的特性之一,那么如何在JS实现继承呢? JS继承的实现方式 既...

网友评论

本文标题:再来看一次JS继承

本文链接:https://www.haomeiwen.com/subject/cfellxtx.html