原型链中的 protorype __proto__

Foo = function(){};
Object.prototype.a = function(){console.log(1)};
Function.prototype.b = function(){console.log(2)};
var f = new Foo();

f.a() // 1
f.b() // throw error

上面的结果很令人费解,但如果了解javascript整个原型链的关系设计后答案就一目了然了。

在看上面的图之前我们要理解几个知识点:

  1. new运算符 (创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例)

    调用new运算符内部会做下面的事:

    1. 创建空对象;
      var obj = {};

    2. 使 obj的内部属性 [[prototype]] 指向构造函数的原型对象prototype, chrome、firefox中可以通过 __proto__ 获取到,老版ie没有 __proto__ 这个属性
      obj.__proto__ = ClassA.prototype;

    3. 使构造函数中的this被指向新实例对象obj,调用构造函数:
      ClassA.call(obj);  //{}.构造函数();          

    4. 构造函数的返回值如果不是引用类型的值,返回 obj,否则返回正常的返回值

 

  2. 原型对象

    只要创建一个新函数,会根据特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。上面的Foo函数就是新创建的函数,Foo函数有一个prototype属性指向原型对象。而这里的原型对象是通过Object构造函数 通过new创建的Object实例 (其实就是 {} )。Foo函数其实也是通过构造函数Function通过new创建的实例,所以Foo函数会有一个内置属性__proto__ 指向构造函数Function的原型对象prototype。

 

  3.原型链(实现继承的主要方法)

    每一个构造函数都会有个原型对象prototype,原型对象会有个curstructor指向这个构造函数,通过new创建的实例都会有个内部属性([[prototype]] 通过__proto__获取)指向构造函数的原型对象prototype。

      __proto__  -> prototype

    如果原型对象是另外一个类型的实例,那么这个原型对象中也会有个([[prototype]] 通过__proto__获取)指向构造函数的原型对象prototype,这样层层递进就构成了实例与原型的链条,也就是原型链。

      __proto__  -> prototype (__proto__) -> prototype

 

  上面题目中的 f函数 就好比是 图中的 new Foo() ,调用f.a()会先查找自己的属性中是否有a方法,如果没有的会通过原型链查找原型链上是否有a方法。f自身没有a方法,通过内部属性([[prototype]] 通过__proto__获取)找到了Foo构造函数的原型对象prototype,这个原型对象是构造函数Object的实列,所以Foo的原型对象中没有a方,再通过__proto__找到了Object的原型对象,最终找到了a方法。

 

console.log(Function.__proto__ === Function.prototype)  //true
console.log(Object.__proto__ === Function.prototype)    //true
console.log(String.__proto__ === Function.prototype)    //true
console.log(Array.__proto__ === Function.prototype)        //true

console.log(Function.prototype.__proto__ === Object.prototype) //true console.log(String.prototype.__proto__ === Object.prototype) //true console.log(Array.prototype.__proto__ === Object.prototype) //true

 

内置函数的prototype和__proto__

   Function,Object,Attay,String,Boolean 是系统的内置函数。每个内置函数都会有一个内置的原型对象prototype, 每个原型对象都会有内置属性([[prototype]] 通过__proto__获取)。我们平时调用的方法像: 数组的 push,pop,unshift,shift 字符串的 substring,split 都是原型对象中的方法。这里有2个比较特别的内置原型对象 Function.prototype 和 Object.prototype。

 Object.prototype  

  所有构造函数的内置属性[[prototype]] 都指向Object.prototype, 除了Objec其他t所有内置函数的原型对象prototype的内置属性[[prototype]] 也都指Object.prototype,Object构造函数的内置属性[[prototype]]为 null。

  (虽然是内置对象但是在原型链上就和通过new Foo构造的实例自带的原型对象是通过new Object获取的实例一样 内置属性[[prototype]]都指向Object.prototype原型对象)

 Function.prototype

  Function.prototype原型对象其实是个函数对象,可以像调用函数那样调用,返回值都为undefined。所有的内置函数的内置属性[[prototype]]都指向 Function.prototype原型对象。

  (内置函数的内置属性[[prototype]]也和通过new Function构造的实例一样 内置属性[[prototype]]都指向 Function.prototype原型对象)

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/angleBrackets/p/9334751.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值