先说下这个老话题:连续赋值

例1:

function a(){ 
    var o1 = o2 = 5; 
} 
a(); 
console.log(o1); 
console.log(o2); 

结果是什么?console.log(o1);这句简单undefined,而console.log(o2);这句呢?答案是5,o2变成了全局变量了
这是实际执行顺序:

var o1; 
o2 = 5; //o2未使用var声明,所以变全局变量了 
o1 = o2;

例2:

var foo = {n:1}; 
var bar = foo; 
foo.x = foo = {n:2}; 
console.log(foo.x); 
console.log(bar.x); 

很早以前的面试题目了,相信很多人知道答案,考点:词法分析、执行顺序、运算符优先级等
这是我理解的实际执行顺序:

var foo; 
var bar; 
foo = {n:1}; 
bar = foo; //bar = {n:1} 
foo.x = undefined; // 
foo.x = (foo = {n:2}); 
console.log(foo.x); //undefined 
console.log(bar.x); //{ n: 2 } 

我是这么猜想的:自我感觉勉强说的通,有不对的地方请指出!
JS引擎遇到foo.x = foo = {n:2}; 词法分析为foo.x, =, foo, =, {n:2}
执行顺序:

  1. 先为foo添加x属性,未赋值(undefined),这里的foo还是{n:1}

  2. 遇到第一个'=',准备为x赋值

  3. '='优先级最低,先计算右边表达式的值

  4. 执行foo = {n:2},并将该赋值表达式的结果值{n:2}赋值给之前的foo.x

最终foo的引用指向了{n:2},不存在属性x
而bar的引用没变,始终指向原来的{n:1},而{n:1}被添加了x属性{n:2}变为{n:1,x:{n:2}},这就是最后bar引用的值

下面给大家介绍下JS的词法分析

以下内容参考:《javascript权威指南》《你不知道的javascript》

JS 解析器在执行语句前会将函数声明和变量定义进行"预编译",而这个"预编译",并非一个页面一个页面地"预编译",而是一段一段地预编译,所谓的段就是一 个 <script> 块

JavaScript代码自上而下执行,但是在js代码执行前,会首先进行词法分析,所以事实上,js运行要分为词法分析和执行两个阶段。

词法分析

词法分析主要分为3步:
第1步:分析形参
第2步:分析变量声明
第3步:分析函数声明
如果存在函数嵌套,则从外往内进行词法分析

执行:

  1. 在函数执行的一瞬间,产生一个空的 Active Object(活动对象),下面简称AO

  2. AO对象初始化

    2.1 函数声明的形参,形成AO的属性,默认值是undefined
    2.2 接收实参,给刚刚形成AO的属性的形参赋值 
    
  3. var声明、函数声明均被提升到函数体顶部(若var声明、函数声明同名,则函数声明将覆盖变量声明),注意,var声明只提前了声明部分,而函数声明提前了整个函数定义。

  4. 分析var声明变量!如 var age;(变量的值是在运行时期决定)

    4.1 如果AO上没有age属性,则给AO添加age属性,默认值是undefined 
    4.2 如果AO上已经存在age属性,则忽视,不做任何操作。 
  5. 分析函数声明!如 function foo(){}

    5.1 如果AO上没有foo属性,则为AO添加foo属性 
    5.2 如果AO上有foo属性,则会直接覆盖,把函数赋给AO.foo属性(因为:若var声明、函数声明同名,则函数声明将覆盖变量声明) 
  6. 依据此时AO的值,自上而下执行代码

代码演示与分析:

function a(b){ 
   alert(b); 
   function b(){ 
       alert(b); 
   } 
   b(); 
} 
a(1); 

这是个常见的面试题,如果不懂JavaScript的词法分析,根本看不懂,下面就按照JavaScript的词法步骤进行分析,前面说过JavaScript自上而下执行,但是先进行词法分析后执行代码

过程:

  1. 形成活动对象AO = {}

  2. 分析形参,–> AO = {b:undefined}; 分析传参,–> AO = {b:1}

  3. 分析变量声明var,没有

  4. 分析函数声明,AO.b = function(){alert(b);},执行覆盖操作

执行:

alert(b);//弹出提示‘function b(){ alert(b); }’
b(); // 执行function b(){ alert(b); },在函数b的作用域内部找不到b,根据作用域链原理往外层寻找,找到b就是函数自己,弹出‘function b(){ alert(b); }’

苏福
167 声望4 粉丝

我只是个喜欢写代码的农民!