浅谈JS原型和原型链、prototype、__proto__

原型和原型链

在说明原型和原型链之前先来看看这么一串代码:

Function.prototype.a = 'aaa'
Object.prototype.b = 'bbb'
function Fn() {}
Fn.prototype.c = 'ccc' 

var fn = new Fn()
fn.__proto__.d = 'ddd'
fn.e = 'eee'

console.log(fn); // fn {}
console.log(fn.a); // undefined
console.log(fn.b); // bbb
console.log(fn.c); // ccc
console.log(fn.d); // ddd
console.log(fn.e); // eee

打印出来如下在这里插入图片描述

  除了fn.e和想的一样,其它的都是云里雾里的。

原型

  这里就涉及到原型了,原型分为显示原型 prototype 和隐式原型__proto__。

prototype和__proto__

  显示原型prototype是在你定义函数的时候就会帮你自动生成一个prototype,默认为空对象;隐式原型是你在创建一个对象的时候会帮你添加一个__proto__,默认为构造函数的prototype属性;

来看一下下面这段代码吧:

var arr = []
var obj = {}
function Fn() {}

var fn = new Fn()

console.log(arr.__proto__ === Array.prototype); // true
console.log(obj.__proto__ === Object.prototype); // true
console.log(Fn.__proto__ === Function.prototype); // true
console.log(fn.__proto__ === Fn.prototype); // true

大伙们可以自己去试一试
在这里插入图片描述
  以var fn 为例,JavaScript一切皆对象,所以在fn被创建的时候就会添加一个__proto__,指向构造函数的prototype也就是Fn,而Fn在你定义它的时候就添加了prototype,所以fn.__ proto __ === Fn.prototype其它的也是同理。

要点:实例对象的隐式原型(__ proto __) === 构造函数的显示原型(prototype)

原型链

  刚刚上面的例子其实涉及到原型链,我们以最开始这个为例子把

Function.prototype.a = 'aaa'
Object.prototype.b = 'bbb'
function Fn() {}
Fn.prototype.c = 'ccc' 

var fn = new Fn()
fn.__proto__.d = 'ddd'
fn.e = 'eee'

console.log(fn); // fn {}
console.log(fn.a); // undefined
console.log(fn.b); // bbb
console.log(fn.c); // ccc
console.log(fn.d); // ddd
console.log(fn.e); // ddd

这里是fn的心路历程:

  首先fn会现在自身寻找,看看有没有a、b、c、d,发现自己只有e,然后它会尝试从原型上去寻找,fn的原型只有__proto__,因为他不是构造函数只是个实例对象,所以就会在fn.__proto__里面寻找有没有,根据刚刚说原型的要点 可以找到 d 和 c ,到这里都OK。

  这时候重点来了,b要怎么找呢?这时候就要岔开话题了,来看下面这个代码

function Fn() {}
var fn = new Fn()
console.log(Fn.prototype) 
// {
//    c: "ccc",
//    d: "ddd",
//    constructor: ƒ Fn(), 
//    __proto__: Object  <---------------这里也有个
//}
console.log(fn.__proto__ === Fn.prototype); // true
console.log(Fn.prototype.__proto__ === Object.prototype); // true

  看了一下里面好像有个__proto__,诶?为什么呢?记得JavaScript是面向什么编程的吗?面向对象的!!所以这个prototype也是有隐式原型的,指向的是Object的显示原型。

  这里大家可能会有疑惑,所以各位可以去试着写一个这样的代码:

var obj = {
  a: {}
}

console.log(obj.a.__proto__ === Object.prototype); // true

  把obj.a当做prototype是不是就很好理解了?

  所以它是这样找到b的。

  那问题又来了。那港道理,凭啥fn.a没有?欺负人呗!

  那么根据刚刚一切皆对象的理论,可以得知这个Fn函数也是个对象,那么它应该也是有隐式原型的,那它应该有对应的构造函数,就是Function了,那么理论没错的话应该可以得到Fn.__ proto __ === Function.prototypetrue。那么来试一试把。

Function.prototype.a = 'aaa'
function Fn() {}
console.log(Fn.__proto__ === Function.prototype); // true
console.log(Fn.__proto__.a === Function.prototype.a); // true

  和刚刚猜想的结论是一致的!那么为什么fn.a会没有呢?这是因为每条原型链都是一路到底的,不能漂移到其它原型链上。

  所以他们两的查询路线分别是这样的一条链;

fn.proto === Fn.prototype——》 Fn.prototype.__ proto __ === Object.prototype——》 Object.prototype.__ proto __

Fn.__ proto __ === Function.prototype—》Function.prototype.__ proto __ === Object.prototype—》 Object.prototype.__ proto __
  所以fn.a是找不到的原因就是这样。

xx.prototype.constructor与xx

  差点忘了,这一块和构造函数有关系的constructor,


function Fn() {}

var fn = new Fn()

console.log(Function === Function.prototype.constructor); // true
console.log(Object === Object.prototype.constructor);  // true
console.log(Fn === Fn.prototype.constructor);  // true

  简单理解就是,prototype有个属性constructor的值是xx本身。

  最后我把自己画的关系图放上来

原型链

原型链.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值