Array/String/Boolean/Object/Function以及申明函数和对象的__proto__、prototype和constructor属性的指向问题

目录

prototype和__proto__的属性联系和区别

constructor属性

关系图


首先我们知道js中函数也是属于对象的,所以Array、String、Boolean、Function、Object这些系统定义好的函数上也是对象,上面有一些定义好了属性像__proto__、prototype和constructor等。

prototype和__proto__的属性联系和区别

以下说的函数和对象是通过typeof()的结果分开看,且不讨论Object.creat(null)的情况,下面只要是===都是可以完全当数学变量互相替换的,文中A指申明的函数,a指通过A构造出来的对象。

1.对象上是没有prototype的属性的,只有函数上才有,而__proto__属性函数和对象上都有

2.prototype、__proto__的指向都是对象

3.对象上的继承即我们通过查找原对象上不存在的属性时,我们会在该对象的属性__proto__所指向的对象去寻找,并可以依次类推查找这个对象上的下一个__proto__属性指向的对象,并把这样一个链接状态称为原型链。而我们在使用构造函数创建对象时会隐式的将__proto__=prototype。这也是为什么每个对象上为什么会有__proto__属性以及能通过设置构造函数的prototype或设置对象的__proto__属性来继承对象。(如果是设置prototype,我们需要注意顺序,先设置构造函数再利用构造函数创建对象,如果是设置__proto__属性,那就可以直接在对象上设置,设置的内容会在添加在原有的__proto__属性上添加,不会替换。)

4.Array/String/Boolean/Object/Function.prototype各自上都有一些定义好了的方法,属性。我们在新建对象时,会隐式的调用__proto__=prototype,所以能从相对应的函数中继承系统中不同的的方法和属性,注意这些prototype属性是各不相同的。例如var a=String(‘a’)。我们能直接使用a.length查看字符串对象的长度,这个length属性就是在String.prototype上定义好的,使用时能在a.__proto__指向的对象上找到该方法。然后这里我们有一条计算机定义好了的,Array/String/Boolean/Function.prototype.__proto__===Object.prototype(可以理解为大家都是对象,所以都继承制Object.prototype)

5.我们在系统中还有已经定义好的__proto__属性。Array/String/Boolean/Object/Function.__proto__===Function.prototype;Object.prototype.__proto__===null(所以称Object.prototype为原型链的终端)。

6.我们申明的函数的__proto__属性===Function.__proto__(比如function A(){};A.__proto__===Function.__proto__),而prototype属性指向一个对象,这个对象只等于本身,可以修改的,但他的__proto__属性===Object.prototype(即A.prototype.__proto__===Object.prototype),注意A.prototype!==Function.prototype(可以说prototype属性指向的对象除了Function.prototype和Object.prototype其他的都是除了自己谁都不等于)

以上可以总结为3点:

A.所有函数的__proto__属性等于Function.prototype(包括Function本身和申明的函数,相当于都继承至Function.prototype,即A/Array/String/Boolean/Object/Function.__proto__===Function.prototype)。

B.Function/申明函数.prototype.__proto__===Object.prototype。(Object.prototype为原型链的终端,可以得出一个有意思的结论Object.__proto__.__proto__===Object.prototype,像A/Array/String/Boolean/Function都是不等于的,如果只替换左边的Object是等于的)

C.构造函数创建对象时会隐式的将__proto__=prototype(即a.__proto__=A.prototype
举例:

function A(){};
var a = new A();

通过这2句代码,我们就可以得到以下信息:首先通过A我们可以得到:

1.A/Array/String/Boolean/Object.__proto__===Function.__proto__;

(A/Array/String/Boolean.prototype不等于谁咱不考虑。然后注意对象上是没有prototype属性的。)

然后我们根据A+B的条件能推出

2.A.prototype.__proto__===Object.prototype===Array/String/Boolean/Object/Function.__proto__.__proto__

最后在加上C点a.__proto__===A.prototype,那么我们又可以推出

3.a.__proto__.__proto__===Object.prototype===Array/String/Boolean/Object/Function.__proto__.__proto__

这样关于__proto__和prototype属性咱就讲完了,这些大家可以通过代码去验证,都是个人的理解,有什么问题或题目欢迎讨论。

———————————————————————————————————————————————

constructor属性

然后再讲讲constructor属性。它是存储在prototype上的系统隐式定义好的属性。这个比较好理解,它和其他属性的关联不大,咱单独讲,他就是字面意义,谁构造了他,比如Array/String/Boolean/Object/Function这些都是函数,那么他的构造者就是Function,而对象咱看他是由谁构造的。

总结:

函数的constructor属性指向

1.所有函数的constructor属性都指向Function(包括他本身和申明的函数,即A/Array/String/Boolean/Object/Function.constructor===Function)。

2.所有函数的prototype指向的对象的constructor属性都指向本身(A/Array/String/Boolean/Object/Function.prototype.constructor===A/Array/String/Boolean/Object/Function)

然后咱再来看对象的constructor属性指向

3.对象的constructor指向构造对象函数原型的constructor(通过2我们知道未更改原型时指向new的函数),比如通过new Number(‘1’)构造的对象,那么他的constructor便指向Number函数,再比如new String(‘a’),那么他的constructor便指向String(直接通过字面量即={}的创建对象的方式,那么他的constructor指向Object)。而改变原型的,比如下面代码,A的原型指向了new B(),通过3我们知道A.prototype的constructor为B,而obj的构造者为A.prototype的constructor即B。

function A(){};
function B(){};
A.prototype = new B(); //改变A的原型
var obj = new A();

至于__proto__指向对象的constructor,我们可以通过上文中的__proto__和prototype的联系转化成prototype来求他的constructor。比如申明函数A.__proto__.constructor,通过上面第A条A.__proto__===Function.prototype,那么A.__proto__.constructor===Function.prototype.constructor===Function,这些咱都可以完全像数学变量一样代换的。咱还可以推一些好玩的,大家可以自己去验证,比如:

对象a.__proto__===A.prototype,a.__proto__.__proto__===Object.prototype,那么a.__proto__.__proto__.constructor===Object,

然后Array.__proto__===Function.__proto__===Function.prototype,那么Array.__proto__.constructor===Function,

再然后Array.__proto__.__proto__===Object.prototype,那么Array.__proto__.__proto__.constructor===Object,又可以推出Array.__proto__.__proto__.constructor===a.__proto__.__proto__.constructor同理咱还可以得出A/Array/String/Boolean/Object/Function.__proto__.__proto__.constructor===a.__proto__.__proto__.constructor===Object。

这样关于constructor属性咱就讲完了,这些大家可以通过代码去验证,都是个人的理解,有什么问题或题目欢迎讨论。

———————————————————————————————————————————————

关系图

最后我们这里还有一张借用的别人的关系图来方便大家理解:

这里写图片描述

———————————————————————————————————————————————————————————————————————————————————————————

以上都是个人的理解总结,有什么问题或题目欢迎讨论。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值