js-原型

原型对象prototype的主要作用是解决实例对象之间数据共享,节省内存空间。

我们以一段代码开始我们的原型之旅。

// 构造函数
function Foo() {}
// 实例对象
const foo = new Foo();
// 普通函数
function demo() {}
console.dir(Foo);
console.dir(foo);
console.dir(demo);
复制代码

image.png

显式原型和隐式原型

从控制台的打印结果可以看出,构造函数Foo(函数对象)和普通函数demo都有一个prototype属性和__proto__属性。实例对象foo有一个__proto__属性。我们称prototype为显式原型,__proto__为隐式原型。

所有函数都是Function的实例

 console.log(demo instanceof Function) // true
 console.log(Foo instanceof Function) // true
复制代码

我们经常说实例对象上会有__proto__属性,只要有__proto__就可以说明他一定是个实例对象,那么构造函数为什么也会有__proto__属性呢?这就要归功于Function了,所有函数都是通过new Function()生成的,也就是所有函数都是Function的实例,所以函数也有__proto__属性。

从打印的结果上看,函数和构造函数的结构是一模一样的,也就是说构造函数也是函数。

显式原型和隐式原型的关系

函数的prototype属性是在函数定义的时候自动添加的。默认值是一个空的Object实例对象。创建的大概过程Fn.prototype = {}

实例对象的__proto__属性是在对象创建的时候自动添加的,默认值是构造函数的prototype属性值。创建的大概过程this.__proto__ = Fn.prototype

//验证
console.log(foo.__proto__ === Foo.prototype);//true
复制代码

所以可以得出结论:实例对象的隐式原型的值等于其构造函数的显示原型的值,它们俩指向同一块内存区域。

原型链

// 构造函数
function Foo(w) {
    this.w = w;
}
Foo.prototype.a = 1;
Object.prototype.b = 2;
// 实例对象
const foo = new Foo(1);
console.log(foo.w); // 1
console.log(foo.a); // 1
console.log(foo.b); // 2
console.log(foo.c); // undefined

复制代码

foo上并没有ab,那么为什么可以访问到呢? 这就要归功于原型链的机制了。

内存图
image.png

原型链的查找机制

当访问一个对象的属性的时,首先会在自身属性中去查找,找到就返回;如果没有,就再沿着__proto__这条链向上查找,找到就返回,如果最终没有找到,返回undefined。Object原型对象就是原型链的尽头。

原型链是沿着隐式原型__proto__查找的。

image.png

那么这条链是如何产生的呢?从上文我们知道对象的隐式原型的值和它的构造函数显式原型的值是相等的。而且构造函数的显式原型对象默认是一个Object实例对象, 也就是说prototypeObject的实例对象,那么prototype的隐式原型__proto__就指向Object的显式原型prototype

在本例中也就是

console.log(Foo.prototype.__proto__ === Object.prototype);//true
复制代码

既然构造函数的显式原型对象默认是一个Object实例对象,那么Object.prototype它是不是Object的实例对象呢?答案是否定的。

console.log(Object.prototype instanceof Object); //false
复制代码

我们要修改一下前面的结论: 函数的显式原型prototype指向的对象,默认是空Object的实例对象(但是Object不满足)。

console.log(Object.prototype.__proto__); // null  
复制代码

那么Object.prototype是谁的实例呢?让我们来看看Object.prototype的隐式原型__proto__,不幸的是它的隐式原型为null,也就是说Object原型对象就是原型链的尽头。

// foo.__proto__是 Foo.prototype
// foo.__proto__.__proto__ 是 Foo.prototype.__proto__是Object.prototype
// foo.__proto__.__proto__.__proto__ 是Object.prototype.__proto__是 undefined/null
foo.__proto__.__proto__.__proto__ = null
复制代码

一个比较复杂的原型链

image.png

instanceof 的实现机制

表达式: A instanceof B

如果B函数的显式原型对象prototype在A对象的原型链__proto__上,返回true,否则返回false
简单实现,只能判断实例对象哦

function myInstanceof(left, right){
    // 获取实例对象的隐式原型
    let proto = Object.getPrototypeOf(left);
    // 获取函数显式原型对象
    const prototype = right.prototype;
    while(true){
        if(!proto) return false;
        if(proto === prototype) return true;
        // 沿着原型链查找
        proto = Object.getPrototypeOf(proto);
    }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享