CPPAlien / JS-QA

前端知识问答
0 stars 0 forks source link

JS 中的 this #24

Open CPPAlien opened 4 years ago

CPPAlien commented 4 years ago

两个误解 1,this 指向函数本身。 2,this 指向包含方法的实例。

实际的 JS 的 this 是动态的,根据传入函数中的上下文决定,这个和一般的如 JAVA 语言有很大区别。JAVA 中的 this 就是指向类实例本身。

function classroom(teacher) {
    return function study() {
        console.log(
            `${ teacher } says to study ${ this.topic }`
        );
    };
}
var assignment = classroom("Kyle");
assignment() // Kyle says to study undefined

在非 strict mode 下,未指定上下文,会默认挂在全局对象上,在浏览器则会是 window,所以此时 this.topic 是 undefined。

"use strict";
function classroom(teacher) {
    return function study() {
        console.log(
            `${ teacher } says to study ${ this.topic }`
        );
    };
}
var assignment = classroom("Kyle");
assignment()

---
Uncaught TypeError: Cannot read property 'topic' of undefined
    at study (<anonymous>:5:49)
    at <anonymous>:10:1
var otherHomework = {
    topic: "Math"
};

assignment.call(otherHomework);
// Kyle says to study Math

也可以使用隐式绑定的方式,如下,我们可以说 homework 这个对象拥有了 assignment 这个函数,此时 assignment 中的 this 就可以被推断出指向 homework

var homework = {
    topic: "JS",
    assignment: assignment
};

homework.assignment(); // Kyle says to study JS
CPPAlien commented 4 years ago

内部函数 this 指针在未显式绑定时也会指向全局,这是 JS 的一个设计缺陷

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

关键区别在:箭头函数没有自己的 this,而 function 方式有。但内部函数的 this 会被指向全局对象,而不是外部函数。所以我们可以通过使用箭头函数避免这个设计缺陷

function Person() {
  var that = this;
  that.age = 0;

  setInterval(function growUp() {
    // The callback refers to the `that` variable of which
    // the value is the expected object.
    that.age++;
  }, 1000);
}
当使用箭头函数时
function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| properly refers to the Person object
  }, 1000);
}
CPPAlien commented 4 years ago
var a = { a: () => { console.log(this) }, b: "123", c: function() {console.log(this)}}

a.a() // Window 对象
a.c() // {b: "123", a: ƒ, c: ƒ}
CPPAlien commented 4 years ago

call、apply、bind

call 和 apply 都是 ES3 时出现的,基本一样,唯一区别是 apply 接收一个数组作为参数,而 call 接收参数隔开的传入方式。他们第一个参数都是 this 指针。

bind ES5 引入,与 call 的区别是不会立即执行。

var obj = {name:"Niladri"};

var greeting = function(a,b,c){
    return "welcome "+this.name+" to "+a+" "+b+" in "+c;
};

greeting.call(obj, "Newtown", "KOLKATA", "WB");
greeting.apply(obj, ["Newtown", "KOLKATA", "WB"]);
// welcome Niladri to Newtown KOLKATA in WB

greeting.bind(obj)("Newtown", "KOLKATA", "WB")
greeting.bind(obj, "Newtown")("KOLKATA", "WB")