原型
原型
每个函数都有一个默认的原型对象 - prototype
,通过 prototype
我们可以扩展 js 的内置对象。一个函数和它创建的实例共享这个函数的原型属性和方法。实例对象的 constructor
会指向构造函数
原型链
每个实例对象都会有一个隐式原型属性 __proto__
,通过 __proto__
指针指向创建该对象的构造函数的原型对象,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 Object.prototype
,而 Object.prototype.__proto__ === null
可以看到:
- 对象都能通过
__proto__
属性找到Object.prototype
,Object.create(null)
创造出的对象例外,因为没有__proto__
属性。 - 函数都能通过
__proto__
属性找到Function.prototype
- Object 本身是个构造函数,是 Function 的实例
根据规范不建议直接使用
__proto__
,推荐使用Object.getPrototypeOf()
instanceOf
的原理
比如 A instanceOf B
,会先沿着 A 的原型链一直向上找,如果能找到一个 __proto__
等于 B 的 prototype
,则返回 true;如果找到终点还没找到则返回 false
function _instanceOf(A, B) {
if (!A || !B) {
return false;
}
let O = B.prototype;
A = A.__proto__;
while (true) {
if (A === null) {
return false;
} else if (O === A) {
return true;
} else {
A = A.__proto__;
}
}
}
Object
和Function
的鸡和蛋的问题
Object instanceof Function; // true
Function instanceof Object; // true
Object
本身是个构造函数,是Function
的实例,即Object.__proto__ === Function.prototype
Function.__proto__
指向了Function.prototype
,Function.prototype
继承自Object.prototype
,Function.prototype.__proto__ === Object.prototype
js 引擎查找对象属性/方法
先通过作用域链查找对象本身的属性或方法,之后沿着__proto__
构成的原型链向上查找原型对象中的属性和方法,直到找到一个名字匹配的属性/方法或到达原型链的末端,如果找不到就会返回 undefined
为了判断一个对象是否包含自定义属性而不是原型链上的属性, 需要使用继承自 Object.prototype 的
hasOwnProperty
方法
面试题
// Object.prototype 是原型链的顶端
console.log(Object.prototype.__proto__ === null); // true
// Function可以理解为制造一切函数的机器,且自身也是由自己制造的,所以
console.log(Function.__proto__ === Function.prototype); // true
// Object从「对象」角度来讲,是由构造函数 Function 生产的
console.log(Object.__proto__ === Function.prototype); // true
// Function虽然由自身生产,但生产“机器”总要一个模板吧,这个模板对象(Function.prototype.__proto__)就是 Object.prototype
console.log(Function.prototype.__proto__ === Object.prototype); // true
// Object作为一个机器可以看做是有由Function制造出来的
// 而Function作为一个对象可以看做是由Object制造出来的。
console.log(Object instanceof Function); // true
console.log(Function instanceof Object); // true
// String 作为「对象」,是有构造函数 Function 生产的
console.log(String.__proto__ === Function.prototype); // true
// String.prototype 是个对象,是有 Object 生产的
console.log(String.prototype.__proto__ === Object.prototype); // true
function Person() {}
// 自定义构造函数作为「对象」,也是 Function 生产的
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
// Person 和 Object 一样,都是构造函数,都是有 Function 生产出来的对象
console.log(Person.__proto__ === Object.__proto__);
function Student() {
Person.call(this);
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor === Student;
console.log(Student.__proto__ === Function.prototype); // true
console.log(Student.prototype.__proto__ === Person.prototype); // true