作用域相关
var a = 2; |
注: 不成功的LHS会抛出一个(ReferenceError)异常,而一个不成功RHS会创建一个全局变量(费严格模式下)
此法作用域
- js本身会在编译阶段进行数项的性能优化。但是如果使用eval或者with的话,编译器无法明确的知道会接受到什么样的代码,所以这些优化都会无效,所以不建议使用eval或者with
- 遮蔽效应
指由于作用域查找会在找到第一个匹配的值时停止,所以在多层嵌套的作用域中,内部的标识符遮蔽了外部的标识符。
注:词法作用域只会查找一级标识符,比如foo.bar.baz,此法作用域只会试图查找foo,当找到foo变量时,对象访问规则便会分别接管对bar和baz的访问权限。with关键字可能会导致变量的泄露,看如下代码
function foo(obj) {
with(obj) {
a = 2;
}
}
var o1 = {
a = 3;
}
var o2 = {
b = 2;
}
foo(o1);
foo(o1);
在这段代码中,当第二次执行foo函数时,因为o2并没有a属性,此时程序会自动创建一个a变量并绑定到全局作用域中。
函数作用域和块作用域
- 函数作用域
指属于这个函数的全部变量都可以在整个范围内使用及复用。 - 最小授权原则
指在软件设计中,应该最小限度的暴露必要的内容,将其他内容隐藏起来。 - 规避冲突
- 全局命名空间
通过命名空间,将各自的属性都声明再统一的对象下,,而不是将自己暴露在顶级词法作用域下。 - 模块管理
模块模式
- 全局命名空间
IIFE(立即执行函数)
(function(){})()块作用域
在一个代码块内,变量只能在内部使用,不会对外部的块作用域进行污染。
with, trh/catch都会创建一个块作用域
es6的let 和 const 也会创建一个快作用域
注: 当声明一个覆盖整个函数作用域的闭包时,js极有可能不会回收该函数,造成内存不必要的浪费和泄露,但是在块作用域下就能够与避免这样的情况。
闭包
- 函数中的函数,由于函数的作用域链,外部函数无法访问函数中定义的函数内容,从而形成闭包
隐式和显示作用域
- let声明会创建一个显示作用域并与其进行绑定,再块外部是无法访问let声明的变量的
this词法
- es6中新增了箭头函数() => {} 使用箭头函数会放弃普通的this绑定规则,取而代之的使用当前词法作用域覆盖了this本来的值
关于this
- 为什么要用this
答: this提供了一种更优雅的方式来隐式’传递’一个对象引用,由此可以将API设计的更加简洁并且易于复用。随着使用的模式越来越多
显式传递上下文对象会让代码越来越混乱,使用this就不会这样。
function foo(num) { |
- this调用栈和调用位置
function baz() { |
this绑定规则
默认规则
- 再无法应用其他规则时的规则
function foo() {
console.log(this.a);
}
foo();
// 这里this默认绑定到了全局变量上,因为foo是直接使用不带任何修饰的函数引用进行调用的,所以应用了this的默认绑定,因此this指向全局对象
// 但是在严格模式下则不会绑定到全局全局对象,会直接绑定到undefined
- 再无法应用其他规则时的规则
隐式绑定
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo,
};
obj.foo();
// 因为此时foo调用的函数上下文是obj,所以此时this就绑定到了obj上。调用位置会使用obj上下文来引用函数,因此你可以说函数被调用时obj对象'拥有'或者'包含'它显式绑定(call apply bind)
Function.prototype.bind = function(newThis) { |