1. LHS引用与RHS引用的区别:
RHS:取到源值-得到某某的值
LHS:谁是赋值操作的源头-给谁赋值
function foo(a) {
var b = a;
return a + b;
}
var c = foo( 2 );
// 所有LHS查询:a=...(形参隐式赋值)/b=.../c=...
// 所有RHS查询:foo(2)/=a/a+/+b
2. 作用域是什么?
作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。
3. 词法作用域:
词法作用域就是在定义词法阶段产生的作用域,词法作用域是由代码书写过程中将变量以及代码块书写位置确定的。如下:
词法作用域中的查找会在找到第一个匹配标识符停止,当当前作用域内没有找到目标标识符会继续向上层作用域查找,直到查找到顶层作用域,这也意味着在多层嵌套作用域中定义同名标识符上层匹配标识符会被屏蔽。
4. 函数作用域与块作用域:
函数作用域:属于这个函数的全部变量都可以在整个函数范围内使用及复用。
函数表达式与函数声明的区别:如果function是声明中的第一个词,那么就是函数声明,否则就是函数表达式。
立即执行函数表达式(IIFE):(function(…))()
块作用域:指变量和函数不仅可以属于所处的作用域也可以属于某个代码块(通常是{…}内部)
注意:let声明的变量并不是声明一个块级作用域,而是将变量绑定到所在的任意作用域(通常是{…}内部)代码是显式的,绑定行为是隐式的。
5. 提升
先有声明,后有赋值
函数提升优先级高于变量
6. 作用域闭包
- JavaScript中的闭包无处不在,你只需要能够认识并且拥抱他。
- 当函数能够记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。
- 闭包能够阻止引擎垃圾回收机制对函数内部作用域的销毁动作,使得函数内部作用域能够一直被引用
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo(); baz(); // 2 —— 朋友,这就是闭包的效果。
- 不能简单地将闭包理解为函数中return出另外一个函数,闭包有多种形式的展示,只需要满足上述2的条件即可
function foo() {
var a = 2;
function baz() {
console.log( a ); // 2
}
bar( baz ); // 引用了全局作用域中的bar函数并且将词法作用域中的baz传递进去
}
function bar(fn) {
fn(); // 妈妈快看呀,这就是闭包!
}
//---------------------
var fn;
function foo() {
var a = 2;
function baz() {
console.log( a );
}
fn = baz; // 将 baz 分配给全局变量 }
function bar() {
fn(); // 妈妈快看呀,这就是闭包!
}
foo();
bar(); // 2
- 无论通过何种手段将内部函数传递到所在的词法作用域之外,它都会持有对原始定义词法作用域的引用,在任何地方执行这个函数都会使用闭包。
- 无论何时何地,如果将函数(访问它们各自的词法作用域)当作第一 级的值类型并到处传递,你就会看到闭包在这些函数中的应用,可以简单理解为只要有地方使用了回调函数,实际上就已经使用了闭包。(定时器,事件监听器,ajax请求,跨端口通信…)
7. 动态作用域
动态作用域不关心函数和作用域是如何声明以及在何处声明,只关心它们从何处调用。作用域链是基于调用栈的,而不是作用域嵌套。