在 javascript 中,this 关键字是一个特殊的对象标识符,它指向当前执行上下文的对象。与其他编程语言不同,javascript 的 this 不是在编写时绑定,而是在运行时根据函数的调用方式动态绑定的。理解 this 的指向是掌握 javascript 的关键,也是许多开发者容易混淆的地方。
全局上下文中的 this
在全局执行环境(浏览器中是 window,Node.js 中是 global)中,this 指向全局对象。
1 2 3 4 5 // 浏览器环境 console.log(this === window); // true var name = 'globalName'; console.log(this.name); // 'globalName'
函数调用中的 this
非严格模式
在普通函数调用中,this 指向全局对象。
1 2 3 4 function showThis() { console.log(this); } showThis(); // 浏览器中输出 window
严格模式
如果函数处于严格模式(‘use strict’),this 会保持为 undefined,因为严格模式下禁止默认指向全局。
1 2 3 4 5 'use strict'; function showThisStrict() { console.log(this); } showThisStrict(); // undefined
方法调用中的 this
当函数作为对象的方法被调用时,this 指向调用该方法的对象。
1 2 3 4 5 6 7 8 9 10 11 const person = { name: 'Alice', greet: function() { console.log('Hello, ' + this.name); } }; person.greet(); // Hello, Alice // 如果将方法赋值给变量再调用,this 会丢失 const greetFn = person.greet; greetFn(); // Hello, undefined (非严格模式下 this 指向 window)
构造函数中的 this
使用 new 关键字调用函数时,会创建一个新对象,并将该对象绑定到函数的 this 上。构造函数通常首字母大写。
1 2 3 4 5 function Person(name) { this.name = name; } const alice = new Person('Alice'); console.log(alice.name); // Alice
如果构造函数显式返回一个对象,则 this 会被替换;如果返回基本类型,则忽略,依然返回 this 指向的新对象。
箭头函数中的 this
箭头函数没有自己的 this,它捕获其所在(定义时)上下文的 this 值。箭头函数的 this 在定义时就确定了,之后不会改变。
1 2 3 4 5 6 7 8 9 10 11 12 const obj = { name: 'obj', normalFunc: function() { console.log(this.name); }, arrowFunc: () => { console.log(this.name); } }; obj.normalFunc(); // 'obj' obj.arrowFunc(); // undefined(箭头函数的 this 继承自全局/外层,此处外层是全局,所以 this 指向 window)
箭头函数的 this 不能被 call、apply、bind 改变。
事件处理中的 this
在 DOM 事件处理函数中,this 通常指向绑定事件的元素。
1 2 3 4 5 6 7 <button id="btn">Click me</button> <script> const btn = document.getElementById('btn'); btn.addEventListener('click', function() { console.log(this); // <button id="btn">Click me</button> }); </script>
如果使用箭头函数,this 会继承外层上下文(比如 window),可能不是期望的元素。
改变 this 指向:call、apply、bind
我们可以使用 call、apply 或 bind 显式指定函数调用时的 this。
call(thisArg, arg1, arg2, …):立即调用函数,并指定 this。
apply(thisArg, [argsArray]):与 call 类似,但参数以数组形式传递。
bind(thisArg, arg1, arg2, …):返回一个新函数,其 this 永久绑定到指定对象,不会立即执行。
1 2 3 4 5 6 7 8 9 10 11 function introduce(age, city) { console.log(`I'm ${this.name}, ${age} years old, from ${city}.`); } const user = { name: 'Bob' }; introduce.call(user, 25, 'New York'); // I'm Bob, 25 years old, from New York. introduce.apply(user, [30, 'London']); // I'm Bob, 30 years old, from London. const boundIntroduce = introduce.bind(user, 28); boundIntroduce('Paris'); // I'm Bob, 28 years old, from Paris.
常见陷阱与注意事项
回调函数中的 this 丢失:将对象方法作为回调传递时,常常丢失 this。
1 2 3 4 5 6 7 8 9 10 const counter = { count: 0, increment: function() { console.log(this.count); } }; setTimeout(counter.increment, 1000); // 输出 undefined(this 指向全局) // 解决方法:使用箭头函数、bind 或包装函数 setTimeout(() => counter.increment(), 1000); // 0 setTimeout(counter.increment.bind(counter), 1000); // 0
嵌套函数中的 this:在方法内部定义普通函数时,该函数的 this 会指向全局(非严格模式)或 undefined(严格模式)。
1 2 3 4 5 6 7 8 9 10 11 12 const obj = { name: 'obj', outer: function() { console.log('outer this:', this.name); // 'obj' function inner() { console.log('inner this:', this.name); // undefined(非严格模式 window.name) } inner(); } }; obj.outer(); // 解决:使用箭头函数、保存 this 变量(const self = this)、bind
总结
this 的指向取决于函数的调用方式,而不是定义位置。
全局函数调用 → 指向全局对象(严格模式下 undefined)。
对象方法调用 → 指向调用该方法的对象。
构造函数调用(new)→ 指向新创建的实例。
箭头函数 → 继承定义时外层上下文的 this。
事件处理 → 指向绑定事件的元素。
可以使用 call、apply、bind 显式绑定 this。