this

A 函数的 this keyword behaves a little differently in JavaScript compared to other languages. It also has some differences between 严格模式 和非严格模式。

In most cases, the value of this is determined by how a function is called (runtime binding). It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind() method to 设置值为函数的 this regardless of how it's called , and ES2015 introduced 箭头函数 which don't provide their own this binding (it retains the this value of the enclosing lexical context).

句法

this
					

A property of an execution context (global, function or eval) that, in non–strict mode, is always a reference to an object and in strict mode can be any value.

描述

全局上下文

In the global execution context (outside of any function), this refers to the global object whether in strict mode or not.

// In web browsers, the window object is also the global object:
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"
					

注意: You can always easily get the global object using the global globalThis property, regardless of the current context in which your code is running.

函数上下文

Inside a function, the value of this depends on how the function is called.

Since the following code is not in 严格模式 , and because the value of this is not set by the call, this will default to the global object, which is window in a browser.

function f1() {
  return this;
}
// In a browser:
f1() === window; // true
// In Node:
f1() === globalThis; // true
					

In strict mode, however, if the value of this is not set when entering an execution context, it remains as undefined , as shown in the following example:

function f2() {
  'use strict'; // see strict mode
  return this;
}
f2() === undefined; // true
					
In the second example, this should be undefined , because f2 was called directly and not as a method or property of an object (e.g. window.f2() ). This feature wasn't implemented in some browsers when they first started to support 严格模式 . As a result, they incorrectly returned the window 对象。

To set the value of this to a particular value when calling a function, use call() ,或 apply() as in the examples below.

类上下文

The behavior of this in and functions is similar, since classes are functions under the hood. But there are some differences and caveats.

Within a class constructor, this is a regular object. All non-static methods within the class are added to the prototype of this :

class Example {
  constructor() {
    const proto = Object.getPrototypeOf(this);
    console.log(Object.getOwnPropertyNames(proto));
  }
  first(){}
  second(){}
  static third(){}
}
new Example(); // ['constructor', 'first', 'second']
					

注意: Static methods are not properties of this . They are properties of the class itself.

派生类

Unlike base class constructors, derived constructors have no initial this binding. Calling super() creates a this binding within the constructor and essentially has the effect of evaluating the following line of code, where Base is the inherited class:

this = new Base();
					

警告: Referring to this before calling super() will throw an error.

Derived classes must not return before calling super() , unless they return an Object or have no constructor at all.

class Base {}
class Good extends Base {}
class AlsoGood extends Base {
  constructor() {
    return {a: 5};
  }
}
class Bad extends Base {
  constructor() {}
}
new Good();
new AlsoGood();
new Bad(); // ReferenceError
					

范例

this 在函数上下文中

// An object can be passed as the first argument to call or apply and this will be bound to it.
var obj = {a: 'Custom'};
// We declare a variable and the variable is assigned to the global window as its property.
var a = 'Global';
function whatsThis() {
  return this.a;  // The value of this is dependent on how the function is called
}
whatsThis();          // 'Global' as this in the function isn't set, so it defaults to the global/window object
whatsThis.call(obj);  // 'Custom' as this in the function is set to obj
whatsThis.apply(obj); // 'Custom' as this in the function is set to obj
					

this 和对象转换

function add(c, d) {
  return this.a + this.b + c + d;
}
var o = {a: 1, b: 3};
// The first parameter is the object to use as
// 'this', subsequent parameters are passed as
// arguments in the function call
add.call(o, 5, 7); // 16
// The first parameter is the object to use as
// 'this', the second is an array whose
// members are used as the arguments in the function call
add.apply(o, [10, 20]); // 34
					

Note that in non–strict mode, with call and apply , if the value passed as this is not an object, an attempt will be made to convert it to an object. Values null and undefined become the global object. Primitives like 7 or 'foo' will be converted to an Object using the related constructor, so the primitive number 7 is converted to an object as if by new Number(7) and the string 'foo' to an object as if by new String('foo') , e.g.

function bar() {
  console.log(Object.prototype.toString.call(this));
}
bar.call(7);     // [object Number]
bar.call('foo'); // [object String]
bar.call(undefined); // [object global]
					

bind method

ECMAScript 5 introduced Function.prototype.bind() . Calling f.bind(someObject) creates a new function with the same body and scope as f , but where this occurs in the original function, in the new function it is permanently bound to the first argument of bind , regardless of how the function is being used.

