不积跬步之this输出题(15道详细解析版)
卷完Promise咱们继续卷this
关于this
的输出题,无非是考察什么可以改变this
的指向.我们知道有四种方式:
- 函数默认执行 执行
window
.也就是什么都不做直接执行 - 对象调用函数,会隐式绑定把this指向对象
- 显示绑定,通过
call,apply,bind
,会指向输入的参数,如果不输入参数,则默认绑定为window
- 通过
new
操作符来绑定this
.
它们的优先级是:
new绑定 > 显式绑定 > 隐式绑定 > 默认绑定。
还有一个考察的知识点就是箭头函数.它的this
由定义它的结构代码时父级执行上下文决定的
- 如果是在全局环境,或者是在一个对象里,它的父级执行上下文就是全局环境,它的this就指向了window
- 如果它的外部是一个函数,那么它的this就指向了函数的执行上下文.而函数的执行上下文就是活的.取决于调用时的情况.也就上面列举的四种情况.
1.代码输出结果
function foo() {
console.log( this.a );
}
function doFoo() {
foo();
}
var obj = {
a: 1,
doFoo: doFoo
};
var a = 2;
obj.doFoo()
结果为:
2
在this绑定中有一个隐式绑定是 如果用对象来调用函数,那么这个对象的this就是指向这个对象.
但是这里我们嵌套了一层,在doFoo的时候,实际上它的上下文中还是window.
所以是2
2.代码输出结果
var a = 10
var obj = {
a: 20,
say: () => {
console.log(this.a)
}
}
obj.say()
var anotherObj = { a: 30 }
obj.say.apply(anotherObj)
输出结果:
10
10
这个结果我很意外.
我 以为应该是20 20
箭头函数时不绑定this的.它的this来自原父级所处的执行上下文里.,所以首先会打印全局中的 a 的值10。后面虽然让say方法指向了另外一个对象,但是仍不能改变箭头函数的特性,它的this仍然是指向全局的,所以依旧会输出10。
箭头函数的this
取决于它父级所处的执行上下文.对象可不算是执行上下文.只有全局上下文和函数上下文.
所以箭头函数这里的上下文就是全局上下文.
如果想要箭头函数输出20 ,那么就给它换一个上下文好了.
var a = 10
var obj = {
a: 20,
say:function (){
let conso =()=>{
console.log(this.a)
}
conso();
}
}
obj.say()
var anotherObj = { a: 30 }
obj.say.apply(anotherObj)
20
30
这样上下文就换成了函数的执行上下文了,而函数的执行上下文的this却是可以动态决定的.在对象里会隐形绑定对象的this.
在apply
的时候则换成了传入的对象.
3.代码输出结果
function a() {
console.log(this);
}
a.call(null);
打印结果:window对象
根据ECMAScript262规范规定:如果第一个参数传入的对象调用者是null或者undefined,call方法将把全局对象(浏览器上是window对象)作为this的值。所以,不管传入null 还是 undefined,其this都是全局对象window。所以,在浏览器上答案是输出 window 对象。
要注意的是,在严格模式中,null 就是 null,undefined 就是 undefined:
'use strict';
function a() {
console.log(this);
}
a.call(null); // null
a.call(undefined); // undefined
4.代码输出结果
var obj = {
name: 'cuggz',
fun: function(){
console.log(this.name);
}
}
obj.fun() // cuggz
new obj.fun() // undefined
- 函数被对象调用,隐式绑定this
- 通过作为构造函数调用,这个构造函数在执行初始化的时候并没有这个属性.
5.代码输出结果
var obj = {
say: function() {
var f1 = () => {
console.log("1111", this);
}
f1();
},
pro: {
getPro:() => {
console.log(this);
}
}
}
var o = obj.say;
o();
obj.say();
obj.pro.getPro();
输出为:
1111 window对象
1111 obj对象
window对象
解析:
我们分开来看,第一个f1
的箭头函数在编译的时候就已经确定,它的this
是绑定的外面函数的执行上下文的this
.而函数的this
它就是活的了.
如果是在外面调用,就是window
如果是对象调用,就是对象
而下面的getPro
在编译的时候绑定的是全局上下文中的this
.所以它的值应该是window
6.代码输出结果
var myObject = {
foo: "bar",
func: function() {
var self = this;
console.log(this.foo);
console.log(self.foo);
(function() {
console.log(this.foo);
console.log(self.foo);
}());
}
};
myObject.func();
输出结果为:
bar bar undefined bar
解析:
1.func
是被对象myObject
调用的,所以它的this
指向了myObject
,所以打印了两个bar
2.在函数中我们建立了变量self
,然后里面的立即执行函数引用了self
,形成了一个闭包.所以里面的self.foo
也打印了bar
3.而立即执行函数的this
,它又指向哪里呢? 它那里也没有靠啊,所以window.
但是window
有没有这个foo的属性.
所以是undefined
.
7.代码输出结果
window.number = 2;
var obj = {
number: 3,
db1: (function(){
console.log(this);
this.number *= 4;
return function(){
console.log(this);
this.number *= 5;
}
})()
}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number);
console.log(window.number);
输出结果:
15
40
考察点:this
的指向.
1.第一个立即执行函数里面的this
当然是指向window
.所以先变成了8
2.接着返回一个函数.这个函数还是单独调用.所以又指向了widnow.变成了40
3.接着是对象调用.这个时候是this指向了对象,所以是15
8.代码输出结果
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
解析:
1.第一个fn()指向window对象.输出为10
2.第二次执行arguments0,相当于arguments调用方法,this指向arguments,而这里传了两个参数,故输出arguments长度为2。
9.代码输出结果
var a = 1;
function printA(){
console.log(this.a);
}
var obj={
a:2,
foo:printA,
bar:function(){
printA();
}
}
obj.foo();
obj.bar();
var foo = obj.foo;
foo();
输出结果:
2
1
1
解析:
1.var 声明的变量会被当做window的属性
2.obj.foo()直接隐式绑定了对象
3.oob.bar()的调用,它里面的printA被直接单独调用.所以和谁都没有关系.
指向了window.
4.最后的foo又单独调用.离开了隐式绑定,所以也是window
10.代码输出结果
var x = 3;
var y = 4;
var obj = {
x: 1,
y: 6,
getX: function() {
var x = 5;
return function() {
return this.x;
}();
},
getY: function() {
var y = 7;
return this.y;
}
}
console.log(obj.getX()) // 3
console.log(obj.getY()) // 6
输出结果:
3
6
解析:
1.函数里面在调用一次函数,那么里面的函数的this指向就完全和外面的没有关系了,及时你把外面的改了,它也还是window,所以指向的是3
2.对象隐式绑定,没有上面的花里胡哨.直接就是6
11.代码输出结果
var a = 10;
var obt = {
a: 20,
fn: function(){
var a = 30;
console.log(this.a)
}
}
obt.fn();
obt.fn.call();
(obt.fn)();
输出:
20
10
20
解析:
call函数在不传如参数的时候,指向的是window
12.代码输出结果
function a(xx){
this.x = xx;
return this
};
var x = a(5);
var y = a(6);
console.log(x.x) // undefined
console.log(y.x) // 6
解析:
1.最关键的就是var x = a(5),函数a是在全局作用域调用,所以函数内部的this指向window对象。所以 this.x = 5 就相当于:window.x = 5。之后 return this,也就是说 var x = a(5) 中的x变量的值是window,这里的x将函数内部的x的值覆盖了。然后执行console.log(x.x), 也就是console.log(window.x),而window对象中没有x属性,所以会输出undefined。
2.当指向y.x时,会给全局变量中的x赋值为6,所以会打印出6。
13.代码输出结果
function foo(something){
this.a = something
}
var obj1 = {
foo: foo
}
var obj2 = {}
obj1.foo(2);
console.log(obj1.a); // 2
obj1.foo.call(obj2, 3);
console.log(obj2.a); // 3
var bar = new obj1.foo(4)
console.log(obj1.a); // 2
console.log(bar.a); // 4
输出结果: 2 3 2 4
解析:
1.首先执行obj1.foo(2); 会在obj中添加a属性,其值为2。之后执行obj1.a,a是右obj1调用的,所以this指向obj,打印出2;
2.执行 obj1.foo.call(obj2, 3) 时,会将foo的this指向obj2,后面就和上面一样了,所以会打印出3;
3.obj1.a会打印出2;
4.最后就是考察this绑定的优先级了,new 绑定是比隐式绑定优先级高,所以会输出4。
14.代码输出结果
function foo(something){
this.a = something
}
var obj1 = {}
var bar = foo.bind(obj1);
bar(2);
console.log(obj1.a); // 2
var baz = new bar(3);
console.log(obj1.a); // 2
console.log(baz.a); // 3
输出: 2 2 3
这道题目和上面题目差不多,主要都是考察this绑定的优先级。记住以下结论即可 :this绑定的优先级: new绑定 > 显式绑定 > 隐式绑定 > 默认绑定。