引言
前面两篇文章介绍了上下文、作用域、闭包、this。这里我精心挑选了一些特别经典的面试题(不定期更新,跪求收藏)。相信通过这些题目能让你完全通关JS三座大三中的之一。
闭包组:
这类题目还是挺简单的,我总结了几个要注意的地方
1.有没有闭包
2.如果有闭包,看创建了几个闭包。换句话说,是在一个闭包内直接操作还是操作完一个闭包,再创建一个新的闭包继续操作
3.注意数据的归属,即数据存放在哪个上下文环境
1、
var n=0;
function a(){
var n=10;
function b(){
n++;
console.log(n);
}
b();
return b;
}
var c=a();
c();
console.log(n);
//11 12 0
2、
var a=9;
function fn(){
a=0; //如果这里是var a = 0 ,答案是多少
return function(b){
return b+a++;
}
}
var f=fn();
console.log(f(5));
console.log(fn()(5));
console.log(f(5));
console.log(a);
// 5 5 6 2
// 如果是var a = 5 5 6 9
3、
var ary=[1,2,3,4];
function fn(ary){
ary[0]=0;
ary=[0];
ary[0]=100;
return ary;
}
var res=fn(ary);
console.log(ary);
console.log(res);
// [0,2,3,4] [100]
4、
function fn(i) {
return function (n) {
console.log(n + (i++));
}
}
var f = fn(10);
f(20);
fn(20)(40);
fn(30)(50);
f(30);
//30 60 80 41
5、
var i = 10;
function fn() {
return function (n) {
console.log(n + (++i));
}
}
var f = fn();
f(20);
fn()(20);
fn()(30);
f(30);
//31 32 43 44
6、以下代码的功能是要实现为5个input按钮循环绑定click点击事件,绑定完成后点击1、2、3、4、5五个按钮分别会alert输出0、1、2、3、4五个字符。(腾讯)
请问如下代码是否能实现?
如果不能实现那么现在的效果是什么样的?
应该做怎样的修改才能达到我们想要的效果,并说明原理?
<div id="btnBox">
<input type="button" value="button_1" />
<input type="button" value="button_2" />
<input type="button" value="button_3" />
<input type="button" value="button_4" />
<input type="button" value="button_5" />
</div>
<script type="text/javascript">
var btnBox=document.getElementById('btnBox'),
inputs=btnBox.getElementsByTagName('input');
var l=inputs.length;
for(var i=0;i<l;i++){
inputs[i].onclick=function(){
alert(i);
}
}
</script>
1.不能实现
2.因为js没有块作用域,所以公用的外层作用域的i,当点击触发函数的时候 ,应当注意外层的i是5了,所以全部打印5没毛病
3.
解决思路1:没有块作用域我就用es6的let形成块作用域
for(let i=0;i<l;i++){
inputs[i].onclick=function(){
alert(i);
}
}
解决思路2:每次绑定的时候i其实都是正确的,我能不能用另外一个变量将每次的i存起来呢?
//这样行吗?
for(var i=0;i<l;i++){
inputs[i].onclick=function(){
var num = i
alert(num);
}
}
//这样还是不行,因为回调函数定义的时候并不会执行,所以当var num = i 执行的时候i已经等于5了
那么我应该让回调函数定义的时候里面的代码能立即执行,接收到参数0,1,2,3,4
for(var i=0;i<l;i++){
inputs[i].onclick=(function(){
var num = i
alert(num);
})(i)
}
//这样也有问题i传递进去了,但是里面核心代码定义也执行了,我想让它点击的时候再执行
for(var i=0;i<l;i++){
inputs[i].onclick=(function(){
var num = i
return function (e) { //注意这个时候e是啥,是点击的事件
console.log(num)
}
})(i)
} //这样就没毛病了,返回一个方法,不会立即执行,i传进去了,给了num,由于有闭包,又不会被销毁
还能怎么优化?既然i能传进去,我为啥还要而外用个变量保存呢?
for(var i=0;i<l;i++){
inputs[i].onclick=(function(x){//x是形参,由于闭包存在,上下文不销毁
return function () {
console.log(x)
}
})(i)
}
this组:
这类题目严格按上篇文章的分析思路,不复杂,就是麻烦一点。不要在脑子里想,每步的结果用纸和笔演算下
1、
var num = 10;
var obj = {num: 20};
obj.fn = (function (num) {
this.num = num * 3;
num++;
return function (n) {
this.num += n;
num++;
console.log(num);
}
})(obj.num);
var fn = obj.fn;
fn(5);
obj.fn(10);
console.log(num, obj.num);
//22 23 65 30
let length = 20
let obj = {
length: 100,
sayHi() {
console.log(this.length)
}
}
obj.sayHi()
const fn = obj.sayHi
fn()
const arr = [obj.sayHi,2,3,4,5,6]
arr[0]()
// 100 undefined 6
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。