一、执行环境及做用域 javascript
(1).执行环境:java
定义了变量或函数有权访问的其它数据,决定了它们的各自行为。每一个执行环境都有一个与之关联的变量对象(variable object, VO),执行环境中定义的全部变量和函数都会保存在这个对象中,解析器在处理数据的时候就会访问这个内部对象。web
全局执行环境是最外层的一个执行环境,在web浏览器中全局执行环境是window对象,所以全部全局变量和函数都是做为window对象的属性和方法建立的。每一个函数都有本身的执行环境,当执行流进入一个函数的时候,函数的环境会被推入一个函数栈中,而在函数执行完毕后执行环境出栈并被销毁,保存在其中的全部变量和函数定义随之销毁,控制权返回到以前的执行环境中,全局的执行环境在应用程序退出(浏览器关闭)才会被销毁。编程
(2).做用域:数组
做用域就是变量和函数的可访问范围,控制着变量和函数的可见性与生命周期,在JavaScript中变量的做用域有全局做用域和局部做用域。浏览器
全局做用域:任何地方均可以定义拥有全局做用域的变量。缓存
a.没有用var声明的变量(除去函数的参数)都具备全局做用域,成为全局 变量,因此声明局部变量必需要用var。安全
b.window的全部属性都具备全局做用域闭包
c.最外层函数体外声明的变量也具备全局做用域 app
局部做用域:局部变量的优先级高于全局变量。
a.函数体内用var声明的变量具备局部做用域,成为局部变量
b.函数的参数也具备局部做用域
JavaScript是函数做用域(function scope),没有块级做用域。不管函数体内的变量在什么地方声明,对整个函数都是可见的,即JavaScript函数里声明的全部变量都被提早到函数体的顶部,只是提早变量声明,变量的赋值仍是保留在原位置
(3).做用域链:
JavaScript的变量都是对象的属性,而该对象可能又是其它对象的属性,而全部的对象都是全局对象的属性,因此这些对象的关系能够看做是一条链,因为每一个对象都有一个做用域,因此造成了一个做用域链。链头就是变量所处的对象,链尾就是全局对象。
当代码在一个环境中执行时,会建立变量对象的一个做用域链来保证对执行环境有权访问的变量和函数的有序访问。
二、原型链、继承
(1)理解原型对象
1).只要建立了一个新函数,就会为该函数建立一个prototype属性,这个属性指向函数的原型对象;
2).全部原型对象都会自动得到一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针;
3).当调用构造函数建立一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。
(2)原型链
综上所述,假如咱们让原型对象等于另外一个类型的实例,则此时的原型对象将包含一个指向另外一个原型的实例,相应地,另外一个原型中也包含着一个指向另外一个构造函数的指针。假如另外一个原型又是另外一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条,这就是原型链。
【注】:全部引用类型默认都继承了Object,而这个继承也是经过原型链实现的。全部函数的默认原型都是Object的实例,所以默认原型都会包含一个内部指针,指向Object.prototype。这也正是全部自定义类型都会继承toString(),valueOf()等默认方法的根本缘由。
(3)继承
1).经过原型链实现。不能使用对象字面量建立原型方法,由于这样会重写原型链。
缺点:最主要的问题是包含引用类型值的原型;二是在建立子类型的实例时,不能向超类型的构造函数中传递参数。
2)借用构造函数。在子类型构造函数的内部调用超类型构造函数。使用apply()和call()方法,能够向超类型的构造函数中传递参数。apply()和call()的做用同样,只是专递的参数形式不一样,apply()的参数是以数组的形式传递,call()中是展开的形式。
缺点:函数复用无从谈起,并且在超类型的原型中定义的方法,对子类型而言是不可见的。
3).组合继承(原型链+借用构造函数)。避免了1)、2)的缺陷,融合了他们的优势,成为javascript最经常使用的继承模式,并且,instanceof和isPrototypeOf()也可以用于识别基于组合继承建立的对象。
三、闭包
(1).概念:有权访问另外一个函数做用域中的变量的函数。简单理解为“定义在一个函数内部的函数”。
(2).好处:保护函数内的变量安全,增强了封装性;在内存中维持一个变量(缓存);匿名自执行函数;模拟面向对象编程。
(3).应用场景:使用闭包代替全局变量;函数外或在其余函数中访问某一函数内部的参数;包装相关功能;为节点循环绑定click事件,在事件函数中使用当次循环的值或节点,而不是最后一次循环的值或节点;
(4).缺点:常驻内存,会增大内存使用量,使用不当很容易形成内存泄露,更重要的是,对闭包的使用不当会形成无效内存的产生。