资讯专栏INFORMATION COLUMN

关于javascript中的原型和原型链

SmallBoyO / 2684人阅读

摘要:先来一个构造函数构造一个人类实例化一个对象看看的名字是什么打印结果先说一个前提只要是函数,就会有一个属性,可以理解为子代的原型遗传基因只要是对象,就会有一个方法,可以理解为向上寻找原型的方法。

关于javascript中的原型和原型链
我GitHub上的菜鸟仓库地址: 点击跳转查看其他相关文章
文章在我的博客上的地址: 点击跳转

        关于javascript中的原型和原型链,可能都会想到一个词“prototype”,而实际里面藏的是什么东西,才是大家应该要掌握的。

        看过一些文章,将原型和原型链说得很枯燥难懂,其实抽丝剥茧之后,理顺思路,其实原型和原型链没有想象中的那么难以理解。我一直崇尚的是类比生活去理解,所以个人还是不太喜欢纯叙述性的解释。

        其实很多讲解的人,都是从自身角度出发的,解释的都是理所当然的,他们无法感受我们这些菜鸟的角度,不知道我们很多个为什么。当然,当我们了解理解之后,再重新看他们的文章,说的也是头头是道的。

        关于原型这个词,其实很好理解,可以说成是“原来的模型”。比如说,“儿子长得就像是爸爸一个模子出来一样”,那爸爸就是儿子的原型,儿子继承了爸爸的一些特征,当然,儿子也会有自己的特征,这些特征,就是属性。而有时候儿子有些特征没有,可以在儿子的爸爸那里找到,甚至儿子爸爸那里找不到的特征,可以在爸爸的爸爸那里找到,而彼此之间维系着的,就是血缘关系,DNA传递,而这个关系链,就是我们说的原型链,当然,往上找祖先,找到最后肯定是炎帝黄帝了,他们就是人类始祖了,如果他们身上还找不到,再往上找,就是空了,因为往上就没有祖先了,本来无一物,何处惹尘埃。

        好了,开始来代码了。

        先来一个构造函数:

//构造一个人类
function Mankind(name){
    this.name = name;
}

//实例化一个Dad对象
var Dad = new Mankind("BaBa");

//看看Dad的名字是什么
console.log(Dad.name);

//打印结果
BaBa

        先说一个前提:

        只要是函数,就会有一个 prototype 属性,可以理解为子代的原型(遗传基因);只要是对象,就会有一个__proto__方法,可以理解为向上寻找原型的方法。

        所以上面的构造函数中,Mankind这个构造函数,就会有一个prototype属性(不是函数没有),可以这样访问:Mankind.prototype,当然也可以给传统基因添加其他特征:

//还是上面的构造函数
function Mankind(name){
    this.name = name;
}

//还是实例化一个Dad对象
var Dad = new Mankind("BaBa");

//然后给构造函数添加特征
Mankind.prototype.sayHello = "HaHaHa";

//看看Dad有没有sayHello特征
console.log(Dad.sayHello);

//打印结果
HaHaHa

        从结果可以看出,Dad本来没有的sayHello特征,你给Dad的祖先添加了,Dad也会拥有这个特征了,其实这就是从原型链上找到这个属性了。

        Dad对象这个实例的原型,就是Mankind.prototype这个遗传基因。

        而向上找原型,就是通过__proto__这个方法,所以:

Dad.__proto__ === Mankind.prototype  //true

        当然,Mankind.prototype也是一个对象,当然也有一个__proto__方法,通过这个方法,也是可以找到他再上一级的原型,所以:

Mankind.prototype.__proto__ === Object.prototype //true

        这也是对的。因为函数的祖先是Object,所以就是指向Object.prototype这个原型 。

    当然,再往上找,就是空了。
Object.prototype.__proto__  === null  //true 

        所以各个原型组织起来,就是一条原型链了:

        Dad ---> Mankind.prototype ---> Object.prototype ---> null   可以看到从对象开始的原型链的规律

        回过头来,其实Mankind.prototype这个对象除了__proto__这个方法外,还有一个constructor的方法,因为Mankind是函数,所以有这个方法,所以通过这个方法,可以访问到自身这个函数:

//打印一下Mankind.prototype.constructor
console.log(Mankind.prototype.constructor);

//打印结果
function Mankind(name){
    this.name = name;
}

        说到这里,相信已经类比得很清楚了。然后又会有一个疑问:

        既然说函数是对象(函数对象Function,普通对象Object,Function是继承于Object的),那么前面的构造函数Mankind可以有prototype属性,也应该有__proto__这个方法?

        没错,所以我们也可以有Mankind.__proto__这个方法访问原型:

