题目一:

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

大致就这些,抛砖引玉。

本文出自:http://julying.com/blog, 原文地址:http://julying.com/blog/so-you-think-you-know-javascript/, 感谢原作者分享。

你真的已经搞懂JavaScript了吗?的更多相关文章

  1. 来一轮带注释的demo,彻底搞懂javascript中的replace函数

    javascript这门语言一直就像一位带着面纱的美女,总是看不清,摸不透,一直专注服务器端,也从来没有特别重视过,直到最近几年,javascript越来越重要,越来越通用.最近和前端走的比较近,借此 ...

  2. 一张图彻底搞懂JavaScript的==运算

    一张图彻底搞懂JavaScript的==运算 来源 https://zhuanlan.zhihu.com/p/21650547 PS:最后,把图改了一下,仅供娱乐 : ) 大家知道,==是JavaSc ...

  3. 彻底搞懂Javascript的“==”

    本文转载自:@manxisuo的<通过一张简单的图,让你彻底地.永久地搞懂JS的==运算>. 大家知道,==是JavaScript中比较复杂的一个运算符.它的运算规则奇怪,容让人犯错,从而 ...

  4. 彻底搞懂JavaScript中的继承

    你应该知道,JavaScript是一门基于原型链的语言,而我们今天的主题 -- "继承"就和"原型链"这一概念息息相关.甚至可以说,所谓的"原型链&q ...

  5. 一张图带你搞懂Javascript原型链关系

    在某天,我听了一个老师的公开课,一张图搞懂了原型链. 老师花两天时间理解.整理的,他讲了两个小时我们当时就听懂了. 今天我把他整理出来,分享给大家.也让我自己巩固加深一下. 就是这张图: 为了更好的图 ...

  6. 一张图搞懂 Javascript 中的原型链、prototype、__proto__的关系 转载加自己的总结

    1. JavaScript内置对象 所谓的内置对象 指的是:JavaScript本身就自己有的对象 可以直接拿来就用.例如Array String 等等.JavaScript一共有12内置对象    ...

  7. 一张图轻松搞懂javascript event对象的clientX,offsetX,screenX,pageX区别

    总是会被javascript的event对象的clientX,offsetX,screenX,pageX 弄得头晕,于是决定做个图来区分一下(画得我手那个酸呀....) 先总结下区别: event.c ...

  8. 彻底搞懂javascript中的match, exec的区别

    在工作中经常发现一些同学把这两个方法搞混,以致把自己弄的很郁闷.所以我和大家一起来探讨一下这两个方法的奥妙之处吧. 我们分以下几点来讲解: 相同点: 1.两个方法都是查找符合条件的匹配项,并以数组形式 ...

  9. 五个小例子教你搞懂 JavaScript 作用域问题

    众所周知,JavaScript 的作用域和其他传统语言(类C)差别比较大,掌握并熟练运用JavaScript 的作用域知识,不仅有利于我们阅读理解别人的代码,也有助于我们编写自己的可靠代码. 下面笔者 ...

随机推荐

  1. erlang,elixir安装

    erlang下载地址:https://packages.erlang-solutions.com/erlang/ elixir(precompile版)下载地址:https://github.com/ ...

  2. asp.net web api添加统一异常处理

    1.自定义异常处理过滤器 /// <summary> /// 自定义异常处理过滤器 /// </summary> public class CustomExceptionFil ...

  3. 模糊测试(Fuzz testing)

    模糊测试(fuzz testing)是一种安全测试方法,他介于完全的手工测试和完全的自动化测试之间.为什么是介于那两者之间?首先完全的手工测试即是渗透测试,测试人员可以模拟黑客恶意进入系统.查找漏洞, ...

  4. Android开发工具全面转向Android Studio(3)——AS project/module的目录结构(与Eclipse对比)

    如果AS完全还没摸懂的,建议先看下Android开发工具全面转向Android Studio(2)——AS project/module的CRUD. 注:以下以Windows平台为标准,AS以目前最新 ...

  5. css 字间距、CSS字体间距、css 字符间距设置

    1.text-indent设置抬头距离css缩进 2.letter-spacing来设置字与字间距_字符间距离,字体间距css样式

  6. ng-init,ng-controller,ng-model

    1.ng-init 用于初始化数据,跟在$scope插入数据一样,但是在配合repeat指令时候比较有用: <div ng-repeat="arrOuter in arr" ...

  7. Flask备注三(Context)

    Flask备注三(Context) Flask支持不同的应用场景下,对应不同的local context(本地上下文环境),用来提供当前环境下的资源.lcoal context和全局变量以及局部变量最 ...

  8. DSP(1) -- 离散时间信号的序列类型

    1.单位采样序列δ(n):在MATLAB 中函数zeros(1,N)产生一个由N个零组成的列向量.它可用来实现有限区间的δ(n).然而,更高明的方法是利用逻辑关系式n==0来实现δ(n). 2.单位阶 ...

  9. IIS 的一些配置记录

    1.日志分析: URL:http://www.cnblogs.com/fish-li/p/3139366.html2.性能监视: 执行 perfmon.msc ,右键添加counter,添加web s ...

  10. 从多列的DataTable里取需要的几列(转)

    方法一: 也是广为人知的一种: YourDataTable.Columns.Remove("列名"); 但是这种情况只适合于去掉很少列的情况. 如果有很多列我却只要一两列呢,那就得 ...