https://segmentfault.com/a/1190000002900676javascript
和java这种基于类(class-base)的面向对象的编程语言不一样,javascript没有类这样的概念,可是javascript也是面向对象的语言,这种面向对象的方式成为 基于原型(prototype-base)的面向对象。虽说ES6已经引入了类的概念来做为模板,经过关键字 “class” 能够定义类,但ES6的这种写法能够理解为一种语法糖,它的绝大部分功能,ES5均可以作到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。若是要理解基于原型实现面向对象的思想,那么理解javascript中得三个重要概念: 构造函数(constructor)、原型(prototype)、原型链(prototype chain) 对帮助理解基于原型的面向对象思想就显得尤其重要。下面就重点介绍一下这几个概念。java
先来看一张来自mollypages.org 的javascript对象的结构图,下面的例子都按照这张图阐述。编程
构造函数是用来初始化对象的,每一个构造函数都有一个不可枚举的属性,这就是原型(prototype).而且,每一个prototype 都包含一个包含了不可枚举属性的constructor属性,这个属性始终会指向构造函数。segmentfault
function Foo(){}; console.log(Foo.prototype.constructor === Foo); // true
每一个被new实例化的对象都会包含一个__proto__
属性,它是对构造函数 prototype
的引用。编程语言
function Foo(){}; var foo = new Foo(); console.log(foo.__proto__ === Foo.prototype); // ture
function Foo(){}; console.log(Foo.prototype.__proto__ === Object.prototype); // true
上面返回true 的缘由是Foo.prototype 是Object预建立的一个对象,是Object建立的一个实例,因此,Foo.prototype.__proto_ 是Object.prototype的引用。函数
咱们能够来看一下原型链的脉络。ui
在javascript中,函数是一种特殊的对象,全部的函数都是构造函数 Function
的实例。spa
function Foo() {}; console.log(Foo.__proto__ === Object.prototype); //false console.log(Fool.__proto__ === Function.prototype); // true
从上面能够看出,函数Foo.__proto_ 指向到 Function.prototype, 说明函数 Foo
是 Function的一个实例。prototype
function Foo(){}; console.log(Foo.__proto__ === Function.prototype); //true console.log(Foo.prototype.__proto__ === Object.prototype);//true
Foo.prototype 是Object预约义的对象,构造函数为Object,因此__proto__
指向 Object.prototype
code
从上面的图咱们能够看出, Object、Function、Array 等这些函数,他们的构造函数都是 Function 的实例。
有了上面的基础知识之后,咱们就能够本身去基于原型链去封装对象,实现javascript的继承。先来看下面一个例子。
运行上面的例子,输入 cat init 和 animal eat,说明cat 继承了 Animal.prototype.eat 的方法。
咱们来分析一下代码。
一、Animal 的prototype中定义了 eat方法。
二、将Empty.prototype 指向 Animal.prototype , 因此 Empty.prototype 中也存在eat
方法.
三、Cat.prototype == new Empty(),因此 Cat.prototype.__proto_ === Animal.__proto_.
四、从新为Cat指定constructor为Cat,不然Cat不存在constructor。
这样就完成了继承,原型链是这样的:
这样咱们用原型链的方式实现了一个简单的继承方式。