一、原型链

  JavaScript 中原型链是实现继承的主要方法。其主要的思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。实现原型链有一种基本模式,其代码如下。

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

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

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

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

var instance = new SubType();
console.log(instance.getSuperValue());     // true;

这种继承的本质是重写原型对象,代之以一个新类型的实例。上面这段代码对应的对象关系图如下:

原型链实现的继承的主要问题是:a:当原型包含引用类型的值时,此属性会被所有实例共享; b:在创建子类型的实例时,不能向超类型的构造函数中传递参数。

二、借用构造函数

  借用构造函数也叫伪造对象或经典继承。其思想是在子类型的构造函数的内部调用超类型构造函数(这里的调用是指以普通函数的调用方式调用,而不是使用new操作符)。

function SuperType(name) {
    this.name = name;
}

function SubType() {
    // 继承了SuperType, 同时传递了参数
    SuperType.call(this, "Haha");

    // 实例属性
    this.age = 34;
}

var instance = new SubType();
console.log(instance.name);   // "Haha"

这样以后,SubType的每个实例都会有自己的实例属性的副本了。同时也可以在子类型构造函数中向超类型构造函数传递参数。同时,带来的问题是:方法都在构造函数中定义,函数复用无从谈起。而且在超类型的原型中定义的方法,对子类型而言是不可见的。

三、组合继承

  组合继承也叫做伪经典继承,其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

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.constructor = SubType;
SubType.prototype.sayAge = function() {
     console.log(this.age);
};

var instance1 = new SubType("Haha", 23);
var instance2 = new SubType("Hehe", 45);        

两个不同的SubType实例即分别拥有了自己的属性,又可以使用相同的方法。这里的缺点是:实例和实例的原型对象中,都存有父类的实例属性,不是特别完美。这个问题的解决方案是寄生组合式继承。

四、原型式继承

  基本思想是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。

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

var person = {
    name: "Haha",
    friends: ["Shelby", "Court", "Van"]
};

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

这种原型式继承,要求你必须有一个对象可以作为另一个对象的基础。ECMAScript 5中通过新增Object.create()方法规范化了原型式继承。这个方法接收两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。这种方式定义的属性会覆盖原型对象上的同名属性。

五、寄生式继承

  寄生式继承的思路与计生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。

function createAnother(original) {
    var clone = object(original);
    clone.sayHi = function() {
        alert("hi");
    };
    return clone;
}

var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};

var anotherPerson = createAnother(person);

这种方式使用了原型式继承,并在自己的实例对象上,又添加了自己的方法。在主要考虑对象而不是自定义类型和构造函数的情况下,继承式继承是一种有用的模式。示例代码中的object()函数不是必需的;任何能够返回新对象的函数都适用此模式。

六、寄生组合式继承

  前面的第三种组合式继承模式最大的问题是:无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。解决办法是使用寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。背后的思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。所以,我们可以使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。

function inheritPrototype(subType, superType) {
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}

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

SuperType.prototype.syaName = function() {
    console.log(this.name);
};

inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function() {
    console.log(this.age);
};

这个例子的高效率体现在它只调用了一次SuperType构造函数,并且避免了在SubType.prototype上创建不必要的、多余的属性。同时,保持了原型链不变。能正常使用instanceof和isPrototypeOf()。这就是关于JavaScript中对象继承的完美的解决方案。

七、总结

  当我们仔细去分析前面的六种方法的时候,其中的某几个模式之间的差异是非常小的。其实所有的这些模式无非就是利用了JavaScirpt的那些底层特性:构造函数、原型链、不同对象中属性的访问性的差异。

