今天刚做完网易校招的前端笔试题,总体难度不算很难,有送分题也有拉分题,不过大公司的笔试算法题占比最大,整套笔试题的题型与分值分布分别是:单选题40分共20题、编程题60分共3题、问答题20分共2题,是牛客网的笔试。
遇到一道比较坑的单选题,在此记录一下。
以下代码执行时console.log的结果是:
1 var obj = { 2 x: 1, 3 xyz: function () { 4 with(this) { 5 function con () { 6 console.log(x); 7 console.log(this.x); 8 } 9 var x = 2; 10 (function() { 11 con() 12 })() 13 con.call(this) 14 } 15 } 16 } 17 18 obj.xyz()
执行结果:
要理解这道题就必须搞懂每一个this指向的是什么,所以我们可以把对应的各个this打印出来分析一波
1 var obj = { 2 x: 1, 3 xyz: function () { 4 console.log(\'1\', this) 5 with(this) { 6 function con () { 7 console.log(\'2\', this) 8 console.log(x); 9 console.log(this.x); 10 } 11 var x = 2; 12 console.log(\'3\', this); 13 (function() { 14 con() 15 })() 16 con.call(this) 17 } 18 } 19 } 20 21 obj.xyz()
执行结果如下:
从执行顺序分析,1号this打印出来的是obj对象,也就是说with传进去的是obj对象,在with代码块里,首先声明了con函数,然后再执行了var x=2;这一段代码,而with修改了词法作用域,把with代码块里的上下文改为obj对象,那么这段代码等同于obj.x = 2,即把obj对象里的x属性修改为2,接着打印了3号this,值为obj对象,验证了with代码块的上下文是obj对象。接着执行了一个立即执行函数,函数里调用了con函数。在《你不知道的JavaScript上卷》第2章里有提到函数里this的绑定取决于函数的调用方式,而于函数声明的位置无关,this的绑定规则有四个:默认绑定(独立函数调用)、隐式绑定(obj.foo())、显示绑定(call()和apply())和new绑定。显然,立即执行函数里直接调用con函数,属于默认绑定,默认绑定this会指向全局对象(window或global),所以第9行console.log(this.x)打印的是window.x,而全局对象window中并没有定义x,因此打印出undefined,而第8行console.log(x)打印的是当前词法作用域里的x,即为obj.x,打印出2。接着分析第16行代码con.call(this)相当于con.call(obj),显然,使用call()方法调用con函数,显示绑定this指向obj,所以第9行console.log(this.x)打印的是obj.x,即为2,然后第8行同理打印的是当前词法作用域里的x。如此分析一波,这道题的答案就很清晰明了了。