关于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中对象的 ...
随机推荐
- JS-DOM 综合练习-动态添加删除班级成绩表
费了2个小时,才把原理弄懂,把问题逐个解决,当你发现你最后栽的那个点,是一个小石头拌的你,你起来是该哭还是该笑呢?只怪自己习武不精吧. 虽然问题都解决了,但是还有一个余留的问题就是鼠标经过input时 ...
- php 简单分页类
/** file: page.class.php 完美分页类 Page */ class Page { private $total; //数据表中总记录数 privat ...
- split shell tools
split [-bl] file [prefix] 参数说明: -b, --bytes=SIZE:对file进行切分,每个小文件大小为SIZE.可以指定单位b,k,m. -l, --lines=NUM ...
- php上传$_FILES 无法取值
无法取值的主要原因在form. 代码 <form method="post" action="****" name="theForm" ...
- UIAlertController 标题文字大小 颜色
NSString *title = [NSString stringWithFormat:]; NSString *msg = @"\n把红包分享给微信好友,金额随机,可用于购买雪票和雪卡& ...
- "Java 反序列化"过程远程命令执行漏洞
一.漏洞描述 国外 FoxGlove 安全研究团队于2015年11月06日在其博客上公开了一篇关于常见 Java 应用如何利用反序列化操作进行远程命令执行的文章.原博文所提到的 Java 应用都使 ...
- Map静态键值对
private final static Map<String,String> map = new HashMap<String, String>(); static { // ...
- GC垃圾回收机制
学习资料:http://kb.cnblogs.com/page/106720/
- [Mongodb]删除指定字段
摘要 如果想要删除mongodb中一个document的某个字段,该如何做呢? 方法模版 db.user.update({"email_state":{"$exists& ...
- Linq 操作基础
参考资料: LINQ系列:LINQ to DataSet的DataTable操作 List<T>转换为DataTable C# DataTable 和List之间相互转换的方法 Linq中 ...