一篇弄清楚JavaScript中的 this到底指向谁
前言
在写代码的时候我们经常会看到this这个关键词,this到底有什么用?今天我们就来聊聊关于this的那些事。
正文
为什么要有this
1.为了让对象中的函数有能力访问对象自己的属性。
例子
如果我们想要在对象内部方法中使用对象内部的属性,就像图中的代码,它是可以在C语言里运行的,但是在JS中不可行,JS它需要使用this机制来访问(图中的myName)
let obj = {
myName: '喜羊羊',
age: 12,
bar: function () { // 在对象内部方法中使用对象内部的属性
console.log(this.myName);
}
}
obj.bar();
2.this可以显著的提升代码质量,减少上下文参数的传递。
这种显示传参的方法有点啰嗦,如果我们采用this的话,那么就会优雅,方便很多。
function identify() {
return this.name.toUpperCase();//英文字符转为大写
}
function speak() {
var greeting = 'Hello, I am ' + identify.call(this);
console.log(greeting);
}
var me = {
name: 'gg bond'
}
speak.call(me);
运行结果是一样的
this的使用场景
可以产生作用域的地方就可以用this(除了块级作用域)
也就是:
- 全局
- 函数体内
console.log(this);
在node里打印出来是:
因为node的全局是global空对象,跟浏览器的引擎有些不一样,我们看在浏览器上的运行:
全局代指的是Window
this 代指某一块作用域
写在全局下面就代指全局的作用域
this的绑定规则
1. 默认绑定
当一个函数直接独立调用,不带任何修饰符时,使用默认绑定。 - 函数在哪个词法作用域中生效,函数中的this就指向哪里。(只要是默认绑定this一定指向全局对象window。)
function foo() {
console.log(this);//指向Window
}
foo();//独立调用
function foo() {
console.log(this);//还是指向Window
}
function bar() {//词法作用域在全局
foo();
}
bar()
var
在全局,通过var
声明的变量相当于window.xxx
,在window
对象上添加了一个属性在函数中,通过var声明的变量相当于函数的词法作用域。
let
就不会
2. 隐式绑定
当函数的引用有上下文对象时(当函数被某个对象所拥有时),隐式绑定。 - 函数中的this指向的是引用它的对象。
var obj = {
a: 1,
foo: foo//引用
}
function foo() {
console.log(this.a);//输出obj的a
}
obj.foo()//隐式绑定
3. 隐式丢失
当一个函数被赋值被多个对象链式调用时,函数的this指向就近的那个对象
我附庸的附庸不是我的附庸
var obj = {
a: 1,
foo: foo//引用
}
var obj2 = {
a: 2,
obj: obj
}
function foo() {
console.log(this.a);
}
obj2.obj.foo()
4. 显示绑定
通过bind、apply、call,将函数的this指向指定的对象。call直接接受参数,apply接受参数需要用数组装起来。
bind()
band()会默认返回一个函数体。
当这个新函数被调用时,它的 this
值会被设置为在 bind()
调用中传递的第一个参数。
function greet(greeting) {
console.log(greeting + ', ' + this.name);
}
let person = { name: 'GG Bond' };
let greetJohn = greet.bind(person, 'Hello'); // 第一个参数用于绑定 this,之后的参数将作为函数的参数
greetJohn(); // 输出 'Hello,GG Bond'
call()
立即调用一个函数,并允许指定 this
值以及任何需要传递给函数的参数。参数直接列在 call()
后面,不需要用数组包装。
function greet(greeting) {
console.log(greeting + ', ' + this.name);
}
let person = { name: 'call' };
greet.call(person, 'Hi'); // 输出 'Hi, call'
apply()
apply()
也立即调用一个函数,但与 call()
不同的是,它的参数需要以数组的形式给出。
var obj = {
a: 1
}
function foo(x, y) {
console.log(this.a, x + y);//这里的this指向了a,输出1
}
foo.apply(obj, [1, 2])
6. new绑定
通过new调用函数,将函数的this指向新创建的对象。
创建对象并绑定 this
的过程:
- 创建一个新对象:首先,JavaScript 引擎会创建一个全新的空对象。
- 设置原型链:新对象的原型(
__proto__
)会被设置为构造函数的prototype
属性所指向的对象。 - 绑定 this:函数内部的
this
被绑定到这个新创建的对象上。 - 执行构造函数:构造函数的代码被执行,
this
指向新创建的对象。 - 返回新对象:如果构造函数没有显式返回一个对象,则默认返回新创建的对象。如果构造函数返回了一个对象,那么这个返回的对象将覆盖新创建的对象。
function Person(name) {
this.name = name;
return {}; // 返回一个空对象,这将覆盖新创建的对象
}
let jane = new Person('Jane');
console.log(jane instanceof Object); // true
console.log(jane instanceof Person); // false
7. 箭头函数
箭头函数中没有this
这个机制,写在箭头函数中的this
也是它外层非箭头函数的。
// 使用常规函数
function regularFunction() {
console.log(this);
}
// 使用箭头函数
const arrowFunction = () => {
console.log(this);
};
// 定义一个对象,其中包含一个方法和一个箭头函数属性
const obj = {
name: 'Test',
regularMethod: function() {
console.log(this);
},
arrowMethod: () => {
console.log(this);
}
};
// 调用常规函数和箭头函数
regularFunction(); // 在全局作用域下,this指向全局对象
arrowFunction(); // 同样在全局作用域下,this也指向全局对象
// 调用对象的方法
obj.regularMethod(); // this指向obj
obj.arrowMethod(); // this仍然指向全局对象,而不是obj
结语
以上就是本文的全部内容,希望对你理解this的使用机制有所帮助,感谢你的阅读!
转载自:https://juejin.cn/post/7391005009666031631