this

This translation is in progress.

Từ khoá this của hàm  trong JavaScript hơi khác so với các ngôn ngữ khác. Nó cũng có  một vài điểm khác nhau giữa 2 chế độ strict mode và non-strict mode.

Trong hầu hết các trường hợp, giá trị của this được xác định bởi cách gọi hàm (runtime binding). Nó không thể được thiết lập bằng cách gán trong khi thực thi, và nó có thể khác nhau mỗi lần hàm được gọi. ES5 giới thiệu phương thức bind() để thiết lập giá trị của this bất kể hàm được gọi thế nào, và ES2015 giới thiệu arrow functions mà không cung cấp ràng buộc với this của chúng (Nó sẽ giữ giá trị this của lexical context kèm theo).

Cú pháp

this

Giá trị

Một thuộc tính của bối cảnh thực thi (global, function or eval), trong non–strict mode, luôn luôn tham chiếu tới một đối tượng và trong strict mode có thể là bất kỳ giá trị nào.

Global context

Trong global context (bên ngoài các hàm), this tham chiếu tới global object cho dù trong strict mode hoặc không.

// Trong trình duyệt, đối tượng window ?là 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"

Note: Bạn có thể dễ dàng lấy được  global object bằng cách sử dụng thuộc tính toàn cầu globalThis, bất kể bối cảnh hiện tại mà mã của bạn đang chạy.

Function context

Bên trong một hàm, giá trị của this phụ thuộc vào cách gọi hàm.

Simple call

Vì đoạn mã sau không ở chế độ strict mode, và vì  giá trị của this không được thiết lập khi gọi, this mặc định là global objecct, đó là window trong trình duyệt. 

function f1() {
  return this;
}

// In a browser:
f1() === window; // true 

// In Node:
f1() === global; // true

Tuy nhiên, trong chế độ strict mode, nếu giá trị của this không được thiết lập khi vào bối cảnh thực thi, nó sẽ giữ giá trị undefined, như ví dụ sau:

function f2() {
  'use strict'; // see strict mode
  return this;
}

f2() === undefined; // true
 Trong ví dụ thứ 2, this nên là undefined, bởi vì f2 được gọi 1 cách trực tiếp và không phải là một phương thức hoặc thuộc tính của một đối tượng(ví dụ window.f2()). ?Tính năng này sẽ không được triển khai trong một số trình duyệt khi chúng lần đầu hỗ trợ chế độ strict mode. Như kết quả trên, chúng không trả về đối tượng window.

Để thiết lập giá trị cụ thể của this khi gọi hàm, sử dụng call(), hoặc apply() như các ví dụ dưới đây.

Example 1

// Một đối tượng có thể truyền vào như là tham số đầu tiên của call hoặc apply và this sẽ được ràng buộc với nó..
var obj = {a: 'Custom'};

// Thuộc tính này được thiết lập trên global object
var a = 'Global';

function whatsThis() {
  return this.a;  // Giá trị của this phụ thuộc vào cách hàm được gọi.
}

whatsThis();          // 'Global'
whatsThis.call(obj);  // 'Custom'
whatsThis.apply(obj); // 'Custom'

Example 2

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// Tham số đầu tiên là đối tượng sử dụng như là
// 'this', tham số tiếp theo được truyền vào là 
// đối số trong hàm gọi
add.call(o, 5, 7); // 16

// Tham số đầu tiên là đối tượng sử dụng như là
// 'this', tham số thứ 2 là 1 mảng
// các phần tử được sử dụng làm đối số trong lệnh gọi hàm
add.apply(o, [10, 20]); // 34

 Chú ý trong chế độ  non–strict mode, với call và apply, nếu giá trị được truyền vào this không phải là đối tượng, một nỗ lực sẽ được thực hiện để chuyển đổi nó thành đối tượng bằng cách sử dụng ToObject. Vì thế nếu bạn truyền vào giá trị primitive như 7 hoặc 'foo', nó sẽ được chuyển đổi thành Object bằng cách sử dụng các constructor liên quan, do đó 7 sẽ được chuyển đổi thành đối tượng như tạo bằng new Number(7) và string 'foo' cũng được chuyển đổi thành đối tượng như tạo bằng new String('foo'), ví dụ:

function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7);     // [object Number]
bar.call('foo'); // [object String]

The bind method

ECMAScript 5 giới thiệu Function.prototype.bind(). ?Gọi f.bind(someObject) ?tạo ra một hàm mới với cùng thân hàm và phạm vi như hàm f, nhưng this chỉ xảy ra trong hàm ban đầu, trong những hàm mới nó bị ràng buộc vĩnh viễn với đối số đầu tiên của bind, bất kể các hàm được sử dụng thế nào..

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

Arrow functions

Trong arrow functions, this giữ giá trị ?this của lexical context kèm theo. Trong đoạn mã toàn cục, nó sẽ được thiết lập là global object.

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

 Lưu ý: nếu đối số  this được truyền vào call, bind, hoặc apply ?trong việc gọi một arrow function nó sẽ bị bỏ qua. Bạn vẫn có thể thêm các đối số cho việc gọi hàm ?nhưng đối số đầu tiên (thisArg) nên được đặt thành 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

Không có vấn đề gì ở đây, this của foo vẫn giữ nguyên giá trị khi nó được tạo  (?trong ví dụ trên, nó là global object). ? Điều tương tự cũng được áp dụng cho những arrow function được tạo bên trong hàm khác: this của chúng giữ giá trị this của lexical context kèm theo.

// Tạo 1 đối tượng với phương thức bar trả về 1 hàm, hàm này sẽ
// trả về this của nó. Hàm trả về là arrow function, 
// vì thế this của nó được ràng buộc vĩnh viễn với this của hàm kèm theo.
// Giá trị của bar có thể được thiết lập trong khi gọi hàm,
// lần lượt đặt giá của hàm trả về.
var obj = {
  bar: function() {
    var x = (() => this);
    return x;
  }
};

// Gọi phương thức bar của đối tượng, thiết lập this cho đối tượng.
// Gán một tham chiếu tới hàm trả về cho fn
var fn = obj.bar();

// Gọi hàm fn mà không thiết lập this,
// thông thường sẽ mặc định cho global object hoặc undefined trong strict mode
console.log(fn() === obj); // true

// Nhưng hãy cẩn thận nếu bạn tham chiếu phương thức của đối tượng mà không gọi nó
var fn2 = obj.bar;
// Gọi 'this' của arrow function? bên trong phương thức bar()
// nó sẽ trả về window, bởi vì nó theo 'this' từ 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).

As an object method

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 object.

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

As a constructor

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.)

As a DOM event handler

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);
}

In an inline event handler

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).

Specifications

Specification
ECMAScript Latest Draft (ECMA-262)
The definition of 'The this keyword' in that specification.

Browser compatibility

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
thisChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 4Opera Full support 9.5Safari Full support 1WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0nodejs Full support Yes

Legend

Full support  
Full support

See also