摘要:由于原型即本身也是对象,所以原型继承可认为是一种特殊的对象式继承。原型继承里的原型即是函数的特有属性,原型继承事先得有函数。揭秘魔术箱不论原型继承还是对象式继承,其核心技术是实现了对象实例的链。
JavaScript的原型继承是老生常谈。由于原型即prototype本身也是对象,所以“原型”继承可认为是一种特殊的“对象式”继承。”对象式“继承是笔者基于自己的理解,所提出的一个名词。本文就着重阐述这两种继承方式的异同之处。
原型继承JavaScript里的原型即prototype是函数的特有属性,原型继承事先得有函数。
// 定义函数Foo function Foo(name) { this.name = name; } // 定义Foo的原型 Foo.prototype.say = function() { console.log(this.name, "say"); }
函数及其原型定义好了,就可以使用原型继承了。
var foo = new Foo("foo"); foo.say() //foo say foo instanceof Foo; //true。 foo 是Foo的一个实例 foo.__proto__ === Foo.prototype // true
上面用的是new操作符,它实际是通过Object.create工作,其过程如下。所以new其实是Object.create的便利操作方式。
var foo = Object.create(Foo.prototype); foo.name = "foo" foo.say(); foo instanceof Foo; //true。 foo 是Foo的一个实例 foo.__proto__ === Foo.prototype // true
请打起精神,Object.create(...)接受一个函数原型即object实例,以此实例为“模型”,创建新的object实例。新object实例的__proto__指向前function的prototype,自此新object实例也就拥有了前function prototype的字段和方法。
既然Foo.prototype本身是object实例,那么我们是否可以给Object.create(...)传入一个普通的object实例呢?答案是可以的。这就是本文所要表述的“对象式”继承。
“对象式“继承开门见山地用code来说明:
// 创建对象实例Foo var Foo = { name: "foo", say: function() { console.log(this.name, "say"); } } // 以Foo为“模型”,创建新的对象实例foo var foo = Object.create(Foo); foo.__proto__ == Foo;// true // 所以foo也会拥有Foo的字段和方法,这点与原型继承类似。 foo.say(); // foo say. // 但是foo不是Foo的实例。 foo instanceof Foo; // TypeError: Right-hand side of "instanceof" is not callable
如果Foo是个函数,结果基本是相同的,除了instanceof Foo 会等于false。
function Foo() { } Foo.say = function() { console.log(Foo.name, "say"); } // 以Foo为“模型”,创建新的对象实例foo var foo = Object.create(Foo); foo.__proto__ == Foo;// true // 所以foo也会拥有Foo的字段和方法,这点与原型继承类似。 foo.say(); // Foo say. // 但是foo不是Foo的实例。 foo instanceof Foo; // false“对象式”继承的一个应用
举个不太恰当的例子,如果我们需要对Math.abs做些“修正”,对于在-1和1之间的数值保持原值。
var MMath = Object.create(Math); MMath.abs = function(val) { if (val >= -1 && val <=1) { return val; } return MMath.__proto__.abs(val); } MMath.abs(0.5) // 0.5 MMath.abs(-0.5) // -0.5 MMath.abs(-2) // 2揭秘Object.create魔术箱
不论原型继承还是“对象式”继承,其核心技术是Object.create(...)实现了对象实例的__proto__链。我们做个简单的实现:
Object.myCreate = function(obj) { if (obj instanceof Object || obj === null) { var newObj = {}; Object.setPrototypeOf(newObj, obj) return newObj; } else { throw "error happens. Should input a object"; } }
function Fooo() {} Fooo.say = function() { console.log(Fooo.name, "say"); } var myFooo = Object.myCreate(Fooo); myFooo.say(); // Fooo say
自此我们了解了Object.create(...)的黑魔法,也有助于我们理解Object.create({})和Oject.create(null)的区别,就是前者的__proto__是个object实例,拥有toString等方法。后者的__proto__是null,它不具有任何方法。在特别注重效率的情景,后者具有优势。
总结本文提出“对象式”继承的概念,并与原型继承对比,阐述其区别和联系,希望有助于深化理解。虽然ES6越来越广泛应用了,了解函数原型等这些ES3/ES5的概念应该是有助于JS的深入学习。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/84741.html
摘要:面向对象实现代码动物发声汪汪喵喵调用代码动物发声喵喵动物发声汪汪当要增加一种动物时,只需增加一个继承,不会影响其他已有的动物逻辑。所以的继承和的原型继承,可谓殊途同归。 传统面向对象的继承和多态 我们知道C++/Java/C#等面向对象语言,都原生地支持类的继承。继承的核心作用大抵是创建一个派生类,并使其复用基本类(即父类)的字段和/或方法。并且派生类可以重写基本类的方法。这样基本类和...
摘要:从运行结果可以看出,当子类继承多个父类的时候,对于构造函数,只有第一个能够被继承,第二个就等掉了。重点看,类继承了,同时,在构造函数中自己做了规定,也就是的构造函数是按照的意愿执行,不执行的内容,但是,还有一个方法,则继承了这个方法。 在上一讲代码的基础上,做进一步修改,成为了如下程序,请看官研习这个程序: #!/usr/bin/env python #coding:utf-8 c...
摘要:的内存分配方式修饰变量通常情况下,变量有个地方可以赋值直接赋值,构造函数中,或是初始化块中。如就是对于变量,在声明时,如果你没有赋值,系统默认这是一个空白域,在构造函数进行初始化,如果是静态的,则可以在初始化块。 【java中为什么会有final变量】: final这个关键字的含义是这是无法改变的或者终态的; 那么为什么要阻止改变呢? java语言的发明者可能由于两个目的而阻止改变: ...
摘要:在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本特征。 在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本特征。 1.再论向上转型 多态作用:消除类型之间的耦合关系. 2.转机 绑定:将一个方法调用同一个方法主体关联起来. 前期绑定:在程序执行前就进行绑定(面向过程语言默认绑定方式). 后期绑定:也叫动态绑定或运行时绑定,在运行时根据对象的类型进行绑...
摘要:这正是我们想要的太棒了毫不意外的,这种继承的方式被称为构造函数继承,在中是一种关键的实现的继承方法,相信你已经很好的掌握了。 你应该知道,JavaScript是一门基于原型链的语言,而我们今天的主题 -- 继承就和原型链这一概念息息相关。甚至可以说,所谓的原型链就是一条继承链。有些困惑了吗?接着看下去吧。 一、构造函数,原型属性与实例对象 要搞清楚如何在JavaScript中实现继承,...
阅读 915·2021-11-24 09:38
阅读 924·2021-11-23 09:51
阅读 2938·2021-11-16 11:44
阅读 1761·2021-09-22 15:52
阅读 1625·2021-09-10 11:20
阅读 1360·2019-08-30 13:47
阅读 1291·2019-08-29 12:36
阅读 3292·2019-08-26 10:43