关于js的原型链,__proto__,prototype的理解

首先声明参考博文,感谢

http://blog.sina.com.cn/s/blog_6c62f4330102wq0u.html

http://blog.csdn.net/leadn/article/details/51781539

等作者,还有一些其他链接这里就不粘贴了

js中关于prototype的文章不少,今天自己写一点自己的理解

不喜欢上来就粘概念,因为如果概念能够理解,也不需要写这篇文章了。

关于原型链里面的东西,主要就是prototype,__proto__这两个属性难以理解,今天我们就来看一下怎么玩耍这两个属性

先上代码

:先用js自定义一个对象,同时创建这个对象

  function Man(){   // 定义一个对象

  }
  var m = new Man() ; //创建一个对象

ok,到此我们的原材料就准备好了

接下来,不就是两个属性么,我们都来测试一下就好了

代码要是拼接字符串打印的效果不好,所以直接打印

console.log(m.__proto__)   //对象的__proto__属性console.log(m.prototype)   //对象的prototype属性console.log("========================")console.log(Man.__proto__) //函数的__proto__属性console.log(Man.prototype) //函数的prototype属性

 结果

我们就直接直观的看结果就好了

  1.明显的m.prototype打印为undefined

  2.m.__proto__和Man.prototype打印的结果是一样的,可以自己手动证明(m.__proto__ == Man.prototype 返回 true)

  3.还有一个Man.__proto__打印的东西好奇怪 function() ,无所谓,暂时不管他

这个时候该上概念了

   prototype是构造函数的属性,指的就是构造函数的原型,在生成实例的时候,js会根据构造函数的prototype属性将该属性下的对象生成为父类,只有构造函数这个属性才有这种效果哦~如果一个构造函数没有指定该属性,那么该属性下的__proto__会默认的指向原生Object的原型对象,该属性会变成一个对象,其中constructor属性指向本身。(这句直接粘来的,暂时看不懂就看我标红就行)

__proto__是对象具有属性,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。

  开始解释

    1.为什么m.prototype打印为undefined?

      废话,prototype是构造函数的属性,m是个对象,自然没有这个属性了,所以打印undefined

    2.m.__proto__和Man.prototype打印的结果是一样的

      他俩其实说的就是一个对象,看上面的蓝字,都是指向原型,我这里用的同一个对象,自然相等啊

    3.不解释,等着

