空话不多说,直接看题目,先不要急着看答案 先本身思索,收成更多
(历久补仓);
一
var out = 25,
inner = {
out: 20,
func: function () {
var out = 30;
return this.out;
}
};
console.log((inner.func, inner.func)());
console.log(inner.func());
console.log((inner.func)());
console.log((inner.func = inner.func)());
25,20,20,25
代码剖析:这道题的考点分两个
1.作用域
2.运算符(赋值预算,逗号运算)
先看第一个输出:25,由于(inner.func, inner.func)是举行逗号运算符,逗号运算符就是 运算前面的,
返回末了一个,举个栗子
var i=0,j=1,k=2;
console.log((i++,j++,k))//返回的是k的值 2 ,假如写成k++的话 这里返回的就是 3
console.log(i);//1
console.log(j);//2
console.log(k);//2
回到原题(inner.func, inner.func)就是返回inner.func而inner.func只是一个匿名函数
function () {
var out = 30;
return this.out;
}
而且这个匿名函数是属于window的
则变成了
(function () {
var out = 30;
return this.out;
})()
现在的this--》window
所以out 是25
第二和第三个console.log的作用域都是 foo,也就是他们实行的现实上是
foo.func();
foo作用域中是有out变量的,所以结果是20
第四个console.log
考核的是一个等号运算inner.func = inner.func 实在返回的是运算的结果,
举个栗子
var a=2,b=3;
console.log(a=b)//输出的是3
所以inner.func = inner.func 返回的也是一个匿名函数
function () {
var out = 30;
return this.out;
}
现在 原理就和第一个console.log一样了 输出的结果是 25
二
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("b" in window);
var b;
此时,只管声明是在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。
提早这个词语显得有点疑惑了,你能够明白为:预编译。
三
var a = 1;
var 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了。
四
function a(x) {
return x * 2;
}
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 对象
六
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]就很轻易明白了。