注:本文仅总结本人觉得相关容易混淆的点,关于作用域链完整的描述网上很容易找到大量资源哈。
末尾附有相关易错练习题,有兴趣可以一起探讨解题思路
1.编译原理 :
分词/词法分析, 解析/语法分析, 代码生成
2.JS执行:
引擎, 编译器, 作用域
3.词法作用域(静态作用域):
无论函数在哪里被调用,也无论他如何被调用,他的词法作用域只由函数被声明位置决定。
两个欺骗行为:eval(), with() //可在代码动态执行时修改或新增作用域;降低性能
4.作用域链(Scope Chain):
就是根据名称查找变量(标识符名称)的一套规则。
规则非常简单,在自己的变量对象里找不到变量,就上父级的变量对象查找,当抵达最外层的全局上下文中,无论找到还是没找到,查找过程都会停止。查找会在找到第一个匹配的变量时停止,被称为遮蔽效应
5.执行环境(也称执行环境)堆栈:
执行上下文定义了变量或函数有权访问的其他数据,决定了它们各自的行为。而在javascript中有三种执行上下文: 全局执行上下文, 函数执行上下文, eval执行上下文。
一个函数可能会产生无限上下文集合,因为每次函数调用自身都会产生一个新的执行上下文
每个函数运行时都会产生一个执行环境,js为每一个执行环境关联了一个变量对象。环境中定义的所有变量和函数都保存在这个对象中。
//全局执行环境是最外围的执行环境,全局执行环境被认为是window对象,因此所有的全局变量和函数都作为window对象的属性和方法创建的。
js的执行顺序是根据函数的调用来决定的,当一个函数被调用时,该函数环境的变量对象就被压入一个环境栈中。而在函数执行之后,栈将该函数的变量对象弹出,把控制权交给之前的执行环境变量对象。
js函数内的变量值不是在编译的时候就确定的,而是等在运行时期再去寻找的。
5.1 执行上下文
每个执行上下文可以抽象成一个对象,都包含了一组属性。
注意:隐式劫持(let)
delete 不能删除var/let/const声明的变量。其实,用delete window.vb 的方式也不能删除(var 声明的变量configurable为false; 直接声明的变量为true)
练习题:
//---------------- 题目一 --------------------
inner = 'window';
function say() {
console.log(inner);
console.log(this.inner);
}
var obj1 = (function() {
var inner = '1-1';
return {// TODO 1
inner: '1-2',
say: function() {
console.log(inner);
console.log(this.inner);
}
}
})();
/var obj2 = (function() {
var inner = '2-1';
return {
inner: '2-2',
say: function() {
console.log(inner);
console.log(this.inner);
}
}
})();
say();
obj1.say();
obj2.say();
obj1.say = say;
obj1.say();
obj1.say = obj2.say;
obj1.say();
//---------------- 题目二 --------------------
var scope = 'global';
function t() {
console.log(scope);
var scope = 'local';
console.log(scope)
}
t()
//---------------- 题目三 --------------------
var name = 1;
sex = 'girl';
delete name;
delete sex;
console.log(name)
console.log(sex)
//---------------- 题目四 --------------------
// with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部.with语句结束后,作用域链恢复正常。
//---------------- 题目五 --------------------
*inner = 'window';
function say() {
console.log(inner);
console.log(this.inner);
}
var obj1 = (function() {
var inner = '1-1';
return {// TODO 1
inner: '1-2',
say: function() {
console.log(inner);
console.log(this.inner);
}
}
})();
var obj2 = (function() {
var inner = '2-1';
return {// TODO 2
inner: '2-2',
say: function() {
console.log(inner);
console.log(this.inner);
}
}
})();
say();
obj1.say();
obj2.say();
obj1.say = say;
obj1.say();
obj1.say = obj2.say;
obj1.say();
//---------------- 题目六 --------------------
var a = 1;
function f()
a =10;
return;
function a() {
}
}
f();
console.log(a);
var a = [1];
var b = a;
a.push(2);
var c = 1;
var d = c;
c =2;
console.log(b);
//---------------- 题目六 --------------------
function f1(){
return this;
}
f1() === window;
//---------------- 题目七 --------------------
var foo = 10;
function bar(){};
(function baz(){})
console.log(baz);