JavaScript 面向对象(七)原型链深入

来源:互联网 发布:自动化控制软件 编辑:程序博客网 时间:2024/06/04 13:47

7.1 __proto__属性

W3C是没有规定一个元素的原型链有一个可见的属性,Chrome浏览器特有 __proto__属性。实际上,其他浏览器有原型链的机制,但是我们看不见这个属性只不过,Chrome浏览器为了我们初学者学习方便,增加了这个属性:


但是在Chrome中,__proto__属性是可以自由更改的,而这根本不是语言的规范,其他浏览器没有实现,也就是说,__proto__属性在其他浏览器中,在语言规范中根本就是看不见的,就没有这个属性


原型链的获得有两种情况:

1)引用类型值的对象它们的字面量的__proto__就是他们类型的构造函数的prototype。


2)通过new关键字,此时构造函数的prototype就是实例的__proto__。


实际上,在语言规范中,一旦原型链产生,将不能更改!只不过Chrome浏览器做的高级了一些,让我们自由更改__proto__而已。


ECMAScript2016中,提供了Object.create()函数,可以让我们指定一个对象为原型对象,来创建新对象。





这个Object.create 兼容性很差,我们能不能自己写一个函数create,它接受一个对象参数,返回以这个对象为原型对象的新对象。我们可以用一个临时的构造函数来中转:



显而易见的是,任何一个对象都有原型对象,原型链的终点就是Object.prototype



在Chrome中,可以自由设置__proto__,从而可以让一个对象的原型对象不存在。



对象的toString()方法都是定义在Object.prototype上的,而这个对象是所有对象的原型链终点,所以任何对象都能调用toString()方法,但是切断原型链之后就不行了。


事实上,在语言设计中,当对象一旦创建,原型链一旦确定,此时就没有任何方法删除、改变对象的原型链。Chrome中的__proto__仅仅供研究、学习使用。



7.2 constructor属性


任何一个构造函数的prototype身上,都有一个constructor属性指向构造函数。






constructor 属性比较脆弱,当我们修改原型链对象,比如People.prototype.haha=function(){}此时没有任何问题,但是如果用字面量强行更改了这个对象, 此时 xiaoming 的constructor 就丢了。




还有,比如:


此时,newB()实际上实例是A的实例,此时实例的constructor 指向A。

constructor 属性确实在构造函数的 prototype 身上,但是这个属性不可枚举。

也就是说,如果我们遇见

obj . constructor === 构造函数  //true

此时我们可以稍稍认为obj 是这个构造函数的实例,但是也不一定,比如我们上面举的两个例子。



7.3 instanceof 运算符


这个运算符用来检测某一个对象是不是某一个构造函数的实例。


语法:

待检测对象  instanceof  某个函数


此时这个东西不靠谱。


要知道instanceof 的机理,本质上:

对象 instanceof 函数

如果函数的 prototype 在对象的原型链上,此时返回 true ; 反之返回 false 。

换句话说,

如果对象的原型链上,恰好有某一个元素是函数的 prototype ,此时返回 true ; 反之返回 false 。


因为Object . prototype 是所有人的原型链终点,所以任何对象:

任何对象  instanceof  Object     // true

总结,在JS中,我们没有一种可靠的办法探寻一个元素是不是一个构造函数的实例


鸭式辨型:如果一个动物能够嘎嘎叫,并且走路摇摆,黄色有两只脚,它就是鸭子。


7.4 继承

看看人类和狗类有什么关系,没关系! 计算机领域,关注两个类的关系,就是看属性群之间的关系。

比如,人类和狗类属性群有相交,但是不完全重合,此时可以认为两个类没有任何关系:



人类和小学生类有什么关系,小学生是一类人,小学生肯定是人。人拥有的属性,小学生一定拥有。人拥有的能力,小学生一定也拥有!但是反过来,小学生的属性,人没有,小学生的能力,人也没有。


此时计算机中,小学生继承(extend)了人类

A 继承了 B,此时要意识到:

A 拥有 B 的所有属性和方法,

A 的属性群比 B 大,

A 丰富了 B ,A 把 B 变的更具体,范围更小。


JavaScript 来实现这样的两个类:People类 、Student类,People类拥有的所有属性和方法,Student类的实例都拥有,都能打点调用。Student还能丰富自己的类的属性和方法。


此时很简单, 只需要巧妙设计原型链

   




jQuery的创始人 john Resig写了一个小包,20多行,解决了JS继承恶心的问题。

https://johnresig.com/about/


7.5  属性归属

看看 a 属性是不是在 obj 对象身上(而不是在原型链上),最好用的方法:

obj.hasOwnProperty("a") ;

不靠谱的:

  1. in 运算符 ,此时如果 a 属性在原型链身上也会返回true.                                                                     "a" in obj ;                                                                                                                        for(var k in obj ) {}此时只会遍历可枚举属性。
  2. 点语法 / 方括号枚举   obj.a !=undefined  //看看是不是 undefined                                                  此时的问题是:  首先如果这个值在原型链上,也能返回值;所以不好判断是不是在自己身上;有 a 属性,并且 a 属性就在自己身上,但是值是undefined,此时大水冲了龙王庙,你误会大了!

     

  



原创粉丝点击