对 JS 原型链以及继承的个人理解
这篇文章发布于 2023年12月01日,星期五,01:54。阅读 ? 次,? 条评论
JavaScript 为了实现继承,使用了如下两个属性:
prototype: 原型对象。只有函数才有这个属性,需被实例继承的属性和方法都定义在 prototype 对象上。原型对象上有一个指回构造函数自身的指针 constructor。__proto__: 每个对象都有这个私有属性(函数也是对象),其中实例对象的 __proto__ 属性指向它的构造函数的原型对象(有些对象不是通过构造函数 new 出来的,比如通过 Object.create() 和 extends 创建的对象)。__proto__ 是用以访问 [[Prototype]] 的非标准 getter/setter 属性,可以使用 Object.getPrototypeOf/setPrototypeOf() 获取修改对象的原型。const obj = Object.create(null)
obj.__proto__ = Array.prototype
console.log(obj.__proto__.slice)
console.log(obj.slice) // undefined原型上的 __proto__ 的 setter 才有改变 [[Prototype]] 的功能,Object.create(null) 的对象设置的 __proto__ 只是一个普通的属性,没有改变 [[Prototype]]
通过
__proto__将实例对象与他的原型对象串联起来,形成的一条链。
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。这也是为什么判断变量类型用 Object.prototype.toString.call() 更准确,因为在原型链下层继承过程中 toString 被重写了。
Object.prototype.toString.call(NaN).slice(8, -1) // 'Number'new 操作符的实现Object.create: 以一个对象为原型创建一个新对象。
function New(fn, ...args) {
// 1.创建一个空对象,并将该对象的 __proto__ 指向构造函数的 prototype
const obj = Object.create(fn.prototype)
// 2.将构造函数中的 this 指向 obj 后,执行构造函数,获取返回值
const res = fn.apply(obj, args)
// 3.判断返回值类型
return res instanceof Object ? res : obj
}这是最成熟的方法,也是现在库实现的方法。
constructor 的指向)。function inheritPrototype(subType, superType) {
// 创建对象,创建父类原型的一个副本
const prototype = Object.create(superType.prototype)
// 增强对象,弥补因重写原型而失去默认的 constructor 属性
prototype.constructor = subType
// 指定对象,将新创建的对象赋值给子类的原型
subType.prototype = prototype
}
// 父类初始化实例属性和原型属性
function SuperType(name)
核心代码如下,其实现和上述的寄生组合式继承方式一样。
function _inherits(subType, superType) {
subType.prototype = Object.create(superType && superType.prototype, {
constructor: {
value: subType,
enumerable: false,
writable: true,
configurable: true
}
})