上卷-关于作用域-01

理解

1、引擎:负责程序的编译以及执行过程
2、编译器:负责语法分析以及代码生成等工作
3、作用域:收集并维护由所有声明的标识符组成的一系列查询,根据一些严格的规则,确定当前执行的代码对这些标识符的访问权限。

举个栗子

var a = 2;

var a 的处理

有声明时候的询问

没有声明的时候

a = 2 的处理

有a的时候
没有a的时候

如果最终找到了a,引擎会把2赋值给他,否则会抛出一个异常(ReferenceErrror)

小小解释一下关于ReferenceErrror与TypeError
ReferenceErrror和作用域判别失败相关
TypeError是作用域判别成功了,但是对结果的操作是非法的

术语介绍

LHS:赋值操作的左侧

当变量出现在赋值操作的左侧进行LHS查询
试图找到变量容器的本身,从而对其进行赋值

RHS:赋值操作的右侧

(可以理解成‘retrieve his source value’获取到他的原值)
当变量出现在赋值操作的右侧进行RHS查询(非左侧)
得到XXX的值

比如console.log(a)

这就是对a的RHS查询
再考虑一下这个吧!!!

function foo(a) {
  console.log(a);
}
foo(2)

有几个LHS和RHS呢?

在非严格模式的LHS查找没有找到,会隐式创建一个引用的目标作为标识符

在作用域进行查找

举个栗子

var a = 3;
// 这是第一个作用域(全局作用域)
function foo(a) {
  var c = 5;
  // 这是第二个作用域
  var b =a * 2;
  function bar(c) {
    // 这是第三个作用域
    console.log(a,b,c);
  }
  bar(b*3);
}
foo(2);

因为作用域由内向外查找并在第一个匹配的标识符的时候就停止,因此在多层嵌套作用域中可以命名相同的标识符
遮蔽效应就是内部的标识符遮蔽了外部的标识符

全局变量会会自动生成全局对象的属性(比如浏览器中的window对象),所以可以间接的通过对全局都西昂属性的引用来进行访问,比如window.a;
所以全局变量被遮蔽可以用这种方法访问,但是非全局变量被遮蔽,无论如何都没办法被访问到。

欺骗词法

eval()

可以接受一个字符串作为参数,并将字符串中的内容当作在书写时就在程序中这个位置的代码。

举个栗子

function foo(str,a) {
  eval(str);
  console.log(a,b);
}
var b = 2;// 被遮蔽啦!!!
foo("var b = 3;", 1)
//输出结果:1,3

以上代码相当于:

function foo(a) {
  var b = 3;
  console.log(a,b);
}
var b = 2;
foo(1)

严格模式下eval有自己的词法作用域,无法修改所在的作用域。
拓展关于setTimeout与setInterval,new Function()
去浏览器试一下吧!!

setTimeout('alert(\'aaaaaaaaaa\')',200)

with

举个栗子

function foo(obj) {
  with(obj) {
    a = 2;
  }
}
var obj1 = {
   a: 3
};
var obj2 = {
   b: 4
};
foo(obj1);
console.log(obj1.a); // 2
foo(obj2);
console.log(obj2.a); // undefined
console.log(a); // 2

with可以将对象创建一个完全隔离的作用域,所以对象的属性被处理为定义在这个作用域的标识符

如果with块内部正常的var声明不会被限制在他创建的作用域中,而实添加到with所处的作用域中(但是let和const声明会被限制)。


with创建的作用域

你可能感兴趣的:(上卷-关于作用域-01)