javascript编译器的一些原理——变量提升

来源:互联网 发布:js json添加元素 编辑:程序博客网 时间:2024/05/16 09:44

有没有发现在写代码的时候,往往会遇到一些莫名其妙的错误,然后时间紧急不得不去网上查阅一些代码。虽然要实现的功能解决了,但是看被拷贝的代码好多真心看不懂,以后遇到诸如此类的问题,如果查阅不到这些代码的话还是不会。所以今天给大分享一下内部原理的问题

1.js编译器编译的几条基本原则

a.js预编译:优先解释函数声明,忽略表达式;
b.运行期间:获取变量顺序,由底层向顶层依次查找,直到找到为止。;
c.变量的定义:会被提前到所属代码作用域最前面
d.function foo(){}这种声明会被js编译器解释成var foo;foo = function(){}这种格式

是不是看了几条规则,不知道我说的什么。没关系,可能是我总结的不好,看下面例子具体了解下

2.自执行函数/闭包

自执行函数,相信大家都接触过。如果不知道,应该只是不知道这个学名而已,在此不给出具体文字定义。
简单解释为:类似(function(){...})()这种形式的代码就叫做自执行函数,又称闭包他在js编译器解析到时,直接被执行。

一个简单小例子:

(function(){    //...})()

可以被自执行,写成

function(){    //...}()

可以被自执行吗?
答:不可以!

这里是因为上面所说规则a :优先解释函数声明,忽略表达式

js预编译时,先解释函数声明,因此function(){...}()前面的function(){...}在‘预编译阶段’已经被解释成变量。js会跳过这段代码,遇到了后面的(),会试图去执行()里的内容,显然不科学;
(function(){...})()则可以被自执行。因为它加了括号,已经变成了表达式。‘js预编译时’会运行它,并对它求解得到一个返回值。而此处返回值是一个函数,故而遇到最后面的()便会执行

例子:

a=1;console.info(a)function b(){   console.info(a);   var a=10;   console.info(a);};b();//1,undefined,10

你是不是预期结果是1,1,10

这里正是因为上面的规则c :变量的定义会被提前到所属代码作用域最前面

当js编译器,在执行这个b函数的时候。会把它‘body’里面的声明变量,提前到最前面进行声明。如:var a=10; 编译器先会在‘body’最前面进行var a 声明(变量提升)。

上面代码等同于下面代码:

a=1;console.info(a)function b(){    var a;   console.info(a);   a=10;   console.info(a);};b();

声明a的时候还没有值,故而打印undefined;

再看一个例子…
  
    

a = 1;function b(){    a = 10;    return;    function a(){};};b();console.info(a);//1

你是不是预期结果是10,以为会覆盖全局变量?

这里是因为上面的
规则b :运行期间,获取变量顺序,由底层向顶层依次查找,直到找到为止
规则d function foo(){}这种声明会被js编译器解释成var foo;foo = function(){}这种格式

上述代码等价于

a = 1;function b(){    var a;    a = 10;    return;    a = function(){};}b();console.info(a);

3.使用场景

有了上面的理论知识,可以解决曾经有人问我的一个问题:三元表达式后面,如何执行多条语句?其实答案就是在后面写自执行函数。当然,不排除有其它方法,代码如下:
    

var a = 2 > 1 ?    (function(){ var c = 2, d = 1; return c + d; })()    : (function(){ var c = 2, d = 1; return c - d; })();console.info(a);//2

这种需求应该很少吧。我宁愿写个if,不过可以实现,呵呵…

author: jyjin
date: 2014.8 [博客搬家]

0 0
原创粉丝点击