this的判断

关键一

  • this永远指向,(最内层)调用这个包含"this"关键字的函数的对象
  • 也就是说: 无论在哪里找到方法:在一个对象还是在原型中。在一个方法调用中,this 始终是点符号.前面的对象
  • 示例一
    my_element.addEventListener("click", function (e) {
    console.log(this.className); // 输出 my_element 的 className
    console.log(e.currentTarget === this); // 输出 `true`
    });
    
  • 示例二
    let user = {
    name: "John",
    surname: "Smith",
    
    set fullName(value) {
        [this.name, this.surname] = value.split(" ");
    },
    
    get fullName() {
        return `${this.name} ${this.surname}`;
    }
    };
    
    let admin = {
    __proto__: user,
    isAdmin: true
    };
    
    alert(admin.fullName); // John Smith (*)
    
    // setter triggers!
    admin.fullName = "Alice Cooper"; // (**)
    
    alert(admin.fullName); // Alice Cooper,admin 的内容被修改了
    alert(user.fullName);  // John Smith,user 的内容被保护了
    

关键二

  • 如果函数在最外层直接运行,默认绑定的对象是 window
  • 示例
    function test(){
        var a = 1;
        console.log(this.a);
    }
    
    test(); //undefined
    

补充

  • 对象不构成单独的作用域,而函数有。
  • In arrow functions, this retains the value of the enclosing lexical context’s this.
  • 箭头函数的this,一旦确定后是不可直接更改的,但可间接更改,示例:
    function test () {
        return () => console.log(this); // 这里箭头函数的this指向test()的this
    }
    let obj = {
        aa: 123,
    }
    
    let rr = test.call(obj); // test()的this被修改了,导致箭头函数的也跟着修改了
    
    setTimeout(rr,1000); // obj ,而不是window; 因为箭头函数rr的this已经确定了,后面不能更改
    

参考


call、bind、apply

apply

  • 接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入,必须一次性传入所有参数
  • 当第一个参数为null、undefined的时候,默认指向window(在浏览器中)
  • 改变this指向后原函数会立即执行,且此方法只是临时改变thi指向一次。
  • 示例:
    var arr=[1,10,5,8,3];
    console.log(Math.max.apply(null, arr)); //10
    

call

  • 接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以参数列表的形式传入,必须一次性传入所有参数
  • 当第一个参数为null、undefined的时候,默认指向window(在浏览器中)
  • 改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次。
  • 示例:
    var arr=[1,10,5,8,3];
    console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); //10
    

bind

  • Function.prototype.bind() - JavaScript | MDN
  • 接受两个参数,第一个参数是this的指向,如果函数不在严格模式下,null 和 undefined 会被替换为全局对象;
  • 第二个参数是函数接受的参数,以参数列表的形式传入,可以分多次传入
  • 改变this指向后不会立即执行,而是返回一个永久改变this指向的函数
  • 可以二次传参,但新绑定的 thisArg 值会被忽略
  • 示例:
    var arr=[1,10,5,8,12];
    var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
    console.log(max(arr[4])); //12,分两次传参
    
  • 简易实现
    Function.prototype.bind=function () {
      var _this=this;
      var context=arguments[0];
      var arg=[].slice.call(arguments,1); //将函数调用时传入的参数转换为数组,并且去掉了第一个参数
    
      return function(){
        arg=[].concat.apply(arg,arguments);
        _this.apply(context,arg);
      }
    };
    

作用

  • 防止原型链污染
  • 示例:
    • JavaScript does not protect the property name hasOwnProperty; an object that has a property with this name may return incorrect results
    • The recommended way to overcome this problem is to instead use Object.hasOwn() (in browsers that support it). Other alternatives include using an external hasOwnProperty:
    • 代码
      const foo = { bar: "Here be dragons" };
      
      // Use Object.hasOwn() method - recommended
      Object.hasOwn(foo, "bar"); // true
      
      // Use the hasOwnProperty property from the Object prototype
      Object.prototype.hasOwnProperty.call(foo, "bar"); // true
      
      // Use another Object's hasOwnProperty
      // and call it with 'this' set to foo
      ({}).hasOwnProperty.call(foo, "bar"); // true
      

代码输出题

题目一

  • 代码
    const obj = {
      name: 'eu',
      sayHi1: ()=>{
        console.log(this.name);
      },
      sayHi2() {
        (()=>{
          console.log(this.name);
        })();
      }
    }
    obj.sayHi1(); // ''
    obj.sayHi2(); // 'eu'
    
  • 解释:
    1. obj.sayHi1() 的执行
      • 考察知识点一: 箭头函数中的 this: 箭头函数不会创建自己的 this 绑定,它会继承上下文中的 this。也就是说,this 的值取决于箭头函数定义时所在的上下文,而不是调用时的上下文。

      • 本题中的应用: 在 sayHi1 方法中,箭头函数被定义在 obj 对象的上下文中,但是由于箭头函数继承的是定义时的 this,而不是调用时的 thisthis 将会是全局上下文(在严格模式下为 undefined,在非严格模式下为 window)。

        因为 this 不是指向 obj,而是指向全局对象,this.name 在全局对象中是未定义的,可能返回 undefined 或空字符串 '',具体取决于运行环境。

    2. obj.sayHi2() 的执行
      • 考察知识点一: 简写函数定义
        sayHi2(){
         console.log('hi');
        }
        // 相当于
        sayHi2: function(){
         console.log('hi');
        }
        
      • 考察知识点二: 普通方法中的 this会根据调用的上下文来决定
      • 本题中的应用 sayHi2 是一个普通方法,因此 this 会根据调用的上下文来决定。在这个例子中,obj.sayHi2() 是调用 sayHi2,所以 this 指向 obj

参考