原型与闭包是JavaScript与其余面向对象语言差别最大的两个点,深刻学习js须要咱们理解原型es6
在js中咱们常用typeof运算符来判断一个变量的类型。 常见的类型能够分为值类型与引用类型vim
值类型有:undefined、number、string、boolean数组
引用类型有:obejct、function(数组、对象、空值都是object)闭包
对象是什么??对象就是一些属性值的集合记住这一句话就能够很好地帮助你判断这是否是一个对象app
咱们都知道,对于引用类型的判断,咱们经常使用instanceof运算符。咱们队一个函数使用这个判断符时,得出的结果是object。那么函数与对象之间究竟有着什么样的区别与联系呢?函数
在es6以前,若是咱们想要定义一个对象,那么咱们经常使用的建立构造函数的方式就是。学习
function Fn() {
this.name = '王福朋';
this.year = 1988;
}
var fn1 = new Fn();
复制代码
很显然,咱们创造了一个fn1对象,有名字和出生年份两个属性。ui
这里有一个重要的结论就是*一切的对象都是经过函数来创造的(构造函数)*不信的话咱们能够对Object和Array作typeof运算,获得的结果就是function。this
本小节最后,咱们来理一理思路,全部的对象都是由函数构造的,而一个函数又是一个对象。那么问题来了。。。hahahahspa

如图所示,每个函数都有它的原型(prototype),原型是是一个对象,里面有着许许多多的属性值。咱们在使用函数建立对象时,函数中的prototype就会建立一个引用,这个引用就是__proto__这是每个对象的隐藏属性,指向构造函数的原型。即fn.proto===Fn.prototype
隐式原型指的就时对象的隐藏属性_proto__
每一个函数function都有一个prototype,即原型。这里再加一句话——每一个对象都有一个__proto__,可成为隐式原型。
咱们都知道函数instanceof Obejct的值为true。因此它的本质就是Object的prototype。那么Obeject的_proto_指向哪里呢?答案是null。这是一个特例。
那么函数是一个对象,对象就有隐式原型,它的隐式原型指向的就是创造这个对象的函数Function的prototype。因此咱们能够获得一个很绕的原型链图。

最后,咱们都知道prototype属性是一个对象,那么Function。prototype这个对象的_proto_指向哪里呢?固然只指向Object.prototype啦!!
首先咱们须要知道,所谓继承,继承的是什么。
function Foo () {}
var f1 = new Foo()
f1.a = 100
Foo.prototype.a = 1
Foo.prototype.b = 100
console.log(f1.a) // 100
console.log(f1.b) //100
复制代码
经过以前的学习,我门已经知道了f1具备__proto__属性,这个属性指向构造对象的函数Foo的prototype上。那么当咱们访问f1的属性值时,js会先从对象的基本属性中查找,若是没有就从__proto__这条链一直往上找。这种继承的属性寻找机制,就是原型链。
咱们可使用hasOwnProperty()方法来查询某个属性值是否属于这个对象的基本属性,若是是从原型链上继承过来的就会返回false。
先看三个例子
// Example 1
console.log(a) //Eroor
//-----------------------------
console.log(a) //undefined
var a
//-----------------------------
console.log(a) //undefined
var a = 10
//-----------------------------
// Example 2
console.log(this) //任何状况下都有值,可是取值会变
//-----------------------------
// Example3
console.log(f1) // function f1 () {}
function f1 () {}
console.log(f2) // undefined
var f2 = function () {}
复制代码
咱们来看上面三个例子。
第一个例子的一二个,我想你们都知道为何,一个是没有声明,第二个是存在声明提高,可是没有赋值,第三个的缘由是,console的时候尚未执行赋值。
第二个例子,后面会详细说。
第三个例子,首先咱们须要知道第一个是函数声明,第二个是函数表达式,函数声明一样的具备提高,因此有输出,而表达式理由同例1的第三个。
经过上面的例子咱们发下,在不一样的语句条件下,访问某些变量,这些变量的值是会根据语句条件的不一样而不一样的。咱们就管这种语句条件叫作上下文环境。
执行上下文环境下一个通俗的定义——在执行代码以前,把将要用到的全部的变量都事先拿出来,有的直接赋值了,有的先用undefined占个空。
在函数中this到底取何值,是在函数真正被调用执行的时候肯定的,函数定义的时候肯定不了。由于this的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。
不只仅是构造函数的prototype,即使是在整个原型链中,this表明的也都是当前对象的值
function Foo () {
this.a = 1
console.log(this)
}
var f1 = new Foo() // Foo {a:1}
Foo() //Window
复制代码
当函数做为构造函数使用时,this指向的就是它即将new出来的对象,即f1,可是若是直接使用指向的就是Window
一个对象调用它属性中的某个方法时,方法中的this指向的就是这个对象
当一个函数被call或者apply调用时,函数中this的值就是传入的对象
在全局环境与普通函数调用时,this的值都是Window。
var obj = {
fn: function () {
function f () {
console.log(this) //Window
}
}
}
复制代码
上面这是一种特殊状况,咱们都知道,fn做为obj的方法,它的this应该是obj。可是fn中的f是一个普通函数,普通函数的this就是Window。