【JS基础系列】如何正确判断this的指向?
首先我们要清楚this的指向确定是发生在调用的时候的,而不是声明this的时候。
this的指向总共可以分为五种:
默认绑定(非严格模式-window,严格模式-undefined)
隐式绑定(一般是上下文,特殊情况指向window或者undefined)
显式绑定(指向绑定的对象,特殊情况指向window或者undefined)
new绑定(一般指向新对象,但是返回function或object时,指向返回的对象)
箭头函数绑定(指向上下文中的this)
1.默认绑定的 this
- 浏览器环境:
无论是否在严格模式下,在全局执行环境中(在任何函数体外部this 都指向全局对象 window; - node 环境:
无论是否在严格模式下,在全局执行环境中(在任何函数体外部),this 都是空对象 {}
非严格模式下,this在普通函数中被调用,this会指向全局的window。
// 非严格模式下
function func() {
console.log(this);
}
func(); // window
严格模式下,this在普通函数中被调用,this会指向undefined。
// 严格模式下
function func() {
"use strict";
console.log(this);
}
func(); // undefined
2.隐式绑定的this
当函数引用有上下文对象时,隐式绑定规则会把函数中的this绑定到这个上下文对象。对象属性引用链中只有上一层或者说最后一层在调用中起作用,this指向了这个上下文对象。典型的隐式调用为: xxx.fn()
function func() {
console.log(this.a);
}
var a = 5;
var obj = {
a: 10,
func: func
}
obj.func(); // 10
但是在隐式绑定某些情况下的this会指向window或者undefined。(即类似默认绑定)
function func() {
console.log(this.a);
}
var a = 5;
var obj = {
a: 10,
func: func
}
var func1 = obj.func;
obj.func(); // 10
// func1在调用的时候没有绑定到任何的上下文对象中,所以应用的是默认绑定。
func1(); // 5
3.显式绑定的this
call,apply,bind 绑定中,this指向的就是绑定的对象【称为硬绑定】。这里同样需要注意一种特殊情况,如果call,apply或者bind 传入的第一个参数值是 undefined 或者 null,那么这些值在调用时会被忽略,实际应用的是默认绑定规则。
function info(){
console.log(this.age);
}
var person = {
age: 20,
info
}
var age = 28;
var info = person.info;
info.call(person); //20
info.apply(person); //20
info.bind(person)(); //20
当第一个参数为null和undefined时,this指向全局对象。这个时候严格模式下 this 的值为传入的值 null /undefined,非严格模式为全局对象(node环境为global,浏览器环境为window)
4.new 绑定-构造函数中的this
如果是 new 绑定,并且构造函数中没有返回 function 或者是 object,那么 this 指向这个新对象。如下:
构造函数返回值不是 function 或 object。
function Super(age) {
this.age = age;
}
let instance = new Super('26');
console.log(instance.age); //2
构造函数返回值是 function 或 object,这种情况下 this 指向的是返回的对象。
function Super(age) {
this.age = age;
let obj = {a: '2'};
return obj;
}
let instance = new Super('hello');
console.log(instance.age); //undefined
你可以想知道为什么会这样?我们来看一下 new 的实现原理:
- 创建一个新对象。
- 这个新对象会被执行[[原型]]连接。
- 属性和方法被加入到 this 引用的对象中。并执行了构造函数中的方法.
- 如果函数没有返回其他对象,那么this指向这个新对象,否则this指向构造函数中返回的对象。
function new(func) {
let target = {};
target.__proto__ = func.prototype;
let res = func.call(target);
//排除 null 的情况
if (res && typeof(res) == "object" || typeof(res) == "function") {
return res;
}
return target;
}
5.箭头函数中的this
箭头函数有两个方面的作用:更简短的函数并且不绑定this。
箭头函数没有自己的this,继承外层上下文绑定的this。
var a = 20;
function func() {
var a = 10;
return () => {
console.log(this.a)
}
}
var func1 = func();
func1(); // 20 箭头会从它的上一层func继承this,上一层的this是window,所以是20。如果上一层是箭头函数那会继续往上找。
另一个例子
let obj = {
age: 20,
info: function() {
return () => {
console.log(this.age); //this继承的是外层上下文绑定的this
}
}
}
let person = {age: 28};
let info = obj.info();
info(); //20
let info2 = obj.info.call(person);
info2(); //28
恭喜你,又掌握了一个新技能~
喜欢就点个关注吧~❤️
关注微信公众号【前端FE】了解更多