function f() {
  return this.a;
}
var g = f.bind({a: 'azerty'});
console.log(g()); // azerty
var h = g.bind({a: 'yoo'}); // bind only works once!
console.log(h()); // azerty
var o = {a: 37, f: f, g: g, h: h};
console.log(o.a, o.f(), o.g(), o.h()); // 37,37, azerty, azerty
					

箭头函数

In 箭头函数 , this retains the value of the enclosing lexical context's this . In global code, it will be set to the global object:

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
					

Note: if this arg is passed to call , bind ,或 apply on invocation of an arrow function it will be ignored. You can still prepend arguments to the call, but the first argument ( thisArg ) should be set to null .

// Call as a method of an object
var obj = {func: foo};
console.log(obj.func() === globalObject); // true
// Attempt to set this using call
console.log(foo.call(obj) === globalObject); // true
// Attempt to set this using bind
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
					

No matter what, foo 's this is set to what it was when it was created (in the example above, the global object). The same applies to arrow functions created inside other functions: their this remains that of the enclosing lexical context.

// Create obj with a method bar that returns a function that
// returns its this. The returned function is created as
// an arrow function, so its this is permanently bound to the
// this of its enclosing function. The value of bar can be set
// in the call, which in turn sets the value of the
// returned function.
var obj = {
  bar: function() {
    var x = (() => this);
    return x;
  }
};
// Call bar as a method of obj, setting its this to obj
// Assign a reference to the returned function to fn
var fn = obj.bar();
// Call fn without setting this, would normally default
// to the global object or undefined in strict mode
console.log(fn() === obj); // true
// But caution if you reference the method of obj without calling it
var fn2 = obj.bar;
// Calling the arrow function's this from inside the bar method()
// will now return window, because it follows the this from fn2.
console.log(fn2()() == window); // true
					

In the above, the function (call it anonymous function A) assigned to obj.bar returns another function (call it anonymous function B) that is created as an arrow function. As a result, function B's this is permanently set to the this of obj.bar (function A) when called. When the returned function (function B) is called, its this will always be what it was set to initially. In the above code example, function B's this is set to function A's this which is obj , so it remains set to obj even when called in a manner that would normally set its this to undefined or the global object (or any other method as in the previous example in the global execution context).

作为对象方法

When a function is called as a method of an object, its this is set to the object the method is called on.

In the following example, when o.f() is invoked, inside the function this is bound to the o 对象。

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};
console.log(o.f()); // 37
					

Note that this behavior is not at all affected by how or where the function was defined. In the previous example, we defined the function inline as the f member during the definition of o . However, we could have just as easily defined the function first and later attached it to o.f . Doing so results in the same behavior:

var o = {prop: 37};
function independent() {
  return this.prop;
}
o.f = independent;
console.log(o.f()); // 37
					

This demonstrates that it matters only that the function was invoked from the f member of o .

Similarly, the this binding is only affected by the most immediate member reference. In the following example, when we invoke the function, we call it as a method g of the object o.b . This time during execution, this inside the function will refer to o.b . The fact that the object is itself a member of o has no consequence; the most immediate reference is all that matters.

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42
					

this on the object's prototype chain

The same notion holds true for methods defined somewhere on the object's prototype chain. If the method is on an object's prototype chain, this refers to the object the method was called on, as if the method were on the object.

var o = {f: function() { return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
					

In this example, the object assigned to the variable p doesn't have its own f property, it inherits it from its prototype. But it doesn't matter that the lookup for f eventually finds a member with that name on o ; the lookup began as a reference to p.f , so this inside the function takes the value of the object referred to as p . That is, since f is called as a method of p , its this refers to p . This is an interesting feature of JavaScript's prototype inheritance.

this with a getter or setter

Again, the same notion holds true when a function is invoked from a getter or a setter. A function used as getter or setter has its this bound to the object from which the property is being set or gotten.

function sum() {
  return this.a + this.b + this.c;
}
var o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3;
  }
};
Object.defineProperty(o, 'sum', {
    get: sum, enumerable: true, configurable: true});
console.log(o.average, o.sum); // 2, 6
					

作为构造函数

When a function is used as a constructor (with the new keyword), its this is bound to the new object being constructed.

