这里是JavaScript核心的内容了. 挺多的JavaScript测试题也是围绕这个出的.
这里的一静一动指的是:
- 静, 词法作用域 - Lexical scoping
- 动, 动态绑定this的值
在JavaScript中函数有静态的词法作用域. 这是什么意思?
当我们写好了代码, 如 lexical.js , 那么此刻, 代码里的各个函数的作用域就已经确定了. 与这个函数是否被调用, 在哪儿调用, 被谁调用无关.
作用域大都被说成作用域链, 它是有层级关系的, 从顶层向底层直到全局作用域; 或者说从链头部向尾部延伸, 直到最后面的全局空间Global.
Global总在最后.
此作用域是函数的一个内部属性, 代码访问不到. 技术书籍中通常用 [[scope]] 这个名字来表示这个静态的词法作用域.
静 和 作用域 都说了, 那么这个词法是什么?
JavaScript解释器只需要分析源代码的文本就能确定[[scope]]. 嗯..我是这么理解的
例:
(1)
var scope = "global"; function foo() { console.log(scope); } function bar() { var scope = "local"; foo(); console.log(scope); } bar(); // global // local
(2)
var scope = "global", ns = { scope: "In object", bar: function() { console.log(scope); // !this.scope } }; ns.bar(); //result global
(3)
var scope = "global", bar = function() { var scope = "In bar"; return function() { // var scope = "In anony fn"; console.log(scope); }; }; bar()();
======
稍微讲下, 这里形成了闭包, 比上面的例子稍复杂些, 但是判断词法作用域却非常简单! 为什么, 因为我们不用去考虑什么闭包什么调用逻辑,
我们只要分析代码文本就行了!
例子里一共出现2个函数, 3个scope变量(算上我注释掉的). 前提我们知道JavaScript中函数能产生新的作用域.
那么, 我们看一下return的这个匿名函数的词法作用域 [[scope]] 是什么?
分析代码文本, 首先有匿名函数自己, 往下是包着它的 bar 函数, 再往下发现没有函数了, 那就到Global了.
[[scope]] = Returned anonymous function -> bar function -> global
当我们确定了[[scope]], 当解析标识符scope的时候就是从这个链的顶端 anonymous function 向底部 Global 查找;
那么就上面的例子, bar()()调用时, 我们相当于在Global空间里调用了bar函数返回的匿名函数, 此函数打印 console.log(scope). 虽说是在Global里打印scope, 但是结果
是"In bar". 因为无论在哪调用, [[scope]]早已经确定! [[scope]] = Returned anonymous function -> bar function -> global
当打印scope的时候, 从Returned anonymous function开找, 发现没有 scope(被我注释掉了), 找下一个, bar function 发现目标, 打印之.