一些js题




Code One
if (!("a" in window)) {
var a = 1;
}
alert(a);
这个奇怪的代码似乎是这样: “如果window 没有属性 a , 定义一个变量 a 并且赋值1”, 你可能会认为应该alert 1。 实际上,alert的是”undefined”。 为了理解发生了什么,你应该知道JavaScript的四件事。
首先, 所有的全局变量都是window的属性。  var a = 1  完全等价于 window.a = 1
第二, 所有的变量声明都会被提升(hositing)至所在作用域的顶部, 这个是JavaScript一大特性。看看,下面的这个例子
alert("a" in window);
var a;
上面的例子会alert出”true”即使变量声明在 alert() 之后。这是因为JavaScript引擎会首先扫描所有变量生命并把他们 hositing 至作用域顶部。上面那段代码相当于这样:
var a;
alert("a" in window);
第三件事你应该理解只有变量声明被hositing而变量初始化没有
var a = 1;
你可以拆分看待上面的代码
var a;
a = 1;
实际上JavaScript引擎也是这么做的, 当有变量声明并初始化,JavaScript会自动拆分变量声明和变量初始化。那为什么没有提升(hositing)变量初始化? 因为这样会影响变量值在代码执行期间,导致不可预料的结果。
最后一点是JavaScript Scoping, 很多新手不能理解甚至很多有经验的JavaScript程序员也不能完全理解scoping。JavaScript的scoping如此复杂原因是他看起来像C系语言的成员, 看看下面的C程序:
#include <stdio。h>
int main() {
int x = 1;
printf("%d", x); // 1
if (1) {
int x = 2;
printf("%d", x); // 2
}
printf("%d", x); // 1
}
上面输出的是 121 这是因为C系语言有 块级作用域(block-level scope) ,但JavaScript却不是这样。
var x = 1;
console.log(x); // 1
if (true) {
var x = 2;
console.log(x); // 2
}
console.log(x); // 2
上面console出 122 , 这是因为JavaScript是 函数级作用域(function-level scope) , 像if语句是不会创建新的作用域的。只有函数才会创建新的作用域。
如果你理解上面四点,那么上面的例子你肯定可以知道为什么alert的是”undefined”, 上述的代码实际上是这样执行的。
var a;
if (!("a" in window)) {
a = 1;
}
alert(a);
不难看出alert的是”undefined”, 声明了变量 a , 所有 !("a" in window) 的是结果是false; 变量声明了但是没有初始化, 所以alert “undefined”。
Code Two
var a = 1,
b = function a(x) {
x && a(--x);
};
alert(a);
这段代码看起来比实际上复杂得多。结果是alert “1”。 不用太困惑。同样的,这段代码需要你知道关于JavaScript的三件事。
首先, 变量声明提升。上一个例子已经讲过。第二个方面是函数声明提升。所有的函数声明同变量声明一样都会被提升至当前的作用域顶部。
很重要的一点是,一个函数声明如下:
function functionName(arg1, arg2) {
// function body
}
对应是函数表达式, 其实也就是变量初始化赋值。
var functionName = function(arg1, arg2) {
//function body
};
函数表达式并不会被提升。这其实也就是变量初始化。
第三点就是你必须知道和理解函数声明会覆盖了变量声明但没有覆盖变量初始化。为了理解这一点,看看下面的例子
function value() {
return 1;
}
var value;
alert(typeof value); // "function"
上面的 value 作为 function 而结束了,即使变量声明出现在函数声明之后。在这种情况下函数声明会获得更高的优先权。
但是下面的例子会有不同的结果。
function value() {
return 1;
}
var value = 1;
alert(typeof value); // "number"
现在 value 的值为1, 变量初始化覆盖的函数声明。
我们再看一个例子:
var a = 1;
function foo() {
a = 10;
return;
function a() {}
}
foo();
alert(a);
上面的例子会alert 1, 上面的这段代码实际执行是这样的,
var a;
function foo() {
function a() {}
a = 10;
return;
}
a = 1;
foo();
alert(a);
这样你应该就不难理解为什么会是1了吧。
回到Code Two, 那个函数实际上是函数表达式即使有函数名 a , 有名称的函数表达式并不会被认为是函数声明因此不会被覆盖变量声明。不过,你可能会发现包含函数表达式的变量是 b , 而函数表达式的名称是 a 。 不同浏览器会做不同的处理,IE会认为 function a() {} 是函数声明,因此它会被变量初始化覆盖,意味这当调用 a(--x) 是会抛出一个错误。其他浏览器允许在函数里调用 a(--x) 即使函数外部 a 的类型的number。 同时,在IE中调用 b(2) 会抛出一个error但是在其他浏览器中抛出 undefined
Code Two 可以简化为更加正确并容易理解的代码,如下:
var a = 1,
b = function(x) {
x && b(--x);
}
alert(a);
Code Three
function b(x, y, a) {
arguments[2] = 10;
alert(a);
}
b(1, 2, 3);
这段代码相对简单, 你只需回答是3, 或是 10。 ECMA-262, 3rd Edition, 10。1。8节解释关于 arguments 对象:
For each non-negative integer, arg, less than the value of the length property, a property is created with name ToString(arg) and property attributes { DontEnum }。 The initial value of this property is the value of the corresponding actual parameter supplied by the caller。 The first actual parameter value corresponds to arg = 0, the second to arg = 1, and so on。 In the case when arg is less than the number of formal parameters for the Function object, this property shares its value with the corresponding property of the activation object。 This means that changing this property changes the corresponding property of the activation object and vice versa。
简而言之, 每一个参数在 arguments 对象中都是一个同名的副本。也就是
arguments[0] 指向x,  arguments[1] 指向y, 而 arguments[2] 指向a。 当传入的参数是 b(1, 2, 3, 4) 时,  arguments[3] 没有指向那个变量,但是它的值为4。
显而易见,alert 的是10。
Code Four
var b = 5;
function a() {
var b = 10;
alert(this.b);
}
a.call(null);
你应该理解关于JavaScript的两个方面。
首先, 你应该理解 this 对象是什么。 看看下面的例子:
var object = {
method: function() {
alert(this === object);
}
}
object.method(); // true
在上面的代码中,  this 指向 object 对象, 所以结果是 true
在全局作用域中,  this 指向 window ,因此下面的 this 指向的则是 window
function method() {
alert(this === window); //true
}
method();
理解了第一点你才能理解第二点,  call() 是干嘛的。 通过 call() 可以重新定义函数的执行环境,即 this 的指向, 第一个参数将成为this的指向对象, 随后的参数将作为参数传入函数。
function method() {
alert(this === window);
}
method(); // true
method.call(document); // false
当执行 method.call(document) 时,  this 指向的将是 document
当传入函数为 null undefined 时会怎样呢?
If thisArg is  null  or  undefined , the called function is passed the global object as the this value。 Otherwise, the called function is passed ToObject(thisArg) as the this value。
所以此时传入的是 window
PS: 还有一个 apply() call() 类似,不过只有两个参数,第二参数应该是数组。
理解上面讲的,很容易就可以知道答案是 5


转载来自:
鲲鹏之志
http://youbookee.com/2016/08/30/js-you-should-know/

posted @   ·一库  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示