JavaScript中的原型与原型链理解

64 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情

前言

js中要说比较让人难理解的技术点,我想原型与原型链可以算其中一个比较难理解的知识点。我们得理解隐式原型、显示原型、new关键字、构造函数等等概念要熟悉。

什么是原型

在JavaScript中,每个对象都有一个内置的属性prototype,这个属性也是一个对象,并且指向另外一个对象,这个属性prototype就可以叫做对象的原型。

首先我们得先理解几个关键属性

__proto__

这个属性叫隐式原型,可以通过 对象. _proto_获取到,不过这个是浏览器自己添加的,存在一定的兼容性问题,所以实际代码里如果要使用这个属性,一般要做判断,但是不建议直接拿来用。

var proObj ={
    name:'gogo',
    age:23
}

console.log(proObj)
console.log(proObj.__proto__)

如果想要拿对象的原型,建议通过

Object.getPrototypeOf(proObj)来获取到这个对象的原型。因此可以得出 Object.getPrototypeOf(proObj) == proObj.__proto__ image.png

image.png

prototype

这个属性叫显示原型,只有函数对象才有,也就是所有的函数都有prototype属性。


function Person(){
    name:'person'
}

console.log(Person.prototype)
console.log(Person.__proto__)

image.png

new 操作符

new 操作的过程是

创建一个空对象,将这个空对象赋值给this。

将函数的显示原型赋值给这个对象作为它的隐式原型

执行函数体代码,将这个对象默认返回。

var o1=new Person()
console.log(o1.__proto__)
console.log(Person.prototype)

执行代码看下结果,可以看到2个是相等的。 image.png

原型链

从一个对象上获取属性,如果在当前对象没有获取到就会去它的原型上获取。



    function Animal(name) {
        this.name = name;
    }
    
    //如果没有dance方法,就去构造函数原型对象prototype身上去查找dance这个方法。
    Animal.prototype.dance = function () {
        console.log(this.name + '2');
    };
    
    //如果再没有dance方法,就去Object原型对象prototype身上去查找dance这个方法。
    Animal.prototype.dance = function () {
        console.log(this.name + '3');
    };
    //如果再没有,则会报错。
    let obj = new Animal('小狗');
    obj.dance();
    console.log(obj)
    console.log(obj.__proto__);  //{dance: ƒ, constructor: ƒ}

image.png

我们调用了对象的方法,发现并没有,因此会去对象Animal上的原型去查找,我们在这个原型上定义了这个方法,因此会调用到这个方法。

如果在Animal的原型上没有找到dance方法,那么就会继续找上层原型,即原型对象的原型,写法如下, 发现在继续向上找,就找到了Object原型,并且存在这个方法,因此完成这次操作,这就是原型链的操作。

  console.log(obj.__proto__);  //{ constructor: ƒ}
    console.log(obj.__proto__.__proto__);  // 

image.png

总结

某个函数作为对象都是Function的实例对象,因此也存在隐式原型,指向Function的显示原型。

某个函数作为函数存在,则存在显示原型和隐式原型,显示原型则指向本身函数对象的原型。 Person.prototype.__proto__==Object.prototype

某个Object对象则只有隐式原型,指向Object的显示原型。

整个原型的规则思路则是按下图,理解完这个图,则掌握

image.png