到底JavaScript原型以及原型链是什么?

原型是JavaScript这门语言最重要的部分之一 ,理解原型以及原型机制对于学习这门语言来说事半功倍。这篇博客帮助你理解。

构造函数与实例

    Person.prototype.lastName = 'chen';
    function Person(){
        firstName = 'Joe';
    }
    var person = new Person();
    console.log(person.lastName); 
    //output:'chen';   

 prototype

在JS中,每个函数上面都会有一个属性 "prototype" ,它指向了一个名为原型对象的对象,这个对象为由函数创建的实例提供了一个原型模板,也就是说这个对象是实例的 原型,实例会继承原型对象的属性和方法,原型对象包含两个属性,一个是 "consturctor", 指向这个函数,是函数默认取得的属性,至于为什么要指向这个函数,下文有提到,其他的属性都是继承自Object。

consturctor

prototype上面的属性"constructor" 指向函数本身,但是它的作用其实是为实例指明自己的构造函数是谁(个人认为),当实例访问属性contructor时,其实实例是没有这个属性的,找不到就会去实例原型里也就是prototype指向的对象里找,而这个原型对象里的contructor指向的是构造函数,在原型链中constructor属性不一定真能代表构造函数,这一点要注意。

    console.log(Person.prototype.constructor==Person);
    //true

    console.log(person.constructor==Person)
    //true

__proto__

当用new运算符来调用构造函数构造出一个实例后,实例会有一个属性__proto__它指向了构造函数的原型对象,《JavaScript高级程序设计》里面有这样一段话描写这个属性

        ECMA-262第五版中管这个指针叫[[ Prototype ]],虽然在脚本中没有标准的方式访问[[ Prototype ]],但Firefox,Safari,Chrome           在每一个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本则是完全不可见的。

意思是JS中每个对象都会有一个__proto__属性,但是在不同的浏览器上面存在不同的实现方式,貌似最新版本的IE11也实现了对它的访问,

    console.log(Person.prototype.__proto__ == Object.prototype)
    //output:true

原型链

我们说到prototype是一个对象,那么它会不会也有一个__proto__属性,指向它的构造函数的原型对象呢?答案是肯定的。它指向的是Object的原型对象Object.prototype,而Object.prototype__proto__指向的是 null ,这就是person的原型链的尽头。

    console.log(Object.prototype.__proto__== null);
    //output:true

值得注意的是在上面的例子中函数Person也是有一个__proto__属性的,因为函数本质上也是一个对象,它指向的是Function.prototype。Person.__proto__要和Person.prototype.__proto__区分开,前者指向的函数的原型,后者指向的是函数原型的原型。

Object上面也有__proto__属性,它指向的是Function.prototype。最难以理解的地方来咯,下图为Function和Object之间的关系,三条红色虚线最难以理解,下面我阐述一下我个人的理解,仅代表我个人观点,因为我是一个初学者。。。。 

第一条红色的虚线标识Functionprototype__proto__指向同一个地方,这样做,我认为是因为Function已经是顶级的构造器的,顶级的构造器哪里需要什么参考原型。

    console.log(Function.prototype == Function.__proto__);
    //output:true

第二条红色虚线标识Function.prototype.proto指向Object.prototype,这样做,是要符合所有对象的原型都是Object.prototype的原则,从名字上来看也可以知道"Object.prototype"应该是所有对象的祖先,也包括Function.prototype这个对象。

   
    console.log(Function.prototype.__proto__ == Object.prototype)
    //output:true

第三条红色虚线也是讲的这个道理,Object.prototype是所有对象的祖先,它是不需要有原型的,所有对象都会继承Object.prototype的属性和方法。

     console.log(Object.prototype.__proto__);
    //output:null

hasOwnProperty()和"in"

对象会从原型链上继承属性,判断属性是存在与实例上,还是原型链上,用hasOwnProperty()方法。'in'运算符则会判断属性是否可以访问,无论是在实例上还是在原型链上,

    console.log(person.hasOwnProperty("firstName"));
    //true
    console.log(person.hasOwnProperty("lastName"));
    //false

    console.log("firstName" in person);
    //true
    console.log("lastName" in person);
    //true

参考,掘金冴羽大佬的深入JS系列,红宝书,知乎藕粉海大佬的深入原型。

//欢迎在评论区留言讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值