原型机制是理解对象继承和属性查找的关键
__proto__ 属性,函数也是对象prototype 属性__proto__ 指向构造函数的 prototype
实例对象.__proto__ === 构造函数.prototypeprototype 是一个对象,有一个默认的 constructor 属性,指向其构造函数
构造函数.prototype = { constructor: 构造函数, __proto__: XXX }构造函数.prototype.constructor === 构造函数实例无法直接修改(新增、删除、修改)原型上的字段(属性和方法),而是修改自身字段。除非显示调用 实例.__proto__ 进行修改
function F() {}
F.prototype.tag = 'F'
F.prototype.printTag = function() { console.log('[TAG]', this.tag) }
const f = new F()
console.log(f.tag) // 'F'
f.printTag() // '[TAG] F'
delete f.tag // true
// 无法删除原型上的字段
// f:
// {
// __proto__: { tag: 'F', printTag: function(), constructor: F, __proto: XXX }
// }
f.tag = 'i am f'
f.printTag() // '[TAG] i am f'
// 无法修改原型上的字段,只是在自身上修改字段
// f:
// {
// tag: 'i am f',
// __proto__: { tag: 'F', printTag: function(), constructor: F, __proto: XXX }
// }
// 调用 printTag() 时,找 this.tag,在自身上找到了,就不向上找原型链了
delete f.tag // true
f.printTag() // '[TAG] F'
// 可以删除自身的字段
// f:
// {
// __proto__: { tag: 'F', printTag: function(), constructor: F, __proto: XXX }
// }
实例对象.__proto__ 指向 构造函数.prototype,是在 new 时发生的。之后如果修改了 构造函数.prototype 指向,之前 new 的实例对象的 __proto__ 还指向原来的 构造函数.prototype
function F() {}
F.prototype.tag = 'F'
F.prototype.printTag = function() { console.log('[TAG]', this.tag) }
const f1 = new F()
F.prototype = {
constructor: F,
tag: 'other F',
printTag() { console.log('[--TAG--]', this.tag) }
}
const f2 = new F()
console.log(f1.tag) // 'F'
f1.printTag() // '[TAG] F'
console.log(f2.tag) // 'other F'
f2.printTag() // '[--TAG--] other F'
new 逻辑手写: ^new
Function.prototype.new = function(...args) {
// 1. 创建实例对象
const instance = {}
// 2. 绑定原型
instance.__proto__ = this.prototype
// 或:const instance = Object.create(this.prototype)
// 3. 模拟 ES6 的 new.target
instance.newTarget = this
// 构造函数通过 this.newTarget 访问
// 4. 执行构造函数,并改变 this 指向为实例对象
const res = this.apply(instance, args)
// 5. 构造函数返回非原始类型,则返回该对象
if (res !== null && (typeof res === 'object' || typeof res === 'function')) {
return res
}
// 否则返回实例对象
return instance
}
[[Prototype]]实例对象.__proto__ 是非标准字段,所以不建议使用Object.getPrototypeOf(实例对象) 或 Reflect.getPrototypeOf(实例对象) 获取Object.setPrototypeOf(实例对象) 或 Reflect.setPrototypeOf(实例对象) 修改![[Pasted image 20240925124641.png]]
两个注意点:
Object.prototype.__proto__ === null
Object.prototype 是对象,所以其 __proto__ 应该指向 Object.prototype,但这样就死循环了,所以显式规定 Object.prototype.__proto__ === nullFunction.__proto__ === Function.prototype
Function 是函数,所以 Function.__proto__ === Function.prototype