关于JavaScript中对象的继承实现的学习总结
一、原型链
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中对象的继承实现的学习总结的更多相关文章
- javascript中对象函数继承的概念
什么是函数对象?这个对象既是通常意义上的对象,又可以加上括号直接执行的函数. 产生函数对象的方式有两种:1.通过function关键字产生:var fn = function(){};2.实例化Fun ...
- 理解JavaScript中的原型继承(2)
两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...
- javascript中对象字面量的理解
javascript中对象字面量与数组字面量 第一部分 我们知道JavaScript中的数据类型有基本数据类型和引用类型,其中Object类型就是非常常用的类型.那么如果创建一个Object类型的实例 ...
- javascript中的原型继承
在Javascript面向对象编程中,原型继承不仅是一个重点也是一个不容易掌握的点.在本文中,我们将对Javascript中的原型继承进行一些探索. 基本形式 我们先来看下面一段代码: <cod ...
- JavaScript中一个对象如何继承另外一个对象
如题,JavaScript中一个对象a如何继承另外一个对象b.即将b中的属性和方法复制到a中去. 面试中遇到了这个问题,当时脑子里的想法是: 1.除了循环遍历复制,还能怎样 2.javascript中 ...
- JavaScript中对象的属性
在JavaScript中,属性决定了一个对象的状态,本文详细的研究了它们是如何工作的. 属性类型 JavaScript中有三种不同类型的属性:命名数据属性(named data properties) ...
- JavaScript中对象转换为原始值的规则
JavaScript中对象转换为原始值遵循哪些原则? P52 对象到布尔值对象到布尔值的转换非常简单:所有的对象(包括数字和函数)都转换为true.对于包装对象亦是如此:new Boolean(fal ...
- 【你不知道的javaScript 上卷 笔记7】javaScript中对象的[[Prototype]]机制
[[Prototype]]机制 [[Prototype]]是对象内部的隐试属性,指向一个内部的链接,这个链接的作用是:如果在对象上没有找到需要的属性或者方法引用,引擎就 会继续在 [[Prototyp ...
- javascript中对象的深度克隆
记录一个常见的面试题,javascript中对象的深度克隆,转载自:http://www.2cto.com/kf/201409/332955.html 今天就聊一下一个常见的笔试.面试题,js中对象的 ...
随机推荐
- ClassLoader 详解及用途(写的不错)
ClassLoader主要对类的请求提供服务,当JVM需要某类时,它根据名称向ClassLoader要求这个类,然后由ClassLoader返回 这个类的class对象. 1.1 几个相关概念Clas ...
- c++异常捕获
概念: “C++异常”就是 try{}catch(...){} “SEH异常”就是 __try{} __except(-//){} (关于这两种异常,如有不了解的地方,网上有很多资料可以参考) 目前微 ...
- (转)HBase 的原理和设计
转自:HBase的原理和设计 HBase架构:
- php----显示中文乱码的问题
条件: 在显示页面设置页面编码格式为<?php header('Content-Type: text/html; charset=utf-8');?>: 在写入数据库时设置:mysql_q ...
- [Redis]如何通过Powershell创建Redis服务
目前Redis在中国上线了,不过只是预览版而且不能通过Portal进行操作,不过可以通过Powershell创建,具体如下: 下载最新的Powershell SDK:http://www.window ...
- Java数据库连接池封装与用法
Java数据库连接池封装与用法 修改于抄袭版本,那货写的有点BUG,两个类,一个用法 ConnectionPool类: package com.vl.sql; import java.sql.Conn ...
- _SYS_LIB="-lm -lnsl -ldl"
-lm 是指连接libm.so 意思是连接数学库, -lnsl 如果涉及RPC编程,必然需要libnsl.so,因此必须在编译选项里加入 -lnsl. gcc 编译选项 -L是要 ...
- R You Ready?——大数据时代下优雅、卓越的统计分析及绘图环境
作者按:本文根据去年11月份CSDN举办的“大数据技术大会”演讲材料整理,最初发表于2012年2月期<程序员>杂志. 0 R 的安装
- CSS鼠标响应事件经过、移动、点击示例介绍
本文为大家介绍下CSS 鼠标响应事件:鼠标经过CSS.鼠标移动CSS.鼠标点击CSS以及示例,喜欢的朋友可以参考下 几种鼠标触发CSS事件. 说明: onMouseDown 按下鼠标时触发 onM ...
- PHP弹出提示框并跳转到新页面即重定向到新页面
本文为大家介绍下使用PHP弹出提示框并跳转到新页面,也就是大家所认为的重定向,下面的示例大家可以参考下 这两天写一个demo,需要用到提示并跳转,主要页面要求不高,觉得没必要使用AJAX,JS等, ...