你不知道的JS——读书笔记

基本的编译原理

1. 词法分析

var a = 2;=>vara=2;

2. 语法分析

将词法分析得到的代码块转换为 AST(Abstract Syntax Tree 抽象语法树)

3. 代码生成

将 AST 转换为可执行的代码

JavaScript 编译原理

角色:1.编译器 2.作用域 3.引擎

实例代码:var a = 2;

过程描述:

1. 当编译器遇到 var a 声明

编译器会询问作用域集合中是否已经有一个 a 变量。如果是,那么编译器会忽略此声明;否则,编译器会要求作用域声明一个变量,并且命名为 a。

2. 声明完成,处理 a=2

编译器会为引擎生成此赋值操作的可执行代码。当引擎执行此代码时,首先会询问作用域,当前作用域集合是否存在 a 变量。如果是,那么引擎就会使用 a 变量,并把 2 赋给它;如果不存在,引擎会继续行外层作用域查找,直到最外层作用域(全局作用域),如果到全局作用域还是没找到,那么引擎就会抛出异常。

细说赋值操作 a=2

首先此赋值操作会触发两个查询(查找),LHS 和 RHS,LHS 负责查找赋值的目标(也就是把值赋给谁),RHS 负责查找赋值的值。

LHS

首先,引擎会询问当前作用域是否有一个叫 a 的变量,如果没有,那么就到外层作用域去查找,直到最外层作用域——全局作用域。

RHS

直接找到赋值为 2

实例:

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

1. foo(2)

此调用首先进行 RHS 查询查询到 foo,然后(…)表示需要执行此函数。

2. 对形参 a 赋值

首先进行 LHS 查找到形参,然后对其进行赋值,将 2 赋值给它。

3. 执行函数体

当遇到console.log(a); // 2首先 RHS 查找console,查找到以后判断它是否含有一个叫 log 的方法。将 foo 形参 a 的值赋给 log 函数的形参,LHS 查找 log 形参,RHS 查找 foo 形参 a 的值,然后将查找的结果赋给 log 的形参。

总结:

LHS 就是查找操作的对象,RHS 就是查找非操作对象(不一定是一个具体的值,例如上面的 console 函数)

LHS 异常

a = 2;

非严格模式下,全局作用域会自动创建一个变量 a 给引擎,然后引擎就会把 2 赋给它;严格模式下,引擎会抛出一个 ReferenceError(引用错误)。

RHS 异常

function foo(a) {
  console.log(a + b);
  b = a;
}

foo(2);

引擎在对 a+b 进行 RHS 查询时,所有作用域都找不到 b,所以会直接抛出 ReferenceError(引用异常)

词法作用域

词法作用域就是定义在词法阶段的作用域。由写代码阶段变量和块级作用域的位置决定。

例如:

function foo(a) {
  var b = a * 2;
  function bar(c) {
    console.log(a + b + c);
  }
  bar(b * 3);
}
foo(2); //2,4,12

词法作用域为:

在这里插入图片描述
分析
1 作用域有一个标识符:foo
2 作用域有 3 个标识符:a(foo 的参数),b,bar
3 作用域有一个标识符:c(bar 的参数)

欺骗词法

eval(…)

eval 函数可以接受一个字符串为参数。

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

非严格模式下,eval 函数会在它所在的作用域运行时创建一个变量 b,并且赋值为 3,因此打印的结果为 1,3。
但是在严格模式下,eval 函数只能在它所在的作用域创建一个新的作用域,然后在新的作用域中创建变量 b,并赋值为 3,类似于如下所示:

function foo(a) {
  function(){//并不完全一致
    var b=3;
  }
  console.log(a, b);
}
var b = 2;
foo(1); //1,2

with(…){}

var ob1 = {
  a: 1,
  b: 2,
  c: 3,
};
//正常写法(麻烦)
ob1.a = 2;
ob1.b = 3;
ob1.c = 4;
//使用with(看起来更简单)
with (ob1) {
  a = 2;
  b = 3;
  c = 4;
}

弊端分析

var ob1 = {
  a: 2,
};
var ob2 = {
  b: 1,
};
function foo(obj) {
  with (obj) {
    a = 3;
  }
}
foo(ob1);
console.log(ob1.a); //3
foo(ob2);
console.log(ob2.a); //undefined
console.log(a); //3,不好,自动在全局作用域定义了一个变量a

分析
with(…)会对他引用的对象和属性创建一个新的作用域,在这个作用域中,引用对象的属性默认被处理为此作用域的词法标识符。
但是在严格模式下,with 语法会被禁止。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值