关于JavaScript中对象的继承实现的学习总结的更多相关文章

  1. javascript中对象函数继承的概念

    什么是函数对象?这个对象既是通常意义上的对象,又可以加上括号直接执行的函数. 产生函数对象的方式有两种:1.通过function关键字产生:var fn = function(){};2.实例化Fun ...

  2. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

  3. javascript中对象字面量的理解

    javascript中对象字面量与数组字面量 第一部分 我们知道JavaScript中的数据类型有基本数据类型和引用类型,其中Object类型就是非常常用的类型.那么如果创建一个Object类型的实例 ...

  4. javascript中的原型继承

    在Javascript面向对象编程中,原型继承不仅是一个重点也是一个不容易掌握的点.在本文中,我们将对Javascript中的原型继承进行一些探索. 基本形式 我们先来看下面一段代码: <cod ...

  5. JavaScript中一个对象如何继承另外一个对象

    如题,JavaScript中一个对象a如何继承另外一个对象b.即将b中的属性和方法复制到a中去. 面试中遇到了这个问题,当时脑子里的想法是: 1.除了循环遍历复制,还能怎样 2.javascript中 ...

  6. JavaScript中对象的属性

    在JavaScript中,属性决定了一个对象的状态,本文详细的研究了它们是如何工作的. 属性类型 JavaScript中有三种不同类型的属性:命名数据属性(named data properties) ...

  7. JavaScript中对象转换为原始值的规则

    JavaScript中对象转换为原始值遵循哪些原则? P52 对象到布尔值对象到布尔值的转换非常简单:所有的对象(包括数字和函数)都转换为true.对于包装对象亦是如此:new Boolean(fal ...

  8. 【你不知道的javaScript 上卷 笔记7】javaScript中对象的[[Prototype]]机制

    [[Prototype]]机制 [[Prototype]]是对象内部的隐试属性,指向一个内部的链接,这个链接的作用是:如果在对象上没有找到需要的属性或者方法引用,引擎就 会继续在 [[Prototyp ...

  9. javascript中对象的深度克隆

    记录一个常见的面试题,javascript中对象的深度克隆,转载自:http://www.2cto.com/kf/201409/332955.html 今天就聊一下一个常见的笔试.面试题,js中对象的 ...

随机推荐

  1. hihoCoder1284机会渺茫(唯一分解定理 + 约分)

    题目链接 #1284 : 机会渺茫 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi最近在追求一名学数学的女生小Z.小Z其实是想拒绝他的,但是找不到好的说辞,于是提出 ...

  2. HDU1698Just a Hook(线段树 + 区间修改 + 求和)

    题目链接 分析:1-N区间内初始都是1,然后q个询问,每个询问修改区间[a,b]的值为2或3或者1,统计最后整个区间的和 本来想刷刷手速,结果还是写了一个小时,第一个超时,因为输出的时候去每个区间查找 ...

  3. 前端必备:FastStoneCapture 和 Licecap

    前端必备:FastStoneCapture 和 Licecap FastStoneCapture这个软件非常小,只有2M多,并且其功能很强大,包括截图,录制视频,量尺,取色等等,对于前端工程师绝对是必 ...

  4. jquery 图片浏览功能实现

    效果展示: HTML代码: <div id="no3"> <img src="./img/last.png" id="last&qu ...

  5. RAL 标准颜色表(RAL Color Chart)

    根据经典RAL系统,本网页显示RAL标准颜色的概览.RAL用于信息,为图画和涂层定义标准颜色.现在,它是最流行的中欧颜色标准.这些颜色广泛用于建筑学,建筑物,工业和道路安全. 图表中的RAL颜色尽可能 ...

  6. 【原】react中如何使用jquery插件

    react的思想是虚拟dom,提倡最好较少dom的操作,可是我们在写网页的时候,有些复杂的交互还是离不开jquery插件的.而且当你把jquery直接拿来用的时候,你会发觉会报错,要么是找不到那个插件 ...

  7. quartz_jobs.xml标准配置

    <?xml version="1.0" encoding="UTF-8"?><job-scheduling-data xmlns=" ...

  8. JS判断是wap端访问网站还是PC端访问,然后进行自动跳转的代码

    <script type="text/javascript"> function goPAGE() { if ((navigator.userAgent.match(/ ...

  9. Ztree的简单使用和后台交互的写法(二)

    针对Ztree的简单使用和后台交互的写法(一)中的树进行改进 1.增加节点的权限 由页面的当前用户,决定树的根节点 然后动态获取树的详细节点: 初始化函数为: function init(){ //初 ...

  10. codeforces 724B Batch Sort(暴力-列交换一次每行交换一次)

    题目链接:http://codeforces.com/problemset/problem/724/B 题目大意: 给出N*M矩阵,对于该矩阵有两种操作: (保证,每行输入的数是 1-m 之间的数且不 ...