那么这两个东西怎么用呢?

  你再看概念,prototype是构造函数的属性,__proto__是对象具有属性

  其实,只要区分清楚函数和对象,就能调用对应的属性,达到你想要的结果

  

  别跟我说函数是对象,容易混淆,函数就是函数

  到此,你只要能够知道的这么两点就行了

    1.只有函数可以调用prototype属性

    2.对象可以调用__proto__,但是不能调用prototype属性

  接下来说原型链

     其实,你只要理解了上面的两点,原型链就简单多了

   开始

     先回顾上面概念:看上面绿字(在生成实例的时候,js会根据构造函数的prototype属性将该属性下的对象生成为父类),简单讲,就是函数的prototype属性指向了他爸爸。

  
  再来看prototype的字面意思:原型,啥意思呢,就是说对象在创建之初,是根据原型的样子来创造的(就像女娲造人,照着自己的样子造,也可以理解为照着图纸造大楼),也就是说原型是谁,他就象谁。

  那么,上面的Man.prototype怎么指向了自己的函数对象呢?      没有指定过prototype的函数就像孤儿一样,没有爸爸,怎么办呢,自己就是自己的爸爸(自己照顾自己呗),既然不能长得像别人,那就像自己好了

  原型链,要想链起来肯定得有多个对象啊,(其实所有的对象都来自Object,这里怕引起误会,就不用Object了)  我们再声明一个对象People
    function People(){
        this.name = "Bullet";
    }

      然后让people成为Man的爸爸(这里就是实现js的继承,这种继承代码不够健壮,可以自己百度其他的继承方式,但这也算一种继承方式)

      很简单,不是说函数的prototype属性指向了他爸爸么,那么我就

  

   Man.prototype = new People(); //这里也只能用Man.prototype,因为对象是没有prototype属性的,这里后面要用new 是因为prototype指向的是一个对象哦

    这样,构造Man的时候就不照着Man构造了,而是照着People构造,既然照着People构造,People有的Man也得有啊。这样就实现了继承

    

  (测试继承的代码)

        function People(){
            this.name = "Bullet";
        }

        function Man(){

        }
        Man.prototype = new People(); //让Man认People做爸爸
        var m = new Man();
        console.log(m.name);          //这里就能继承父类的name属性了,会打印Bullet

  

    那么,有了继承,如果子类的属性没有自定义的话,就会使用父类的属性,(就像这里可以读到父类的name属性一样)合情合理啊,但是Man到底怎么找到People的name属性的呢

    这就要循着原型链寻找了

    我们这里要找m的name属性,m本身是没有name的,怎么办?找他爸爸要啊,可他爸爸怎么找呢?我们只设定了Man.prototype = new People();,但是我m是个对象,有没有prototype属性,怎么办呢?

    还能怎么办?,我是个对象,我虽然没有prototype但是我有__proto__属性啊

    m.__proto__ == Man.prototype

    反之亦然啊

    Man.prototype = 爸爸对象    m.__proto__ == Man.prototype    m.__proto__ = 爸爸对象

    恭喜m对象顺利找到爸爸!!!这样就可以用爸爸的属性了呦

    结论

      所以子类找父类就像这样

      首先我们根据prototype 来实现继承,但是子类找父类时却要通过__proto__属性。

      没办法子类没有prototype啊,你能拿我怎么样?

      子对象.__proto__,这样就找到了父类,

      原来__proto__属性就是对象用来找爸爸的属性啊!!!

    

      

      接着,找到的父类是个对象啊,就能继续__proto__找到爷爷,一致这么找下去

      所以  对象.__proto__.__proto__.__proto__.__proto__....是能一直点到尽头的(null)

      这个.__proto__.__proto__.__proto__.__proto__....组成的就是一条原型链

      

      这时,有人会有疑问

        函数.prototype.prototype...可以一直点么

      肯定不行啊,都说了 函数.prototype 获取(或设置)的是个对象,对象没有prototype属性,所以点到第二层就已经挂掉了(undefined)

      

      console.log(Man.prototype.prototype);  // 这里一定为undefined  Man.prototype指向的是一个对象,对象没有prototype属性

      这也又一次解释了问题一

        1.为什么m.prototype打印为undefined?

            废话,prototype是构造函数的属性,m是个对象,自然没有这个属性了,所以打印undefined

      两者可以结合,我们可以

      函数.prototype.__proto__.__proto__.__proto__....是能一直点到尽头的,最后为null

 最后,我们解释最后一个问题

    3.为什么Man.__proto__打印的东西好奇怪 ,是一个function()

      首先他不是undifined,说明函数是有__proto__这个属性 ,怎么强行解释一波呢?

      很简单,我先道个歉,对不起,因为函数他确实是个对象,刚才让你区分是为了好解释,现在你再想起来吧(因为万物皆对象,函数当然也是对象)

      所以Man这个函数是可以使用__proto__属性的

     

    上面又说了__proto__相当于找爸爸的属性,

    我们使用Man.__proto__返回function() 说明function()是这个函数的爸爸,我们还能再继续.__proto__,能够找到Object,说明fanction也是Object的一个子类

        console.log(Man.__proto__);           //找到爸爸function()
        console.log(Man.__proto__.__proto__); //找到爷爷Object{}

    解释一:

      这里为什么不是找到People,原因是因为这里是一个Man函数对象,函数是通过function()来构造的,上面的继承关系是对对象(就是m)来讲的,

      所以Man函数的爸爸是function,而new Man()对象的爸爸是People,不要混淆对象和函数的区别就好(虽然我知道函数也是个对象)

    解释二:

      网上经常可以看到这张好乱的对象关系

      

  你慢慢看原图,我再给你画一个(虽然很丑)

  

  

      使用Object这个超类来找父类的时候会返回null(传说中的无中生有),可以自行百度,上面参考链接中有提到返回null的原因

      

    最后总结

    对象找爸爸用__proto__属性来找,这个大家都有,万物皆对象

    函数因为可以构造,所以可以使用prototype来找他是根据谁构造出来的,但是只能找一层,因为函数是根据对象构造出来的,继续找就只能用__proto__了

    所以,        一个对象.__proto__ == 这个对象的函数.prototype

    翻译成人话就是                        对象他爸  == 构造这个对象的对象

    记住只要分清对象和函数两个东西,使用__proto__和prototype就不会再有难度了

    头一次写博客,大家可以随意喷啊,促进进步,哈哈哈

原文地址:https://www.cnblogs.com/fast-bullet/p/8146365.html

时间: 2024-07-30 17:20:12

关于js的原型链,__proto__,prototype的理解的相关文章

原型prototype、原型链__proto__、构造器constructor