Mankind.__proto__ === Function.prototype  //true

        当然,Function.prototype 也是可以通过__proto__方法访问原型:

Function.prototype.__proto__ === Object.prototype //true

        所以也有这样的原型链:

        Mankind ---> Function.prototype ---> Object.prototype ---> null   可以看到从函数开始的原型链的规律

        当然了,我们既然有一个实例的对象Dad,当然也可以再延生下去,生一个Son来继承Dad的啦:

//从Dad那里继承,创建一个son对象,下面两种方法都可以:
var Son = new Object(Dad);
var Son = Object.create(Dad);

//修改一下儿子的name
Son.name = "ErZi";

//打印一下儿子的name和原型链上父亲的name
console.log(Son.name);
console.log(Son.__proto__.name);//通过__proto__方法找到父亲Dad

//打印结果
ErZi
BaBa

        所以这条原型链是这样的:

        Son ---> Dad ---> Mankind.prototype ---> Object.prototype ---> null   对照从对象开始的原型链的规律

        通过上面的一大顿啰嗦,相信已经很清楚了,最后再说一下鸡和鸡蛋的问题:

        上面既然说到有Object.prototype,而且prototype是函数才有的,所以可以访问到Object这个构造函数,可以用Object.prototype.constructor这个方法,当然构造函数是继承于函数对象的,所以构造函数原型又是Function.prototype,所以也有这样的一条原型链:

        Object ---> Function.prototype ---> Object.prototype ---> null   对照从函数开始的原型链的规律(这里的Object是构造函数)

        或者表示为:

        Object.prototype.constructor---> Function.prototype ---> Object.prototype ---> null

        这就是鸡和鸡蛋的问题了。

        最最后,放上一张网络上解释很清楚的原型链图,再结合我上面的啰嗦,相信就很清楚容易明白了。
       

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84257.html

相关文章

  • 关于javascript原型原型,看我就够了(一)

    摘要:要用作原型的对象。函数对象可以创建普通对象,这个我们上面讲过了回顾一下这是一个自定义构造函数普通对象没法创建函数对象,凡是通过创建的对象都是函数对象,其他都是普通对象通常通过创建,可以通过来判断。 关于js的原型和原型链,有人觉得这是很头疼的一块知识点,其实不然,它很基础,不信,往下看要了解原型和原型链,我们得先从对象说起 创建对象 创建对象的三种方式: 对象直接量 通过对象直接量创建...

    MoAir 评论0 收藏0
  • 关于javascript原型原型,看我就够了(二)

    摘要:原文链接关于的原型和原型链,看我就够了一参考链接闯关记之原型及原型链之原型与原型链一篇文章带你理解原型和原型链彻底理解原型链一的默认指向图解和的三角关系原型和原型链三张图搞懂的原型对象与原型链 温故 创建对象的三种方式 通过对象直接量 通过new创建对象 通过Object.create() js中对象分为两种 函数对象 普通对象 仔细观察如下代码 function Foo(na...

    eccozhou 评论0 收藏0
  • 关于javascript原型原型,看我就够了(三)

    摘要:对于中的引用类型而言,是保存着它们所有实例方法的真正所在。高级程序设计构造函数陌上寒原型对象有一个属性,指向该原型对象对应的构造函数为什么有属性那是因为是的实例。 温故 我们先回顾一下前两天讨论的内容 创建对象的三种方式 通过对象直接量 通过new创建对象 通过Object.create() js中对象分为两种 函数对象 普通对象 原型对象prototype 每一个函数对象都...

    joyvw 评论0 收藏0
  • 关于JavaScript中访问不带有this修饰的变量的搜索顺序的理解

    摘要:这几天因为对于中的作用域链和原型链有点混淆,当访问一个不带有修饰的变量时,我想知道它的搜索顺序,因为作用域链的链结点也是一个变量对象,那么当在这个变量对象中查找变量时会不会沿着它的原型链查找呢这样就有两种可能先查找作用域链前端的变量对象,然 这几天因为对于JavaScript中的作用域链和原型链有点混淆,当访问一个不带有this修饰的变量时,我想知道它的搜索顺序,因为作用域链的链结点也...

    jeyhan 评论0 收藏0
  • 细说 Javascript 对象篇(二) : 原型对象

    摘要:并没有类继承模型,而是使用原型对象进行原型式继承。我们举例说明原型链查找机制当访问一个对象的属性时,会从对象本身开始往上遍历整个原型链,直到找到对应属性为止。原始类型有以下五种型。此外,试图查找一个不存在属性时将会遍历整个原型链。 Javascript 并没有类继承模型,而是使用原型对象 prototype 进行原型式继承。 尽管人们经常将此看做是 Javascript 的一个缺点,然...

    lansheng228 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<