While the default for a constructor is to return the object referenced by this , it can instead return some other object (if the return value isn't an object, then the this object is returned).

/*
 * Constructors work like this:
 *
 * function MyConstructor(){
 *   // Actual function body code goes here.
 *   // Create properties on |this| as
 *   // desired by assigning to them.  E.g.,
 *   this.fum = "nom";
 *   // et cetera...
 *
 *   // If the function has a return statement that
 *   // returns an object, that object will be the
 *   // result of the |new| expression.  Otherwise,
 *   // the result of the expression is the object
 *   // currently bound to |this|
 *   // (i.e., the common case most usually seen).
 * }
 */
function C() {
  this.a = 37;
}
var o = new C();
console.log(o.a); // 37
function C2() {
  this.a = 37;
  return {a: 38};
}
o = new C2();
console.log(o.a); // 38
					

In the last example ( C2 ), because an object was returned during construction, the new object that this was bound to simply gets discarded. (This essentially makes the statement " this.a = 37; " dead code. It's not exactly dead because it gets executed, but it can be eliminated with no outside effects.)

作为 DOM 事件处理程序

When a function is used as an event handler, its this is set to the element on which the listener is placed (some browsers do not follow this convention for listeners added dynamically with methods other than addEventListener() ).

// When called as a listener, turns the related element blue
function bluify(e) {
  // Always true
  console.log(this === e.currentTarget);
  // true when currentTarget and target are the same object
  console.log(this === e.target);
  this.style.backgroundColor = '#A5D9F3';
}
// Get a list of every element in the document
var elements = document.getElementsByTagName('*');
// Add bluify as a click listener so when the
// element is clicked on, it turns blue
for (var i = 0; i < elements.length; i++) {
  elements[i].addEventListener('click', bluify, false);
}
					

在内联事件处理程序中

When the code is called from an inline on-event handler , its this is set to the DOM element on which the listener is placed:

<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>
					

The above alert shows button . Note however that only the outer code has its this set this way:

<button onclick="alert((function() { return this; })());">
  Show inner this
</button>
					

In this case, the inner function's this isn't set so it returns the global/window object (i.e. the default object in non–strict mode where this isn't set by the call).

this 在类中

Just like with regular functions, the value of this within methods depends on how they are called. Sometimes it is useful to override this behavior so that this within classes always refers to the class instance. To achieve this, bind the class methods in the constructor:

class Car {
  constructor() {
    // Bind sayBye but not sayHi to show the difference
    this.sayBye = this.sayBye.bind(this);
  }
  sayHi() {
    console.log(`Hello from ${this.name}`);
  }
  sayBye() {
    console.log(`Bye from ${this.name}`);
  }
  get name() {
    return 'Ferrari';
  }
}
class Bird {
  get name() {
    return 'Tweety';
  }
}
const car = new Car();
const bird = new Bird();
// The value of 'this' in methods depends on their caller
car.sayHi(); // Hello from Ferrari
bird.sayHi = car.sayHi;
bird.sayHi(); // Hello from Tweety
// For bound methods, 'this' doesn't depend on the caller
bird.sayBye = car.sayBye;
bird.sayBye();  // Bye from Ferrari
					

注意: Classes are always strict mode code. Calling methods with an undefined this will throw an error.

规范

规范
ECMAScript (ECMA-262)
The definition of 'The this keyword' in that specification.

浏览器兼容性

更新 GitHub 上的兼容性数据
Desktop Mobile Server
Chrome Edge Firefox Internet Explorer Opera Safari Android webview Chrome for Android Firefox for Android Opera for Android Safari on iOS Samsung Internet Node.js
this Chrome 1 Edge 12 Firefox 1 IE 4 Opera 9.5 Safari 1 WebView Android 1 Chrome Android 18 Firefox Android 4 Opera Android 10.1 Safari iOS 1 Samsung Internet Android 1.0 nodejs 0.1.100

图例

完整支持
完整支持

另请参阅

Metadata

  1. JavaScript
  2. 教程:
  3. 完整初学者
    1. JavaScript 基础
    2. JavaScript 第一步
    3. JavaScript 构建块
    4. 引入 JavaScript 对象
  4. JavaScript 指南
    1. 介绍
    2. 语法和类型
    3. 控制流程和错误处理
    4. 循环和迭代
    5. 函数
    6. 表达式和运算符
    7. 数字和日期
    8. 文本格式
    9. 正则表达式
    10. Indexed collections
    11. Keyed collections
    12. Working with objects
    13. 对象模型的细节
    14. Using promises
    15. 迭代器和生成器
    16. Meta programming
    17. JavaScript 模块
  5. 中间体
    1. Client-side JavaScript frameworks
    2. 客户端侧 Web API
    3. 重新介绍 JavaScript
    4. JavaScript 数据结构
    5. 相等比较和相同
    6. 闭包
  6. 高级
    1. 继承和原型链
    2. 严格模式
    3. JavaScript 类型数组
    4. 内存管理
    5. 并发模型和事件循环
  7. 参考:
  8. 内置对象
    1. AggregateError
    2. Array
    3. ArrayBuffer
    4. AsyncFunction
    5. Atomics
    6. BigInt
    7. BigInt64Array
    8. BigUint64Array
    9. Boolean
    10. DataView
    11. Date
    12. Error
    13. EvalError
    14. FinalizationRegistry
    15. Float32Array
    16. Float64Array
    17. Function
    18. Generator
    19. GeneratorFunction
    20. Infinity
    21. Int16Array
    22. Int32Array
    23. Int8Array
    24. InternalError
    25. Intl
    26. JSON
    27. Map
    28. Math
    29. NaN
    30. Number
    31. Object
    32. Promise
    33. Proxy
    34. RangeError
    35. ReferenceError
    36. Reflect
    37. RegExp
    38. Set
    39. SharedArrayBuffer
    40. String
    41. Symbol
    42. SyntaxError
    43. TypeError
    44. TypedArray
    45. URIError
    46. Uint16Array
    47. Uint32Array
    48. Uint8Array
    49. Uint8ClampedArray
    50. WeakMap
    51. WeakRef
    52. WeakSet
    53. WebAssembly
    54. decodeURI()
    55. decodeURIComponent()
    56. encodeURI()
    57. encodeURIComponent()
    58. escape()
    59. eval()
    60. globalThis
    61. isFinite()
    62. isNaN()
    63. null
    64. parseFloat()
    65. parseInt()
    66. undefined
    67. unescape()
    68. uneval()
  9. 表达式 & 运算符
    1. Addition (+)
    2. Addition assignment (+=)
    3. Assignment (=)
    4. Bitwise AND (&)
    5. Bitwise AND assignment (&=)
    6. Bitwise NOT (~)
    7. Bitwise OR (|)
    8. Bitwise OR assignment (|=)
    9. Bitwise XOR (^)
    10. Bitwise XOR assignment (^=)
    11. Comma operator (,)
    12. 条件 (三元) 运算符
    13. Decrement (--)
    14. Destructuring assignment
    15. Division (/)
    16. Division assignment (/=)
    17. Equality (==)
    18. Exponentiation (**)
    19. Exponentiation assignment (**=)
    20. Function expression
    21. Greater than (>)
    22. Greater than or equal (>=)
    23. Grouping operator ( )
    24. Increment (++)
    25. Inequality (!=)
    26. Left shift (<<)
    27. Left shift assignment (<<=)
    28. Less than (<)
    29. Less than or equal (<=)
    30. Logical AND (&&)
    31. Logical AND assignment (&&=)
    32. Logical NOT (!)
    33. Logical OR (||)
    34. Logical OR assignment (||=)
    35. Logical nullish assignment (??=)
    36. Multiplication (*)
    37. Multiplication assignment (*=)
    38. Nullish coalescing operator (??)
    39. Object initializer
    40. 运算符优先级
    41. Optional chaining (?.)
    42. Pipeline operator (|>)
    43. 特性访问器
    44. Remainder (%)
    45. Remainder assignment (%=)
    46. Right shift (>>)
    47. Right shift assignment (>>=)
    48. Spread syntax (...)
    49. Strict equality (===)
    50. Strict inequality (!==)
    51. Subtraction (-)
    52. Subtraction assignment (-=)
    53. Unary negation (-)
    54. Unary plus (+)
    55. Unsigned right shift (>>>)
    56. Unsigned right shift assignment (>>>=)
    57. 异步函数表达式
    58. await
    59. class expression
    60. delete operator
    61. function* 表达式
    62. in operator
    63. instanceof
    64. new operator
    65. new.target
    66. super
    67. this
    68. typeof
    69. void 运算符
    70. yield
    71. yield*
  10. 语句 & 声明
    1. async function
    2. block
    3. break
    4. class
    5. const
    6. continue
    7. debugger
    8. do...while
    9. empty
    10. export
    11. for
    12. for await...of
    13. for...in
    14. for...of
    15. 函数声明
    16. function*
    17. if...else
    18. import
    19. import.meta
    20. label
    21. let
    22. return
    23. switch
    24. throw
    25. try...catch
    26. var
    27. while
    28. with
  11. 函数
    1. 箭头函数表达式
    2. 默认参数
    3. 方法定义
    4. 其余参数
    5. 自变量对象
    6. getter
    7. setter
    1. Private class fields
    2. Public class fields
    3. 构造函数
    4. extends
    5. static
  12. 错误
    1. Error: Permission denied to access property "x"
    2. InternalError: too much recursion
    3. RangeError: argument is not a valid code point
    4. RangeError: invalid array length
    5. RangeError: invalid date
    6. RangeError: precision is out of range
    7. RangeError: radix must be an integer
    8. RangeError: repeat count must be less than infinity
    9. RangeError: repeat count must be non-negative
    10. ReferenceError: "x" is not defined
    11. ReferenceError: assignment to undeclared variable "x"
    12. ReferenceError: can't access lexical declaration`X' before initialization
    13. ReferenceError: deprecated caller or arguments usage
    14. ReferenceError: invalid assignment left-hand side
    15. ReferenceError: reference to undefined property "x"
    16. SyntaxError: "0"-prefixed octal literals and octal escape seq. are deprecated
    17. SyntaxError: "use strict" not allowed in function with non-simple parameters
    18. SyntaxError: "x" is a reserved identifier
    19. SyntaxError: JSON.parse: bad parsing
    20. SyntaxError: Malformed formal parameter
    21. SyntaxError: Unexpected token
    22. SyntaxError: Using //@ to indicate sourceURL pragmas is deprecated. Use //# instead
    23. SyntaxError: a declaration in the head of a for-of loop can't have an initializer
    24. SyntaxError: applying the 'delete' operator to an unqualified name is deprecated
    25. SyntaxError: for-in loop head declarations may not have initializers
    26. SyntaxError: function statement requires a name
    27. SyntaxError: identifier starts immediately after numeric literal
    28. SyntaxError: illegal character
    29. SyntaxError: invalid regular expression flag "x"
    30. SyntaxError: missing ) after argument list
    31. SyntaxError: missing ) after condition
    32. SyntaxError: missing : after property id
    33. SyntaxError: missing ; before statement
    34. SyntaxError: missing = in const declaration
    35. SyntaxError: missing ] after element list
    36. SyntaxError: missing formal parameter
    37. SyntaxError: missing name after . operator
    38. SyntaxError: missing variable name
    39. SyntaxError: missing } after function body
    40. SyntaxError: missing } after property list
    41. SyntaxError: redeclaration of formal parameter "x"
    42. SyntaxError: return not in function
    43. SyntaxError: test for equality (==) mistyped as assignment (=)?
    44. SyntaxError: unterminated string literal
    45. TypeError: "x" has no properties
    46. TypeError: "x" is (not) "y"
    47. TypeError: "x" is not a constructor
    48. TypeError: "x" is not a function
    49. TypeError: "x" is not a non-null object
    50. TypeError: "x" is read-only
    51. TypeError: 'x' is not iterable
    52. TypeError: More arguments needed
    53. TypeError: Reduce of empty array with no initial value
    54. TypeError: X.prototype.y called on incompatible type
    55. TypeError: can't access dead object
    56. TypeError: can't access property "x" of "y"
    57. TypeError: can't assign to property "x" on "y": not an object
    58. TypeError: can't define property "x": "obj" is not extensible
    59. TypeError: can't delete non-configurable array element
    60. TypeError: can't redefine non-configurable property "x"
    61. TypeError: cannot use 'in' operator to search for 'x' in 'y'
    62. TypeError: cyclic object value
    63. TypeError: invalid 'instanceof' operand 'x'
    64. TypeError: invalid Array.prototype.sort argument
    65. TypeError: invalid arguments
    66. TypeError: invalid assignment to const "x"
    67. TypeError: property "x" is non-configurable and can't be deleted
    68. TypeError: setting getter-only property "x"
    69. TypeError: variable "x" redeclares argument
    70. URIError: malformed URI sequence
    71. Warning: -file- is being assigned a //# sourceMappingURL, but already has one
    72. Warning: 08/09 is not a legal ECMA-262 octal constant
    73. Warning: Date.prototype.toLocaleFormat is deprecated
    74. Warning: JavaScript 1.6's for-each-in loops are deprecated
    75. Warning: String.x is deprecated; use String.prototype.x instead
    76. Warning: expression closures are deprecated
    77. Warning: unreachable code after return statement
  13. 杂项
    1. JavaScript technologies overview
    2. 词汇语法
    3. JavaScript 数据结构
    4. Enumerability and ownership of properties
    5. Iteration protocols
    6. 严格模式
    7. Transitioning to strict mode
    8. Template literals
    9. 弃用特征