从零构建JavaScript的对象系统

 1、正统的类与继承javascript

       类是对象的定义,而对象是类的实例(Instance)。类不可直接使用,要想使用就必须在内存上生成该类的副本,这个副本就是对象。html

       以Java为例:前端

       public class Group { } // 建立一个类java

       Group a = new Group(); // 实例化一个对象程序员

       经过继承,子类能够直接从父类得到其全部的属性和方法,继承的实现机制是"复制、拷贝"。浏览器

       public class Child extends Parent { } // 建立一个子类,继承父类的方法dom

 

2、原型与继承 ide

       和正统的面向对象语言不一样,JavaScript中不存在正统意义的"类"。缘由是Brendan Eich在设计JavaScript的时候,不但愿又从新设计一门面向对象的语言(由于已经有C++和Java了),而且他但愿把JavaScript设计得更简单,所以他借鉴了Java的语法,用构造函数代替类,因此JavaScript中的对象是经过构造函数建立的。函数

       这并不奇怪,JavaScript自己就是一个借鉴多种语言,仓促交媾的产物。idea

       严格的讲,JavaScript中既不存在类,也不存在实例,尽管这些概念是如此的深刻人心,以至于误用起来是那么顺其天然,但咱们仍是须要明白这一点。

       没有类,那么JavaScript怎么实现继承呢? Brendan Eich为构造函数设置了一个prototype属性。这个属性包含一个对象(即"原型对象"),全部实例对象须要共享的属性和方法,都放在这个对象里面;不须要共享的属性和方法,就放在构造函数里面。

       与类继承的"复制、拷贝"不一样,原型继承的机制是"引用、关联"。JavaScript中全部的对象都是由构造函数生成的,每一个对象都共同继承构造函数的原型对象中的属性和方法。

       在对象内部有两种方式访问它继承的原型:

       一、obj.constructor.prototype

       二、obj.__proto__

       第一种方法,源于每一个对象都拥有一个内置属性constructor指向其构造函数;第二种方法源于每一个对象都有一个内部指针[[prototype]],直接指向其原型,这个内部指针是不可访问的,可是有些浏览器暴露出一个__proto__属性,用于直接访问原型对象。

 

3、原型链与继承

       由于全部对象都是由构造函数生成的,也就是说全部对象,都必然继承某个原型,而原型自己也是对象,它也会继承别的原型,如此环环相扣就造成了原型链。

       JavaScript的对象系统是一个相似族谱的树状结构,每个分支都经过原型链一脉相承。

   基于原型链的继承机制和做用域链的工做机制很是相似:当调用对象的某个属性时,若是对象的自有属性中不存在该属性,那么JavaScript引擎就会沿着该对象的原型链向上查找,直到找到第一个匹配的属性名为止。

       原型链总有个尽头吧,就好像DOM只有惟一的根元素同样,全部原型链都汇聚到同一个源头,那就是Object.prototype,它也是一个对象,也有[[prototype]]属性,那么Object.prototype.__proto__ === ?答案是null。

       有人特别擅长发挥,就根据这个大谈“JavaScript原型设计的哲学思想”,什么道生于无,一辈子二,二生三,三生万物……这个真的想多了,一个花两周时间搞出来的“KPI项目”,怎么也扯不到哲学上去,这就是外行学前端的一个写照。原型链系统中每一个对象都必须关联到另外一个对象,而且不能循环引用,那么原型链就只能无限延伸下去,这显然是不可能的,所以只好把个不三不四的 null 拿来做为原型链的终结点,这也在必定程度上解释了 null 明明不是对象,可是它的数据类型倒是对象。

 

4、原型的关联规则

       每一个对象的[[prototype]]具体指向谁,或者说每一个对象的原型到底是谁,取决于对象的建立方式。

一、对象直接量的原型对象是Object.prototype;

       var obj = { }; obj.__proto__ === Object.prototype // true

二、经过Object.create( )建立的对象,其原型是由第一个参数指定的对象;

  对象直接量等价于Object.create(Object.prototype)

三、经过构造函数建立的对象,其原型即构造函数的原型对象。

   内置的构造函数的prototype原型是预设好的,咱们能够修改。内置构造函数的prototype原型并不都是普通的对象,例如:

       typeof Function.prototype // "function"

       Array.isArray( Array.prototype ) // true 

       但这不重要。

   自定义的构造函数,它的原型默认是一个仅含constructor属性的对象。

   function f () {}; Object.getOwnPropertyNames(f.prototype) // "constructor"

       比较特殊的是函数也有继承的原型。注意,这里很容易混淆“函数的继承原型”与“函数的prototype原型”,它们是两回事,函数不会从自身的prototype指向的原型对象中继承任何属性或方法,全部的函数都共同继承一个原型对象,那就是Function.prototype。

       Array.__proto__ === Function.prototype // true

       Function.__proto__ === Function.prototype // true

   Object.__proto__ === Function.prototype // true

       var f = function () { }; f.__proto__ === Function.prototype // true

       为何函数也有__proto__属性?这不奇怪,由于函数也是对象(可调用的对象)。

 

5、从零构建JavaScript对象系统      

       根据以上规则,咱们试着从零开始构建JavaScript的对象系统。

       首先,创造一个构造函数Object,为JavaScript空空如也的对象世界播下第一颗种子。而后给它添一些属性和方法。在Chrome控制台输入Object.getOwnPropertyNames(Object),能够看到Object有二十五个属性,其中就有prototype。

       prototype几乎就是JavaScript的繁育后代的生殖系统,因此它很关键,咱们须要传给它一些公共属性和方法:

   Object.prototype = {/* properties */}

    而后须要给Object定义私有属性,虽然它是函数,但毕竟函数也是对象,因此可以定义属性:

       Object.create = function ( ) { }; Object.keys = function ( ) { } ……

   一样的咱们须要给Function设置原型,可是这个原型不是普通对象,而是函数,所以不能用对象直接量: 

       Function.prototype = {/* properties */} // wrong

       Function.prototype = function () { } // right

       至于为何这么作,规范里只有规定,没有解释。

       (参考:http://stackoverflow.com/questions/39698919/why-typeoffunction-prototype-is-function)

       而后将Function.prototype.__proto__ 设置为 Object.prototype。

       如法炮制,因而咱们有了九大构造函数:Object、Function、Array、String、Number、Boolean、Date、Error、RegExp。

       再来两个单体内置对象:Math和JSON

       var Math = new Object(); // 这里采用new“实例化”了一个对象

       Math.random = ……

       Math.max = ……

       ……

 

       如今原型对象之间的关联有了,函数是否是也效仿着弄一个继承呢,这样就省得给每一个函数都定义相同的方法了,简单粗暴,直接将函数的[[prototype]]都指向Function.prototype完事儿。

         

    JavaScript内置的原型系统基本上就完成了,其它的构造函数和对象就留给程序员自定义设置吧。 

 

参考:阮一峰《JavaScript继承机制的设计思想》

http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html

相关文章
相关标签/搜索