搞懂JavaScript原型链

73 阅读2分钟

首先原型,原型链到底有什么用,为什么要去学习。 来看一段代码

const arr = [1,2,3];
arr.pop() //arr变为[1,2]

const obj = {name:"sdy"}
obj.toString() //res-> [object Object]

在这段代码中发现,对象与数组都可以调用一些方法来操作自己。但是当我们在控制台打印却又发现没有这些方法的存在。

所以我们这篇文章就是来说明这个问题。

原型

在js这个语言中,所有的函数都是通过new Function来创建的,不论是我们自定义的函数,还是js内部的函数像:Object,Array等。

而每个函数都有一个prototype的对象,这个对象存储的就是函数的原型,当我们打印Object,Array的原型后,就会发现上面的toString,push方法都在里面的。

uTools_1690884377475.png

uTools_1690884441110(1).png 而在prototype里面又有一个constructor的属性,他又可以指向构造函数本身的

Object.prototype.constructor === Object //true

隐式原型__proto__

在所有的对象里面都有一个proto 的属性,而这个属性指向 创建该对象的构造函数的原型。

const obj = {};
obj.__proto__ === Object.prototype//true
//在这段代码中注意:在js中直接书写字面量对象,实际上就是通过new Object来创建的。
因此obj的构造函数就是Object

function Fun(){}
const obj1 = new Fun();
obj.__proto__ === obj1.prototype//true 
理解上面代码后,这里也很容易

//关键的地方来了,既然所有的对象都有__proto__,那prototype也是对象啊,他也应该有__proto__,没错,prototype里面的__proto__,指向的就是Object.prototype

obj1.prototype.__proto__ === Object.prototype //true

原型链

当我们调用一个属性或方法的时候,首先会从创建自己的构造函数的prototype里面来调用,如果没找到的话,就会从prototype里面__proto__,指向的对象再去找,循环往复

上面那句话就是本篇文章的关键,特别重要

let arr = [1,2];
// 首先字面量的数组,都是通过new Array来创建的。
// 因此arr.__proto__,指向Array.protoype,而push方法就存放在Array.prototype里面的

看到这里我们最开始的疑问就基本解决了

这里有两点要特别注意1,Object.prototype.__proto__ 指向null。2,Function.__proto__ 指向Function.prototype.__proto__

圣杯模式

但是如果我们需要将自定义的2个函数,来实现继承该怎么办

//es5
function inherit(son,father) {
    son.prototype = Object.create(father.prototype);
    son.prototype.constructor = son;
    son.prototype.uber = father.prototype;
}
//es5以前
var inherit = (function () {
    var tmp = function (){};
    return function (son, father) {
        tmp.prototype = father.prototype
        son.prototype = new tmp();
        son.prototype.constructor = son;
        son.prototype.uber = father;
    }
})()