创建函数时,会有原型prototype,有原型链__proto__,有constructor.(构造函数除外,没有原型) . prototype原型:是对象的一个属性(也是对象),使你有能力向对象添加属性和方法. __proto__原型链:指向创建它的函数对象的原型对象prototype. constructor构造器:返回创建此对象的函数. 创建一个函数 这个函数的constructor返回的是js底层的函数Function,它的原型链__proto__是function.__proto__是

前端基本知识(二):JS的原型链的理解

之前一直对于前端的基本知识不是了解很详细,基本功不扎实,但是前端开发中的基本知识才是以后职业发展的根基,虽然自己总是以一种实践是检验真理的唯一标准,写代码实践项目才是唯一,但是经常遇到知道怎么去解决这个问题,但是不知道使用的是什么一种方法,方法的原理是什么,现在觉得大学里学习的基本知识还是很重要的,一定有自己的理解才能走的更远. 无论以后自己的学习新的技术,但是万变不离其宗,基本扎实,学习效率高. 废话这么多,开始了今天理解的四部分部分. 一.JS的原型链理解方式 二.原型理解 三.规则 四.j

怎么理解js的原型链继承?

前言 了解java等面向对象语言的童鞋应该知道.面向对象的三大特性就是:封装,继承,多态. 今天,我们就来聊一聊继承.但是,注意,我们现在说的是js的继承. 在js的es6语法出来之前,我们想实现js的继承关系,需要借助于原型链.之前的文章,我有讲过原型和原型链的概念.在这,再重新回顾一下. js中万物皆对象,每个对象都有一个隐式原型 __proto__ ,指向创建它的构造函数的原型对象. 函数(构造函数)除了有一个隐式原型对象,还有一个属性prototype,它指向一个对象,这个对象就是原型对

理解js中的原型链,prototype与__proto__的关系

说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: 1 <script type="text/javascript"> 2 var Person = function () { }; 3 var p = new Person(); 4 </script> 很简单的一段代码,我们来看看这个new究竟做了什么?我们可以把new的过程拆分成以下三步: <1> var p={}; 也就是说,初始化一个对象p. <2>

关于JS中原型链中的prototype与_proto_的个人理解与详细总结(代码示例+高清无码大图!——自备瓜子花生)

一直认为原型链太过复杂,尤其看过某图后被绕晕了一整子,今天清理硬盘空间(渣电脑),偶然又看到这图,勾起了点回忆,于是索性复习一下原型链相关的内容,表达能力欠缺逻辑混乱别见怪(为了防止新人__(此处指我)__被在此绕晕,图片就放在末尾了.) 以下三点需要谨记 1.每个对象都具有一个名为__proto__的属性: 2.每个构造函数(构造函数标准为大写开头,如Function(),Object()等等JS中自带的构造函数,以及自己创建的)都具有一个名为prototype的方法(注意:既然是方法,那么就

对js原型链及继承的理解:__proto__&amp;prototpye

首先我们来理解一下原型链的概念: 要理解原型链必须知道构造函数.原型和实例的关系: 每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针(即prototype),而实例则包含一个指向原型对象的内部指针(即__proto__). var father = function() { this.relation = "father"; } father.prototype.money = function() { this.money = 100000; } var father

js最好的继承机制:用对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。

js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法. function ClassA(sColor) { this.color = sColor; } ClassA.prototype.sayColor = function () { alert(this.color); }; function ClassB(sColor, sName) {//在 ClassB 构造函数中,用对象冒充继承 ClassA 类的 sColor 属性 ClassA.call(th

js的原型链

开篇 之前对js中的原型链和原型对象有所了解,每当别人问我什么是原型链和原型对象时,我总是用很官方(其实自己不懂)的解释去描述.有一句话说的好:如果你不能把一个很复杂的东西用最简单的话语描述出来,那就说明你没有真正的理解.最近正在读<Javascript高级程序设计>,书中对原型对象和原型链的描述让我受益匪浅,下面仅用一个对比性的例子来说明. 我们经常会这么写 function Person () { this.name = 'John'; } var person = new Person(

js之原型链的理解

在js中,原型也是一个普通的对象,通过原型我们能够实现对象的属性继承. 首先,我们要明确引用类型有Array.Object.Function,这些引用类型都是能够自由的扩展属性. 1 var obj = {}; 2 obj.a = 10; 3 obj.b = 20; 4 5 obj; // Object {a: 10, b: 20} 我们上面说的这几个引用类型都有一个属性__proto__,这是一个普通的对象.而这个__proto__属性是指向它的构造函数的prototype属性.我们可以在代码