这篇文章的的目的试图经过最简单的表述,让你们理解
prototype
和__proto__
javascript
先把最重要的几点列出来,你们能够带着这几个核心要点阅读下面的文章.html
__proto__
是用来在原型链上查找你须要的方法的实际对象,全部的对象都有这个属性.这个属性被JavaScript
引擎用做继承使用.
根据ECMA的规范,这个属性应该是一个内在的属性,可是大多数的浏览器厂商都容许咱们去访问和修改它.java
prototype
是函数独有的属性.当咱们使用关键词new
而且将函数做为构造函数来构造对象的时候,
它被用来构建对象的__proto__
属性.python
__proto__
属性和prototype
属性都是一个对象代码演示.git
(new A()).__proto__ === A.prototype
的结果为true
,(new A()).prototype === undefined
的结果也为true
,其中A
表示一个函数(也就是构造函数).github
接下来咱们来使用一些代码来解释上面所说的那些要点:代码演示web
// 这是一个普通函数,咱们把它用来当作构造函数,也当作一个[父类] 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('\n'); 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
.app
继续上面的线程,咱们按照代码的执行顺序来讲明这件事情:
首先咱们定义了两个函数Car
和MiniCar
,以下图所示:
而后咱们给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),咱们首先给这个对象添加了了两个属性,分别是name
和color
,而后分别赋值benz
和black
,其实咱们能够只添加一个属性,由于name
属性在Car
上是已经存在的.咱们还给它添加了一个getColor
方法,它的__proto__
属性指向MiniCar.prototype
, 而MiniCar.prototype
是一个对象,这个对象也有一个__proto__
属性,这个属性指向Car.prototype
,如此一来这个伪继承就实现了.而后咱们将这个对象(c)的索引赋值给miniCar
,因此经过miniCar
能够操做对象(c).
而后接下来的一切应该都瓜熟蒂落了.
原文的地址github
参考的文章或者问答: