js便签笔记(12)——浏览TOM大叔博客的学习笔记 part2

1. 前言

昨天写了《js便签笔记(11)——浏览TOM大叔博客的学习笔记 part1》,简单记录了几个问题。part1的重点还是在于最后那个循环创建函数的问题,也就是多个子函数公用一个闭包数据的问题。如果觉得有兴趣,可以再重新翻出来看看。

今天继续把剩下的问题写完。

2. 作用域链

学js的人,即使初级入门的也都知道“原型链”,但是“作用域链”,可能好多人没有听说过。大部分人都知道或者听说过“闭包”,但是可能有好多人不知道闭包其实和作用域链有莫大的联系。如果理解闭包不从作用域链开始理解,那么你就只能理解闭包的皮毛。

我也是从TOM大叔的这些博客中才了解到作用域链的,之前也看过了许多本书籍,都没有很清晰的展开作用域链这个概念。其实作用域链简单说来也好理解,如下代码:

        var x = 10;
function fn() {
var y = 20;
return function () {
var z = 30
console.log(x + y + z);
}
}

上面代码中,如果想要打印 x+y+z 的值,就必须要遍历三个层次的上下文环境或者作用域,这其实和原型链的结构表现形式类似。但要细细将来,连同闭包图文并茂的说明白,需要很多内容。

此处不再深入进去,以后有机会再另起一篇详细介绍。

3. 二维链查找

上文讲到通过作用域练向上查找变量,实际在查找变量的过程中,是使用“二维链查找”——“作用域链” + “原型链”。看如下代码:

       Object.prototype.x = 10;
function fn() {
var y = 20;
return function () {
var z = 30
console.log(x + y + z);
}
}

这份代码跟上文中演示作用域链的代码差不多,但是它却通过 Object.prototype.x = 10; 这么一句话,表现出了原型链在其中的作用。
因此,在查找变量值时,是同时兼顾原型链和作用域链两个方向的,即“二维链查找”。

4. 独立作用域只能通过函数来创建

这句话的下半句是——不能通过if/for等语句块来创建。后半句大家可能知道,但是它的本质确实前半句——独立作用域只能通过函数来创建(除了独立作用域之外,剩下的就是全局作用域)。既然独立作用域只能通过函数来创建,那么函数中任何地方的*变量就都是函数层级的,因此,以下代码希望不要再次出现:

js便签笔记(12)——浏览TOM大叔博客的学习笔记 part2

5. 隐式全局变量的本质

var a = 10;
b = 20;

以上两句代码,看似都是声明两个全局变量,但是按照TOM大叔说的,只有var才能声明一个变量,也就是 var a = 10; 是真正的声明变量。

而下一句 b = 20,其实是相当于设置window的一个属性值而已。

因此,第一句的本质是声明一个全局变量;第二句的本质是设置window的一个属性值。

当然,不推荐用第二句的形式。

6. 函数声明和函数表达式的不同

js定义函数的方法有多种,但看看以下这段代码:

fn();
var fn = function() { //函数表达式
alert(123); // 报错
}
//------
fn();
function fn() { //函数声明
alert(123); //
}

两种函数定义方式,却得出不一样的结果。

此处我当时没有详细看,因为这样使用的情况不是很多,所以就没有过深入的细看,只是做了个标记。如果有了解的朋友,不放解释一下。

7.js使用静态作用域

在part1中讲过,当一个函数作为参数被传入,后者作为一个值被返回的时候,连同它一块被传递的,是它的作用域。也就是咱们常说的闭包。且看如下代码:

var x = 10;
function foo() {
alert(x);
}
(function (funarg) {
var x = 20;
funarg(); // 10, 不是20
})(foo);

foo是一个函数,把它作为参数传入进另一个函数中执行,连同一起传递的,是foo的作用域。而foo使用的是静态作用域,其中的变量x在传递的时候已经被静态赋值,不会受其他环境下x变量的影响。
这个道理也同样适用于函数作为返回值。如下:

function fn() {
var x = 10;
return function () {
alert(x);
}
}
var ret = fn();
var x = 20;
ret(); // 10,不是20

更多内容请关注我的微博

上一篇:Django之组合搜索组件(二)--另附simple_tag的创建使用方法


下一篇:yolo