首先要搞明白几个概念:java
- 函数(function)
- 函数对象(function object)
- 本地对象(native object)
- 内置对象(build-in object)
- 宿主对象(host object)
function foo(){ } var foo = function(){ }
前者为函数声明,后者为函数表达式。typeof foo
的结果都是function。函数
函数就是对象,表明函数的对象就是函数对象ui
官方定义, 在Javascript中,每个函数实际上都是一个函数对象.JavaScript代码中定义函数,或者调用Function建立函数时,最终都会以相似这样的形式调用Function函数:var newFun = new Function(funArgs, funBody)this
其实也就是说,咱们定义的函数,语法上,都称为函数对象,看咱们如何去使用。若是咱们单纯的把它当成一个函数使用,那么它就是函数,若是咱们经过他来实例化出对象来使用,那么它就能够当成一个函数对象来使用,在面向对象的范畴里面,函数对象相似于类的概念。spa
var foo = new function(){ } typeof foo // object 或者 function Foo (){ } var foo = new Foo(); typeof foo // object
上面,咱们所创建的对象prototype
ECMA-262 把本地对象(native object)定义为“独立于宿主环境的 ECMAScript 实现提供的对象”。简单来讲,本地对象就是 ECMA-262 定义的类(引用类型)。它们包括:
Object,Function,Array,String,Boolean,Number
Date,RegExp,Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError.
咱们不能被他们起的名字是本地对象,就把他们理解成对象(虽然是事实上,它就是一个对象,由于JS中万物皆为对象),经过code
typeof(Object) typeof(Array) typeof(Date) typeof(RegExp) typeof(Math)
返回的结果都是function对象
也就是说其实这些本地对象(类)是经过function创建起来的,继承
function Object(){ } function Array(){ } ...
能够看出Object本来就是一个函数,经过new Object()以后实例化后,建立对象。相似于JAVA中的类。ip
ECMA-262 把内置对象(built-in object)定义为“由 ECMAScript 实现提供的、独立于宿主环境的全部对象,在 ECMAScript 程序开始执行时出现”。这意味着开发者没必要明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每一个内置对象都是本地对象)。
理清楚了这几个概念,有助于理解咱们下面要讲述的原型和原型链。
prototype属性是每个函数都具备的属性,可是不是一个对象都具备的属性。好比
function Foo(){ } var foo = new Foo();
其中Foo中有prototype属性,而foo没有。可是foo中的隐含的__proto__属性指向Foo.prototype。
foo.__proto__ === Foo.prototype
为何会存在prototype属性?
Javascript里面全部的数据类型都是对象,为了使JavaScript实现面向对象的思想,就必需要可以实现‘继承’使全部的对象链接起来。而如何实现继承呢?JavaScript采用了相似C++,java的方式,经过new的方式来实现实例。
举个例子,child1,child2都是Mother的孩子,且是双胞胎。(虽然不是很好,可是仍是很能说明问题的)
function Mother(name){ this.name = name; this.father = 'baba'; } var child1 = new Mother('huahua'); var child2 = new Mother('huahua');
若是有一天,发现孩子的父亲实际上是Baba,那么就要修改每个孩子的father属性。
child1.father ='Baba'; console.log(child2.father) // baba
也就是说修改了其中一个孩子的father属性不会影响到下一个,属性的值没法共享。
正是这个缘由才提出来prototype属性,把须要共享的属性放到构造函数也就是父类的实例中去。
__proto__
__proto__属性是每个对象以及函数都隐含的一个属性。对于每个含有__proto__属性,他所指向的是建立他的构造函数的prototype。原型链就是经过这个属性构件的。
想像一下,若是一个函数对象(也称为构造函数)a的prototype是另外一个函数对象b构建出的实例,a的实例就能够经过__proto__与b的原型链起来。而b的原型其实就是Object的实例,因此a的实例对象,就能够经过原型链和object的prototype连接起来。
function a(){ } function b(){ } var b1 = new b(); a.prototype = b1; var a1 = new a(); console.log(a1.__proto__===b1);//true console.log(a1.__proto__.__proto__===b.prototype) //true console.log(a1.__proto__.__proto__.__proto__===Object.prototype) //true
若是要理清原型和原型链的关系,首先要明确一下几个概念:
1.JS中的全部东西都是对象,函数也是对象, 并且是一种特殊的对象
2.JS中全部的东西都由Object衍生而来, 即全部东西原型链的终点指向Object.prototype
3.JS对象都有一个隐藏的__proto__属性,他指向建立它的构造函数的原型,可是有一个例外,Object.prototype.__proto__指向的是null。
4.JS中构造函数和实例(对象)之间的微妙关系
构造函数经过定义prototype来约定其实例的规格, 再经过 new 来构造出实例,他们的做用就是生产对象.
function Foo(){ } var foo = new Foo(); foo实际上是经过Foo.prototype来生成实例的。
构造函数自己又是方法(Function)的实例, 所以也能够查到它的__proto__(原型链)
function Foo(){ } 等价于 var Foo= new Function();
而Function其实是
function Function(){ Native Code } 也就是等价于 var Function= new Function();
因此说Function是经过本身建立出来的。正常状况下对象的__proto__是指向建立它的构造函数的prototype的.因此Function的__proto__指向的Function.prototype
Object 实际上也是经过Function建立出来的
typeof(Object)//function 因此, function Object(){ Native Code } 等价于 var Object = new Function();
那么Object的__proto__指向的是Function.prototype,也便是
Object.__proto__ === Function.prototype //true
下面再来看Function.prototype的__proto__指向哪里
由于JS中全部的东西都是对象,那么,Function.prototype 也是对象,既然是对象,那么Function.prototype确定是经过Object建立出来的,因此,
Function.prototype.__proto__ === Object.prototype //true
综上所述,Function和Object的原型以及原型链的关系能够概括为下图。
对于单个的对象实例,若是经过Object建立,
var obj = new Object();
那么它的原型和原型链的关系以下图
若是经过函数对象来建立,
function Foo(){ } var foo = new Foo();
那么它的原型和原型链的关系以下图
那JavaScript的总体的原型和原型链中的关系就很清晰了,以下图所示