--- title: this slug: Web/JavaScript/Reference/Operators/this translation_of: Web/JavaScript/Reference/Operators/this ---
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 {{jsxref("Function.prototype.bind()", "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).
this
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.
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 {{jsxref("globalThis")}}, bất kể bối cảnh hiện tại mà mã của bạn đang chạy.
Bên trong một hàm, giá trị của this
phụ thuộc vào cách gọi hàm.
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
this
nên là {{jsxref("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 {{jsxref("Function.prototype.call()", "call()")}}, hoặc {{jsxref("Function.prototype.apply()", "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]
bind
methodECMAScript 5 giới thiệu {{jsxref("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
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 obj, thiết lập this là obj. // Gán một tham chiếu tới hàm trả về là 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 hàm 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
Trong ví dụ trên, hàm (gọi nó là hàm ẩn danh A) gán cho obj.bar
trả về một hàm khác (gọi là hàm ẩn danh B) mà nó là một arrow function. Kết quả là, this
của hàm B được thiết lập vĩnh viễn là this
của obj.bar
(hàm A) khi được gọi. Khi hàm trả về (hàm B) được gọi, this
của nó sẽ luôn là những gì được thiết lập ban đầu. Trong đoạn mã trên, this
của hàm B được thiết lập theo this
của hàm A đó là obj
, vì thế nó vẫn được thiết lập là obj
ngay cả khi được gọi theo cách thông thường thiết lập this
thành undefined
hoặc global object (hoặc bất kỳ phương thức nào khác như trong ví dụ trên được thực thi trong bối cảnh toàn cầu).
Khi một hàm được gọi như là một phương thức của đối tượng,this
được đặt thành đối tượng mà có phương thức được gọi trên.
Trong ví dụ dưới đây, khi o.f()
được gọi, this
bên trong hàm sẽ liên kết với đối tượng o
.
var o = { prop: 37, f: function() { return this.prop; } }; console.log(o.f()); // 37
Lưu ý hành vi này hoàn toàn không bị ảnh hưởng bởi cách thức hoặc nơi chức năng được khai báo. Trong ví dụ ở trên, chúng ta khai báo hàm f
bên trong đối tượng o
. Tuy nhiên, chúng ta có thể dễ dàng khai báo hàm trước và đính kèm nó vào o.f
. Làm như vậy sẽ có kết quả tương tự:
var o = {prop: 37}; function independent() { return this.prop; } o.f = independent; console.log(o.f()); // 37
Điều này chứng tỏ rằng vấn đề chỉ là việc gọi hàm f
của o
.
Tương tự, ràng buộc với this
chỉ bị ảnh hưởng bởi tham chiếu trực tiếp nhất. Trong ví dụ dưới, khi chúng ta gọi hàm, chúng ta gọi nó như là một phương thức g
của đối tượng o.b
. Khi thực thi, this
bên trong hàm sẽ tham chiếu tới o.b
. Thực tế đối tượng này là một thành viên của o
không ảnh hưởng; tham chiếu trực tiếp nhất mới là quan trọng nhất.
var o = {prop: 37}; function independent() { return this.prop; } o.f = independent; console.log(o.f()); // 37 bởi vì tham chiếu trực tiếp nhất là o o.b = {g: independent, prop: 42}; console.log(o.b.g()); // 42 bởi vì tham chiếu trực tiếp nhất là o.b
this
on the object's prototype chainThe 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 setterAgain, 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 {{jsxref("Operators/new", "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.)
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).
Specification |
---|
{{SpecName('ESDraft', '#sec-this-keyword', 'The this keyword')}} |
{{Compat("javascript.operators.this")}}