美文网首页
不积跬步之this输出题(15道详细解析版)

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

作者: 雨飞飞雨 | 来源:发表于2022-03-21 18:07 被阅读0次

    卷完Promise咱们继续卷this

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

    1. 函数默认执行 执行window.也就是什么都不做直接执行
    2. 对象调用函数,会隐式绑定把this指向对象
    3. 显示绑定,通过call,apply,bind,会指向输入的参数,如果不输入参数,则默认绑定为window
    4. 通过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
    
    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绑定 > 显式绑定 > 隐式绑定 > 默认绑定。

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/ojutjrtx.html