1、考察this
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1);
输出:10 2
第一次输出10应该没有问题。我们知道取对象属于除了点操作符还可以用中括号,所以第二次执行时相当于arguments调用方法,this指向arguments,而这里传了两个参数,故输出arguments长度为2。
2、var和函数的提前声明
function fn(a) {
console.log(a);
var a = 2;
function a() {}
console.log(a);
}
fn(1);
输出:function a() {} 2
我们知道var和function是会提前声明的,而且function是优先于var声明的(如果同时存在的话),所以提前声明后输出的a是个function,然后代码往下执行a进行重新赋值了,故第二次输出是2。
3、变量隐式声明
if('a' in window) {
var a = 10;
}
alert(a);
答案:10
前面我说过function和var会提前声明,而其实{...}内的变量也会提前声明。于是代码还没执行前,a变量已经被声明,于是 'a' in window 返回true,a被赋值。(这里要特别注意的是,只是声明提前,赋值还是在原来的地方)
4、函数声明优于变量声明
console.log(typeof fn);
function fn() {};
var fn;
答案:function
因为函数声明优于变量声明。我们知道在代码逐行执行前,函数声明和变量声明会提前进行,而函数声明又会优于变量声明,这里的优于可以理解为晚于变量声明后,如果函数名和变量名相同,函数声明就能覆盖变量声明。所以以上代码将函数声明和变量声明调换顺序还是一样结果。
5、实现如下语法的功能:var a = (5).plus(3).minus(6); //2
Number.prototype.plus = function(a) {
return this + a;
};
Number.prototype.minus = function(a) {
return this - a;
};
var a = (5).plus(3).minus(6);
console.log(a); // 2
直接在Number对象上加扩展方法即可,传说中这样很不好,but我也想不到更好的办法了...
6、实现如下语法的功能:var a = add(2)(3)(4); //9
function add(a) {
var temp = function(b) {
return add(a + b);
}
temp.valueOf = temp.toString = function() {
return a;
};
return temp;
}
var ans = add(2)(3)(4);
console.log(ans); // 9
对valueOf和toString的考察,具体可以参考《valueOf和toString》
6-1、写一个 sum 方法,使得以上代码得到预期结果
console.log(sum(2,3)); // Outputs 5
console.log(sum(2)(3)); // Outputs 5
function sum(x) {
if (arguments.length == 2) {
return arguments[0] + arguments[1];
} else {
return function(y) { return x + y; };
}
}
或者这样
function sum(x, y) {
if (y !== undefined) {
return x + y;
} else {
return function(y) { return x + y; };
}
}
7、以下代码的输出是什么?
var a={},
b={key:'b'},
c={key:'c'};
a[b]=123;
a[c]=456;
console.log(a[b]);
一道有趣的题目,答案是 456。
我们知道,Javascript 中对象的 key 值,一定会是一个 string 值,如果不是,则会隐式地进行转换。当执行到 a[b]=123] 时,b 并不是一个 string 值,将 b 执行 toString() 方法转换(得到 “[object Object]“),a[c] 也是相同道理。所以代码其实可以看做这样执行:
var a={},
b={key:'b'},
c={key:'c'};
// a[b]=123;
a["[object Object]"]=123;
// a[c]=456;
a["[object Object]"]=456;
console.log(a["[object Object]"]);
8、以上代码可能会由于递归调用导致栈溢出,如何规避这个问题?
var list = readHugeList();
var nextListItem = function() {
var item = list.pop();
if (item) {
// process the list item...
nextListItem();
}
};
首先,任何递归都可以用迭代来代替,所以改写成迭代方式肯定没有问题。
var list = readHugeList();
var nextListItem = function() {
var item = list.pop();
if (item) {
// process the list item...
setTimeout( nextListItem, 0);
}
};
利用 setTimeout 的异步性质,完美地去除了这个调用栈。
如果你还是摸不着头脑,简单举个栗子:
var list = [0, 1];
var nextListItem = function() {
var item = list.pop();
if (item) {
nextListItem();
}
console.log(item);
};
nextListItem();
上面的代码会依次输出 0 和 1,因为程序中形成了一个调用栈,1 被压到了栈底,最后出栈。
把程序改成这样:
var list = [0, 1];
var nextListItem = function() {
var item = list.pop();
if (item) {
// process the list item...
setTimeout( nextListItem, 0);
}
console.log(item);
};
nextListItem();
这回就是 1 和 0 了,因为 setTimeout 的回调只有当主体的 js 执行完后才会去执行,所以先输出了 1,自然也就没有栈这一说法了。
事实上,并不是所有递归都能这样改写,如果下一次递归调用依赖于前一次递归调用返回的值,就不能这么改了。
9、以下代码输出什么?
console.log(1 + "2" + "2");
console.log(1 + +"2" + "2");
console.log(1 + -"1" + "2");
console.log(+"1" + "1" + "2");
console.log( "A" - "B" + "2");
console.log( "A" - "B" + 2);
+”2″ 能将字符串 “2″ 转换成整数 2,-”2″ 同理,而两个变量进行 “+” 运算时,如果都是数字和字符串,则分别进行数字相加和字符串拼接,如果一个是数字一个是字符串,则将数字转为字符串,如果是 “-” 运算呢?则将字符串转为数字。
“A” – “B” 会返回 NaN,因为 “A” 和 “B” 无法转成数字进行运算,这里不要以为 “A” 和 “B” 能转为 ASCII码 进行运算(不要和 C 语言搞混了)。而 NaN 和字符串相加,会转成 “NaN” 和字符串去拼接,NaN 和任何数字相加结果还是 NaN。
本网刊登的文章均仅代表作者个人观点,并不代表本网立场。文中的论述和观点,敬请读者注意判断。
本文地址:http://www.xlkjgs.com/notes/js/3075.html