不积跬步之this输出题(15道详细解析版)

2022-03-21  本文已影响0人  雨飞飞雨

卷完Promise咱们继续卷this

关于this的输出题,无非是考察什么可以改变this的指向.我们知道有四种方式:

  1. 函数默认执行 执行window.也就是什么都不做直接执行
  2. 对象调用函数,会隐式绑定把this指向对象
  3. 显示绑定,通过call,apply,bind,会指向输入的参数,如果不输入参数,则默认绑定为window
  4. 通过new操作符来绑定this.

它们的优先级是:

new绑定 > 显式绑定 > 隐式绑定 > 默认绑定。

还有一个考察的知识点就是箭头函数.它的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
  1. 函数被对象调用,隐式绑定this
  2. 通过作为构造函数调用,这个构造函数在执行初始化的时候并没有这个属性.

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绑定 > 显式绑定 > 隐式绑定 > 默认绑定。

上一篇下一篇

猜你喜欢

热点阅读