你真的已经搞懂JavaScript了吗?

你真的已经搞懂JavaScript了吗?

著名前端架构师Baranovskiy的博客一个帖子《So, you think you know JavaScript?javascript

 

题目一:前端

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

 

题目二:java

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);

请不要借助任何帮助工具,心算答案。答案在下面。工具

.post

.this

.spa

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

答案:

题目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个题目虽然貌似有点偏,但实际上考察的依然是基本概念,只有熟知了这些基本概念才能写出高质量代码。

 

大体就这些,抛砖引玉。

相关文章
相关标签/搜索