jannahuang / blog

MIT License
0 stars 0 forks source link

JS 的 this 是什么 #18

Open jannahuang opened 2 years ago

jannahuang commented 2 years ago

this 是什么

this 是当前执行上下文的一个属性,在非严格模式下,总是指向一个对象,在严格模式下可以是任意值。 this 的设计目的就是在函数体内部,指代函数当前的运行环境。 全局上下文 无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。 函数上下文 非严格模式下,this 的值默认指向全局对象,浏览器中就是 window。 严格模式下,如果进入执行环境时没有设置 this 的值,this 会保持为 undefined。

在 JavaScript 中,行为由属性中的函数来表示,即添加对象的方法。 通常,对象方法需要访问对象中存储的信息才能完成其工作。为了访问该对象,方法中可以使用 this 关键字。 this 的值就是在点.之前的对象,即调用该方法的对象。

let user = {
  name: "John",
  age: 30,
  sayHi() {
    // "this" 指的是“当前的对象”
    alert(this.name);
  }
};
// 这个例子中 this 的值是 user
user.sayHi(); // John

this 不受限制

JavaScript 中的 this 可以用于任何函数,即使它不是对象的方法。 this 的值是在代码运行时计算出来的,它取决于代码上下文。 举例,在两个对象中使用相同的函数,调用时有不同的 this 值:

let user = { name: "John" };
let admin = { name: "Admin" };

function sayHi() {
  alert( this.name );
}

// 在两个对象中使用相同的函数
user.f = sayHi;
admin.f = sayHi;

// 这两个调用有不同的 this 值
// 函数内部的 "this" 是“点符号前面”的那个对象
user.f(); // John(this == user)
admin.f(); // Admin(this == admin)

规则:如果 obj.f() 被调用了,则 this 在 f 函数调用期间是 obj。

在没有对象的情况下调用:this == undefined

严格模式下的 this 值为 undefined。如果尝试访问 this 的属性,将会报错。 非严格模式下,this 将会是 全局对象 window。

function sayHi() {
  console.log(this);
}
sayHi(); // undefined

箭头函数没有自己的 this

在箭头函数中引用 this,this 值取决于外部函数。这是箭头函数的一个特性,当我们不需要一个独立的 this,而是想从外部上下文中获取时,可以用。

let user = {
  firstName: "foo",
  sayHi() {
    let arrow = () => console.log(this.firstName);
    arrow();
  }
};
user.sayHi(); // foo

把函数调用改写成 call()

平时直接调用函数的写法是 call() 方法的语法糖,将函数调用改写成 call() 之后,this 就是 call() 方法的第一个参数。 把方法改写成 call() 调用的形式:

// 1. 普通函数
f(p1, p2) // 等价于 f.call(undefined, p1, p2)
// 2. 对象里的函数
o.c.f(p1, p2) // 改成 o.c.f.call(o.c, p1, p2)

在非严格模式下使用 call 和 apply 时,如果用作 this 的值不是对象,则会被尝试转换为对象。null 和 undefined 被转换为全局对象。

练习

  1. 
    var f = function () {
    console.log(this.x);
    }

var x = 1; var obj = { f: f, x: 2, };

f() // 改写 f.call(undefined),非严格模式下 undefined 替换成全局对象,即结果 1 obj.f() // 改写 obj.f.call(obj),执行上下文为 obj,即结果 2

函数f在全局环境执行,this.x指向全局环境的x。
![全局环境执行](https://raw.githubusercontent.com/jannahuang/blog/main/pictures/this-window.png)
在obj环境执行,this.x指向obj.x。
![obj 环境执行](https://raw.githubusercontent.com/jannahuang/blog/main/pictures/this-obj.png)

2. 
```javascript
var length = 4;
function callback() {
  console.log(this.length); // 4
}

const obj = {
  length: 5,
  method(callback) {
    callback();
  }
};

obj.method(callback, 1, 2);

/*
答案:
obj.method(callback, 1, 2) 改写为 obj.method.call(obj, callback, 1, 2),即在 obj 里调用。
obj 里的 callback() 改写成 callbacl.call(undefined)。
非严格模式下,undefined 被浏览器改为 window;
而全局属性会挂在 window 对象上,而全局里的 length 为 4。所以结果为 4。
*/

笔记参考《现代 JavaScript 教程》阮一峰博客及其他资料