你自认为理解了JavaScript?

一. 题目

英文原文地址:http://dmitry.baranovskiy.com/post/91403200

其中有五段小代码,用来测试是否理解 JavaScript 的核心(core),闭包(closures)和作用域(scopes)。先尝试回答每段代码中alert语句的结果,然后再作实践检查。

if (!("a" in window)) {
    var a = 1;
}
alert(a);

第一题解析

var a = 1,
    b = function a(x) {
        x && a(--x);
    };
alert(a);

第二题解析

function a(x) {
    return x * 2;
}
var a;
alert(a);

第三题解析

function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
}
b(1, 2, 3);

第四题解析

function a() {
    alert(this);
}
a.call(null);

第五题解析

二. 解析

解析参考:http://bbs.csdn.net/topics/390300541 

第一题解析:

首先会解析所有函数,其次是var声明的变量,但是不会赋值。因为JavaScript没有块(block)的概念。像for(var i in array)这里的i依然是全局变量,这点非常的不同于Java。因此,这几行的代码执行顺序是:

  1. var a; // 声明一个变量,但是不会赋值!
  2. if...语句:因为步骤1已经定义了a变量(没赋值),所以"a" in window为真,取反为假。所以不会执行大括号里面的赋值语句。
  3. alert(a); // 显然,结果为undefined


第二题解析:
我们可以用多个逗号将变量分开定义,只用一个var。另外函数表达式类似于局部变量,不会被全局作用域中访问到。执行步骤:

  1. 声明两个局部变量(因为有var限定符)a,b;并给他们赋值a=1,b=function a(){...};这里的function a是局部变量,外部无法访问到。
  2. alert(a); // 结果为1


第三题解析:

JavaScript永远是先解析声明式函数,再解析变量。所以,它的执行顺序为:

  1. 解析函数a;
  2. 声明变量var a;因为a此时没有被赋值,所以它还是指向原来的值。即function a;
  3. alert(a); // 那就是function a(x){...}


第四题解析:

在函数内部可以引用一个对象,它是arguments类似数组,但不是数组。它代表了函数实际接收参数的集合。可以通过下标对相应参数进行访问。如果修改此对象某些属性,如arguments[index],则被传进来的第index(如果有的话,下标从0开始)变量的值也会被修改。它的执行顺序为:

  1.  声明一个函数b;
  2.  执行函数b(1,2,3);因为这里arguments[2]与变量a引用的是一个值,所以当arguments[2]改变时,a也随之改变。结果为10。

注意1:形参优先级高于arguments

function fn(arguments){
    alert(arguments);
}
fn('hello'); // -> "hello"

注意2:在JavaScript中如果定义了2个或2个以上的相同名字的函数,则只有最后定义的函数才有效。

function b(x, y, a) {
    arguments[2] = 10;
    alert(x);
}
function b(x, y, a, b) {
    arguments[2] = 10;
    alert(y);
}
b(1, 2, 3); // -> 2


第五题解析:

call方法接受多个参数,其作用是借用别人的方法当作自己的方法。这样能保证执行的时候this能够指向自己。

call方法的第二个参数到最后一个参数是传给借用过来函数的。第一个参数是借用的对象,如果这个对象为空,那么将会作为全局window对象调用。即函数中的this指向window,结果为[object Window]。

经验:a()/a.call()/a.call(null)无区别。

posted @ 2013-09-22 12:00  那些年的事儿  阅读(258)  评论(0编辑  收藏  举报