JS函数中的this

本文最后更新于:1 天前

this 的定义

JavaScript 函数中的this 关键字与其他语言略有不同,此外,在严格模式和非严格模式之间也会有一些差别

在绝大多数情况下,函数的调用方式决定了this的值 (运行时绑定)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function baz(){
//当前调用栈:baz
//全局作用域
console.log("baz");
bar();
}

function bar(){
//当前调用栈 baz=>bar
//当前调用位置在baz中
console.log("bar");
foo();
}

function foo(){
//当前调用栈 baz=>bar=>foo
//当前调用位置在bar中
console.log("foo");
}

baz();

要先弄懂调用位置才能更好的理解this,同时,this一旦被确定了,就不可以被更改

绑定规则(重要)

根据不同的使用场合,this有不同的值,主要有下面几种情况

  • 默认绑定

  • 隐式绑定

  • new绑定

  • 显式绑定

默认绑定

无法应用其他规则时使用

1
2
3
4
5
var name = "Jenny";
function person(){
return this.name;
}
console.log(person());//Jenny

this指向全局对象window,严格模式下绑定到undefined

隐式绑定

函数还可以作为某个对象的方法调用,这时this就指这个上级对象

1
2
3
4
5
6
7
8
9
10
function test(){
console.log(this.x);
}

var obj = {};
obj.x = 1;
obj.m = test;

obj.m = 1;
//obj调用的函数,this绑定到obj上,所以相当于obj.x

如果是嵌套对象调用,this依然指向上一级的对象

1
2
3
4
5
6
7
8
9
10
var o = {
a:10,
b:{
fn:function(){
console.log(this.a)
}
}
}
o.b.fn();
//上一级对象为b,b里面没有a属性,所以输出undefined

一种特殊情况

1
2
3
4
5
6
7
8
9
10
11
12
13
var o ={
a: 10,
b:{
a:12,
fn:function(){
console.log(this.a);//undefined window中没有变量a
console.log(this);//window
}
}
}
var j = o.b.fn;
j();
//this -> window

这里的thiswindow,注意:this永远指向最后调用它的对象,虽然fn函数是对象b的方法,但是该函数最后在全局作用域中执行,所以最终指向window

  • 隐式丢失

1
2
3
4
5
6
7
function foo() {
console.log(this.a);
}
var obj = { a: 2, foo: foo };
var bar = obj.foo; // 为函数调用创建别名
var a = "oops, global"; // a是全局对象的属性bar();
bar(); // "oops, global"

为foo函数创建别名bar时发生了隐式丢失,bar函数自动绑定到window或者undefined(严格模式)

new 绑定

通过构建函数new关键字生成一个实例对象,此时this指向这个实例对象

这和new关键字的原理有关

1
2
3
4
5
6
function test(){
this.x = 1;
}

var obj = new test();
console.log(obj.x)//1 obj被绑定到函数调用的this上

列举一些特殊情况

new过程中遇到return一个对象,此时this指向为返回的对象

1
2
3
4
5
6
7
8
function fn()
{
this.user = 'xxx';
return {};
}
var a = new fn();
console.log(a.user)//undefined
//你可能认为this绑定到a上,实际上如果构造函数中有返回对象,则绑定函数调用this为该返回的this上,所以a.user为undefined

如果返回的不是对象,是基本数据类型,则this指向为实例对象

1
2
3
4
5
6
7
8
function fn()
{
this.user = 'xxx';
return 1;
}
var a = new fn;
console.log(a.user);//xxx
//返回值为number类型,则this依然绑定到a上面

虽然null也表示对象,但是此时this依然指向实例对象

1
2
3
4
5
6
7
function fn()
{
this.user = 'xxx';
return null;
}
var a = new fn;
console.log(a.user);//xxx

显式修改

apply()、call()、bind()是函数的一个方法,作用是改变函数的调用对象,它的第一个参数就表示改变后的调用对象,因此,这时this指的就是这第一个参数

1
2
3
4
5
6
7
function foo() {
console.log(this.a);
}
var obj = { a: 2 };
var obj1 = { a: 3 };
foo.call(obj); // 2 this绑定到obj上
foo.call(obj1); // 3 this绑定到obj1上

硬绑定

硬绑定是指强制把this绑定到某个对象上(除了使用new时)

注意,函数通过 bind() 方法被绑定,它的this将被永久固定

优先级

new > 显式绑定 > 隐式绑定 > 默认绑定

this 特例

1
2
3
4
5
6
function foo(a,b){
console.log(a,b);
}
var dmzobj = Object.create(null);//dmzoj对象是一个以null为原型的对象
var bar = foo.bind(dmzobj,2);//将foo函数的this绑定到dmzoj上,bind方法返回一个具有全新this的函数
bar(3);//2 3

间接引用

1
2
3
4
5
6
7
8
function foo(){
console.log(this.a);
}
var a = 2;
var o = { a: 3, foo: foo};
var p = { a: 4 };
o.foo(); //3
(p.foo = p.foo)();//立即执行函数 2

软绑定

1
2
3
4
5
6
7
8
9
10
11
//软绑定版本的foo()可以手动将this绑定到obj2或者obj3上,但如果应用默认绑定,则会将this绑定到obj
function foo() {
console.log("name: " + this.name);
}
var obj = { name: "obj" },
obj2 = { name: "obj2" },
obj3 = { name: "obj3" };
var fooOBJ = foo.softBind(obj);
fooOBJ(); // name: obj

fooOBJ.call(obj3); // name: obj3

箭头函数的this

箭头函数没有自己的this,箭头函数的this由外层作用域决定,(运行时绑定)

1
2
3
4
5
6
7
8
9
const obj = {
sayThis: () => {
console.log(this);
}
};

obj.sayThis();//绑定obj的this 也就是window
const globalSay = obj.sayThis;
globalSay();

箭头函数不能作为构造函数


JS函数中的this
https://blog.seasalt-haiyan.top/2024/04/18/JS函数中的this/
作者
Xu Haoyang
发布于
2024年4月18日
更新于
2024年4月18日
许可协议