资讯专栏INFORMATION COLUMN

理解JavaScript的prototype和__proto__

tanglijun / 3148人阅读

摘要:这篇文章的的目的试图通过最简单的表述让大家理解和先把最重要的几点列出来大家可以带着这几个核心要点阅读下面的文章是用来在原型链上查找你需要的方法的实际对象所有的对象都有这个属性这个属性被引擎用作继承使用根据的规范这个属性应该是一个内在的属性但

这篇文章的的目的试图通过最简单的表述,让大家理解prototype__proto__

先把最重要的几点列出来,大家可以带着这几个核心要点阅读下面的文章.

__proto__是用来在原型链上查找你需要的方法的实际对象,所有的对象都有这个属性.这个属性被JavaScript引擎用作继承使用.
根据ECMA的规范,这个属性应该是一个内在的属性,但是大多数的浏览器厂商都允许我们去访问和修改它.

prototype是函数独有的属性.当我们使用关键词new并且将函数作为构造函数来构造对象的时候,
它被用来构建对象的__proto__属性.

__proto__属性和prototype属性都是一个对象代码演示.

(new A()).__proto__ === A.prototype的结果为true,(new A()).prototype === undefined的结果也为true,其中A表示一个函数(也就是构造函数).

接下来我们来使用一些代码来解释上面所说的那些要点:代码演示

    // 这是一个普通函数,我们把它用来当做构造函数,也当做一个[父类]
    function Car(name) {
        this.name = name;
    }
    Car.prototype.introduce = function() {
      console.log("[From Car.prototype.introduce] " + "Hello, my name is: " + this.name);
    };
    
    var car = new Car("porsche");
    console.log(car.name); // porsche
    car.introduce(); // [From Car.prototype.introduce] Hello, my name is: porsche
    
    
    // 我们开始构建另外一个函数,我们把这个函数当做一个[子类],暂时这么说.
    function MiniCar(name, color) {
        this.name = name;
        this.color = color;
    
        this.getColor = function() {
            console.log("My color is: " + this.color);
        }
    }
    MiniCar.prototype = new Car();
    
    var miniCar = new MiniCar("benz", "black");
    console.log("
");
    console.log("name: " + miniCar.name + ";color: " + miniCar.color); // name: benz;color: black
    miniCar.introduce(); // [From Car.prototype.introduce] Hello, my name is: benz
    miniCar.getColor(); // My color is: black
    
    // 如果使用A表示一个构造函数,那么 (new A()).__proto__ === A.prototype
    console.log((new MiniCar()).__proto__ === MiniCar.prototype); // true
    
    // 如果使用a表示A的一个示例的话,那么 a.__proto__ === A.prototype
    console.log(miniCar.__proto__ === MiniCar.prototype); // true
    
    // 一个对象是没有prototype属性的
    console.log(miniCar.prototype === undefined); // true

如果你练习了上面的代码,对这两个属性的理解应该会有一定的帮助,也许你已经理解了;如果没有太懂的话,那也没关系;我们下面来好好的说一说上面的代码(开始长篇大论了).
首先,在JavaScript中是没有这个概念的,如果你学过Java或者C++的话,应该知道,要是想创建一个对象,必须先有一个;但是JavaScript中没有,那怎么办?模仿喽,所以JavaScript创造了__proto__这个属性用来连接子类父类.创造了prototype属性去用来在构建子类时候构建__proto__这个属性.

这里先暂停上面的线程,我们来说说prototype这个属性,这个属性是只属于Function函数的,那么这个属性的作用是什么呢?这个属性的作用是为了让使用Function作为构造函数new出来的对象实例都能够共享一些函数.

   function Car(name) {
           this.name = name;
       }
   Car.prototype.introduce = function() {
     console.log("[From Car.prototype.introduce] " + "Hello, my name is: " + this.name);
   };

上面的代码中,只要是使用Car这个构造函数new出来的对象都具有方法introduce.

继续上面的线程,我们按照代码的执行顺序来说明这件事情:

首先我们定义了两个函数CarMiniCar,如下图所示:

然后我们给Car的原型上添加了一个方法introduce,如下图所示:

接下来var car = new Car("porsche")这一行代码可不像它看起来那样,它内部的实现还是有许多值得玩味的;首先,函数Car创建了一个新的对象(a),这个对象有一个隐藏的属性__proto__,这个属性和Car的原型都指向同一个对象.然后Car函数内部的this指向哪个新创建的对象(a).如下图所示:

然后我们给这个对象添加了一个属性name,并且为其赋值.还要注意的一点是,我们这个Car函数是有返回值的,虽然没有使用return关键字把这个值显式的返回,这个返回值是一个引用,然后变量car就可以用来操作那个对象了(a).

然后上面的语句运行完之后,场面上是下图这个样子:

接下来我们输出了这个对象的名字,然后调用了这个对象(的构造函数的原型上的)的introduce方法.输出的结果如下图:

然后我们有定义了一个函数MiniCar,我们把它当做Car(父类)的一个子类;我使用代码MiniCar.prototype = new Car()来实现这个功能,这段代码更值得好好分析一下.
首先如上图所示,MiniCar这个函数的prototype是函数Car使用new关键字创建的一个对象(b),所以MiniCar的实例具有这个对象(b)能够使用的任何属性和方法.

让我们更进一步吧,这一步我们开始运行var miniCar = new MiniCar("benz", "black")这段代码,首先我们先要运行函数MiniCar函数,所以通过new操作,我们新创建了一个对象(c),我们首先给这个对象添加了了两个属性,分别是namecolor,然后分别赋值benzblack,其实我们可以只添加一个属性,因为name属性在Car上是已经存在的.我们还给它添加了一个getColor方法,它的__proto__属性指向MiniCar.prototype, 而MiniCar.prototype是一个对象,这个对象也有一个__proto__属性,这个属性指向Car.prototype,如此一来这个伪继承就实现了.然后我们将这个对象(c)的索引赋值给miniCar,所以通过miniCar可以操作对象(c).

然后接下来的一切应该都顺理成章了.

原文的地址github

参考的文章或者问答:

How does proto differ from constructor.prototype?

proto VS. prototype in JavaScript

Inheritance and the prototype chain

JavaScript difference between proto and prototype

Understanding "Prototypes" in JavaScript

JavaScript Prototype in Plain Language

Object.prototype.__proto__

Function.prototype

js中__proto__和prototype的区别和关系?

prototype与__proto__的联系与区别

简单粗暴地理解js原型链--js面向对象编程

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

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

相关文章

  • 深入理解JavaScript原型与继承

    摘要:深入理解原型与继承看过不少书籍,不少文章,对于原型与继承的说明基本上让人不明觉厉,特别是对于习惯了面向对象编程的人来说更难理解,这里我就给大家说说我的理解。 深入理解:JavaScript原型与继承 看过不少书籍,不少文章,对于原型与继承的说明基本上让人不明觉厉,特别是对于习惯了面向对象编程的人来说更难理解,这里我就给大家说说我的理解。 首先JavaScript是一门基于原型编程的语言...

    mengbo 评论0 收藏0
  • 独家解析Javascript原型继承

    摘要:面向对象实现代码动物发声汪汪喵喵调用代码动物发声喵喵动物发声汪汪当要增加一种动物时,只需增加一个继承,不会影响其他已有的动物逻辑。所以的继承和的原型继承,可谓殊途同归。 传统面向对象的继承和多态 我们知道C++/Java/C#等面向对象语言,都原生地支持类的继承。继承的核心作用大抵是创建一个派生类,并使其复用基本类(即父类)的字段和/或方法。并且派生类可以重写基本类的方法。这样基本类和...

    verano 评论0 收藏0
  • JavaScript 原型中哲学思想

    摘要:而作为构造函数,需要有个属性用来作为以该构造函数创造的实例的继承。 欢迎来我的博客阅读:「JavaScript 原型中的哲学思想」 记得当年初试前端的时候,学习JavaScript过程中,原型问题一直让我疑惑许久,那时候捧着那本著名的红皮书,看到有关原型的讲解时,总是心存疑虑。 当在JavaScript世界中走过不少旅程之后,再次萌发起研究这部分知识的欲望,翻阅了不少书籍和资料,才搞懂...

    sugarmo 评论0 收藏0
  • 讲清楚之 javascript原形

    摘要:构造函数和实例都通过属性指向了原形。代码示例是构造函数的实例的属性与的属性保存的值相等,即他们指向同一个对象原形。 讲清楚之javascript原型 标签: javascript javascript 中原形是一个比较难于理解的概念。javascript 权威指南在原形这一章也花了大量的篇幅进行介绍,也许你已经读过javascript 权威指南,或者已经是读第N篇了,然而这篇文章的目...

    高胜山 评论0 收藏0

发表评论

0条评论

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