【转】你确实明白JavaScript了么

来自 So, you think you know
JavaScript?
— 著名前端架构师Baranovskiy

  • 题目1

    var a = ‘he’;

    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);
    求不要借助任何帮助工具,心算答案。答案于底下。

答案

题目1

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

代码含义:如果window不包含属性a,就宣称一个变量a,然后赋值为1。
公恐怕认为alert出来的结果是1,然后实际结果是“undefined”。要打听怎么,需要理解JavaScript里之3单概念。
先是,所有的全局变量都是window的习性,语句 var a = 1;等价于window.a = 1;
你可就此如下方式来检测全局变量是否声明:

"变量名称" in window

第二,所有的变量声明还以界定作用域的顶部,看一下一般之事例:

alert("a" in window);
var a;

此刻,尽管声明是当alert之后,alert弹出底照样是true,这是因JavaScript引擎首先会扫墓所有的变量声明,然后拿这些变量声明移动及顶部,最终的代码效果是这么的:

var a;
alert("a" in window);

这么看起就是够呛容易解释为何alert结果是true了。
老三,你用掌握该问题之意思是,变量声明被提前了,但变量赋值没有,因为当时行代码包括了变量声明和变量赋值。
公可以以讲话拆分为如下代码:

var a;    //声明
a = 1;    //初始化赋值

当变量声明与赋值在联合从而的上,JavaScript引擎会自行将它分成两部以便将变量声明提前,不将赋值的手续提前是以他生或影响代码执行出不可预料的结果。
用,知道了这些概念之后,重新回头看一下题目之代码,其实就等价于:

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

然,题目之意就是格外理解了:首先声明a,然后判断a是否在有,如果不存就赋值为1,很明显a永远在window里在,这个赋值语句永远不见面执行,所以结果是undefined。
超前之词语显得略微迷惑了,你得理解啊:预编译。

  • 题目2

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

是题目看起较实际复杂,alert的结果是1;这里还时有发生3单重点的定义需要我们领略。
率先,在问题1里我们了解了变量声明在进入实施上下文就完事了;第二只概念就是函数声明也是提前的,所有的函数声明还于实践代码之前还已做到了声明,和变
计量声明一样。澄清一下,函数声明是之类这样的代码:

function functionName(arg1, arg2){
    //函数体
}

正如不是函数,而是函数表达式,相当给变量赋值:

var functionName = function(arg1, arg2){
    //函数体
};

弄清一下,函数表达式没有提前,就一定给平常的变量赋值。
其三需知道之凡,函数声明会覆盖变量声明,但无会见盖变量赋值,为了诠释这,我们来拘禁一个事例:

function value(){
    return 1;
}
var value;
alert(typeof value);    //"function"

尽快变量声明在下面定义,但是变量value依然是function,也就是说这种状况下,函数声明的先期级高于变量声明的优先级,但要是该变量value赋值了,那结果虽了无平等了:

function value(){
    return 1;
}
var value = 1;
alert(typeof value);    //"number"

该value赋值以后,变量赋值初始化就蒙了函数声明。
重赶回题目,这个函数其实是一个发生名函数表达式,函数表达式不像函数声明一样可挂变量声明,但若可以小心到,变量b是带有了该函数表达式,而拖欠函数表达式的讳是a;不同的浏览器对a这个名词处理多少不同等,在IE里,会拿a认为函数声明,所以它们深受变量初始化覆盖了,就是说如果调用a(–x)的言语就会见错,而别浏览器在兴在函数内部调用a(–x),因为此时候a在函数外面还是数字。基本上,IE里调用b(2)的早晚会拧,但其他浏览器虽然返回undefined。
懂得上述内容后,该问题换成一个再次准和重爱懂的代码应该像这么:

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

这样的话,就够呛清晰地知道干什么alert的连日1了。

  • 题目3

function a() {
    return 1 ;
}
var a;
alert(a);

其一题材比较简单:即函数声明与变量声明的干和影响,遇到同名的函数声明,不见面再度定义

  • 题目4

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

有关这题目,ECMAsCRIPT 262-3之科班来分解的。
移动对象是当进函数上下文时刻给创造的,它通过函数的arguments属性初始化。arguments属性的值是Arguments对象.
有关 Arguments对象的切实定义,看这里:ECMAScript arguments 对象

  • 题目5

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

其一题材可以说凡是不过简便易行的,也是无比怪异的!关于这个题目,我们先行来询问2独概念。
是题目根本考察 Javascript 的 this 关键字,具体看这里:
有关Javascript语言中this关键字的用法

有关 a.call(null);
根据ECMAScript262标准规定:如果第一个参数传入的目标调用者是null或者undefined的话语,call方法以把全局对象(也尽管是window)作为this的值。所以,不管你啊时传出null,其this都是大局对象window,所以该问题可以清楚成如下代码:

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

故而弹出的结果是[object Window]就是大容易了解了。

—————
总结:
立刻5个问题虽然一般有些偏,但实际上考察之还是基本概念,只有熟知了这些基本概念才会写来大质量代码。

var a = 'hello'

[TOC]