JS语言理解03 非构造函数的继承
JavaScript中非构造函数的继承
什么是”非构造函数”的继承?
让一个对象去继承一个不相关对象,由于这两个对象都是普通对象,不是构造函数,所以无法使用构造函数方法实现继承。
object()
方法
JSON格式的发明人Douglas Crockford,提出了一个object()
函数,可以做到这一点。
1 | function object(o) { |
这个object()
函数,其实只做一件事,就是把子对象的prototype
属性,指向父对象,从而使得子对象与父对象连在一起。
使用的时候,第一步先在父对象的基础上,生成子对象:
1 | var Doctor = object(Chinese); |
实现了子对象对父对象的继承。
ES6中的Object.create
方法的原理就是这样。
Object.create()
方法
Object.create
是直接通过原型,而非模拟类,来实现普通对象(非构造函数)之间的继承。ES6之后这也是最常用的实现普通对象继承的方法
1 | let child = Object.create(father, descriptors); |
这样就可以实现child与father的继承,继承关系是通过child.__proto__ = father
实现的,再通过描述符对象descriptors
添加属于自己的属性
实际上,可以把上面object()
方法看做Object.create
方法的简易Pollyfill
Object.setPrototypeOf()
方法
Object.setPrototypeOf()
和Object.create
都是更改原型链的手段,Object.getPrototypeOf(a)
是用来获取对象的__proto__
属性
Object.setPrototypeOf(a, b)
实现的是a.__proto__ = b
,最常用来避免直接操作对象的非标属性__proto__
1 | Object.setPrototypeOf(child, father) |
注意的是,更改__proto__
性能很差,应该避免设置一个对象的[[Prototype]]
,应该使用 Object.create()
来创建你想要的[[Prototype]]
的新对象
浅拷贝
除了prototype链的思路之外,可以通过对象浅拷贝的方法实现继承:
1 | function extendCopy(p) { |
浅拷贝的问题就是如果父对象的属性等于数组或另一个对象,那么子对象获得的就是指向这个数组或对象的指针,因此存在父对象被篡改的可能。
深拷贝
深拷贝可以实现真正意义上的数组和对象的拷贝,原理是递归调用浅拷贝。
1 | function deepCopy(p, c) { |
之所以不用判断
p
的类型是对象还是数组,原因出在for...in
上,会遍历p
的原型上的属性,具有所有数组原型属性的对象,就是数组了。
==一次面试的时候,发现下面的这个函数有些问题,之前没有注意到==
在进行这个判断typeof p[i] === 'object'
时,对JSON
/Math
/RegExp
对象是有问题的,问题还是出现在了对象判断上,还是使用Object.prototype.toString.call
判断更准确
1 | function deepCopy(p, c) { |
jQuery的extend
方法第一个参数默认为false,此时实现的是浅拷贝,如果为true则实现的其实就是上述的深拷贝。
1 | jQuery.extend([deep], target, object1[, objectN]) |