1.在瀏覽器中,在一個全局環境中,this
就是window
對象。javascript
<script type="text/javascript"> console.log(this === window); //true </script>
2.在瀏覽器中,在全局中使用var
至關於分配給this
或者window
java
<script type="text/javascript"> var foo = "bar"; console.log(this.foo); //logs "bar" console.log(window.foo); //logs "bar" </script>
3.假如你建立一個新的變量,不使用var
或者let
(ECMAScript6),你是添加或者改變全局this
的屬性node
<script type="text/javascript"> foo = "bar"; function testThis() { foo = "foo"; } console.log(this.foo); //logs "bar" testThis(); console.log(this.foo); //logs "foo" </script>
4.在node中使用repl,this
是最頂級的命名空間,你能夠認爲是global
數組
> this { ArrayBuffer: [Function: ArrayBuffer], Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 }, Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 }, ... > global === this true
5.在node中執行腳本,在全局中this
是一個空對象,而不與global
相等瀏覽器
test.js: console.log(this); console.log(this === global);
$ node test.js {} false
6.在node中,全局環境中的var
並不是像在瀏覽器中執行腳本同樣,分配給this
。安全
test.js: var foo = "bar"; console.log(this.foo);
$ node test.js undefined
可是在repl中是同樣的app
> var foo = "bar"; > this.foo bar > global.foo bar
7.在node中,使用腳本執行,不用var
或者let
建立的變量會添加到global
而不是this
.函數
test.js foo = "bar"; console.log(this.foo); console.log(global.foo);
$ node test.js undefined bar
在repl中,它是分配到這兩個上的。this
除了DOM事件處理程序或者一個thisArg
已經設置的狀況外,在node和瀏覽器中,函數中(不實例化new
)的this是全局範圍的。prototype
<script type="text/javascript"> foo = "bar"; function testThis() { this.foo = "foo"; } console.log(this.foo); //logs "bar" testThis(); console.log(this.foo); //logs "foo" </script>
test.js: foo = "bar"; function testThis () { this.foo = "foo"; } console.log(global.foo); testThis(); console.log(global.foo);
$ node test.js bar foo
除非你使用user strict
,this
會變爲underfined
<script type="text/javascript"> foo = "bar"; function testThis() { "use strict"; this.foo = "foo"; } console.log(this.foo); //logs "bar" testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined </script>
當你new
一個函數的時候,this
會成爲一個新的上下文,不等同於全局this
<script type="text/javascript"> foo = "bar"; function testThis() { this.foo = "foo"; } console.log(this.foo); //logs "bar" new testThis(); console.log(this.foo); //logs "bar" console.log(new testThis().foo); //logs "foo" </script>
函數對象有一個特殊的屬性prototype
,當你建立一個函數實例,能夠訪問prototype
屬性,可使用this
進行訪問
function Thing() { console.log(this.foo); } Thing.prototype.foo = "bar"; var thing = new Thing(); //logs "bar" console.log(thing.foo); //logs "bar"
加入建立多個實例化,它們共享原型上的值,this.foo
都會返回相同的值,除非你在實例化函數上進行覆蓋。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } Thing.prototype.setFoo = function (newFoo) { this.foo = newFoo; } var thing1 = new Thing(); var thing2 = new Thing(); thing1.logFoo(); //logs "bar" thing2.logFoo(); //logs "bar" thing1.setFoo("foo"); thing1.logFoo(); //logs "foo"; thing2.logFoo(); //logs "bar"; thing2.foo = "foobar"; thing1.logFoo(); //logs "foo"; thing2.logFoo(); //logs "foobar";
this
在一個實例中是一個特殊的對象,this
實際是一個關鍵字,能夠認爲this
做爲一種方法去訪問prototype
,直接分配給this
,將會覆蓋原來prototype
上的方法。你能夠刪除this
掛接的方法,從而恢復訪問默認prototype
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } Thing.prototype.setFoo = function (newFoo) { this.foo = newFoo; } Thing.prototype.deleteFoo = function () { delete this.foo; } var thing = new Thing(); thing.setFoo("foo"); thing.logFoo(); //logs "foo"; thing.deleteFoo(); thing.logFoo(); //logs "bar"; thing.foo = "foobar"; thing.logFoo(); //logs "foobar"; delete thing.foo; thing.logFoo(); //logs "bar";
或者直接引用函數對象的原型。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo, Thing.prototype.foo); } var thing = new Thing(); thing.foo = "foo"; thing.logFoo(); //logs "foo bar";
建立的實例都共享相同的屬性和方法,若是給prototype
分配一個數組,全部實例都可以訪問。
function Thing() { } Thing.prototype.things = []; var thing1 = new Thing(); var thing2 = new Thing(); thing1.things.push("foo"); console.log(thing2.things); //logs ["foo"]
在prototype
上分配一個數組一般是一個錯誤,若是但願每一個實例都有本身的數組,那在函數中建立。
function Thing() { this.things = []; } var thing1 = new Thing(); var thing2 = new Thing(); thing1.things.push("foo"); console.log(thing1.things); //logs ["foo"] console.log(thing2.things); //logs []
this
能夠經過原型鏈找到相應的方法。
function Thing1() { } Thing1.prototype.foo = "bar"; function Thing2() { } Thing2.prototype = new Thing1(); var thing = new Thing2(); console.log(thing.foo); //logs "bar"
在javascript中可使用原型鏈模擬傳統面向對象繼承。
使用函數內含有綁定this
的方法或者屬性去建立原型鏈,將會隱藏上層原型鏈定義的內容。
function Thing1() { } Thing1.prototype.foo = "bar"; function Thing2() { this.foo = "foo"; } Thing2.prototype = new Thing1(); function Thing3() { } Thing3.prototype = new Thing2(); var thing = new Thing3(); console.log(thing.foo); //logs "foo"
我喜歡叫綁定在原型上的函數爲methods.在methods中使用this
綁定某個值,將會覆蓋原型上的相關定義。
function Thing1() { } Thing1.prototype.foo = "bar"; Thing1.prototype.logFoo = function () { console.log(this.foo); } function Thing2() { this.foo = "foo"; } Thing2.prototype = new Thing1(); var thing = new Thing2(); thing.logFoo(); //logs "foo";
在JavaScript嵌套函數中,雖然能夠捕獲到父函數中的變量,可是不繼承this
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { var info = "attempting to log this.foo:"; function doIt() { console.log(info, this.foo); } doIt(); } var thing = new Thing(); thing.logFoo(); //logs "attempting to log this.foo: undefined"
函數doIt中的this
指向global
,在use strict
下則爲undefined
,這是不少不熟悉this
用法的人痛苦的根源之一。
更壞的狀況是,將一個實例方法做爲參數傳入函數。this
將指向global
,在use strict
下則爲undefined
。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } function doIt(method) { method(); } var thing = new Thing(); thing.logFoo(); //logs "bar" doIt(thing.logFoo); //logs undefined
一些人把this
賦值給一個變量,一般叫self,可以避免this
指向global
這個問題。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { var self = this; var info = "attempting to log this.foo:"; function doIt() { console.log(info, self.foo); } doIt(); } var thing = new Thing(); thing.logFoo(); //logs "attempting to log this.foo: bar"
可是這種方法在將一個實例方法做爲參數傳入函數狀況下,不起做用
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { var self = this; function doIt() { console.log(self.foo); } doIt(); } function doItIndirectly(method) { method(); } var thing = new Thing(); thing.logFoo(); //logs "bar" doItIndirectly(thing.logFoo); //logs undefined
解決這個方法,可使用函數綁定的方法bind
。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } function doIt(method) { method(); } var thing = new Thing(); doIt(thing.logFoo.bind(thing)); //logs bar
你也可使用apply
或者call
在新的上下文環境中調用方法或者函數。
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { function doIt() { console.log(this.foo); } doIt.apply(this); } function doItIndirectly(method) { method(); } var thing = new Thing(); doItIndirectly(thing.logFoo.bind(thing)); //logs bar
可使用bind
替換this
,適用於任何函數或方法,即便沒有在實例原型上定義。
function Thing() { } Thing.prototype.foo = "bar"; function logFoo(aStr) { console.log(aStr, this.foo); } var thing = new Thing(); logFoo.bind(thing)("using bind"); //logs "using bind bar" logFoo.apply(thing, ["using apply"]); //logs "using apply bar" logFoo.call(thing, "using call"); //logs "using call bar" logFoo("using nothing"); //logs "using nothing undefined"
避免從構造函數返回任何東西,由於它可能會替換所產生的實例。
function Thing() { return {}; } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } var thing = new Thing(); thing.logFoo(); //Uncaught TypeError: undefined is not a function
奇怪的是,假如你返回的是原始值(string或者number),返回語句將會被忽略。最好不要從你打算調用的構造函數中返回任何東西,即便你知道你在作什麼。若是你想建立一個工廠模式,使用一個函數來建立實例,不要用new
的。固然,這只是我的觀點。
避免使用new
`,使用Object.create
也能建立一個實例
function Thing() { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } var thing = Object.create(Thing.prototype); thing.logFoo(); //logs "bar"
然而這不會調用構造函數。
function Thing() { this.foo = "foo"; } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { console.log(this.foo); } var thing = Object.create(Thing.prototype); thing.logFoo(); //logs "bar"
由於Object.create
不會調用構造函數,因此這是一個有效的建立繼承模式的方法,可以重寫原型鏈上的構造函數。
function Thing1() { this.foo = "foo"; } Thing1.prototype.foo = "bar"; function Thing2() { this.logFoo(); //logs "bar" Thing1.apply(this); this.logFoo(); //logs "foo" } Thing2.prototype = Object.create(Thing1.prototype); Thing2.prototype.logFoo = function () { console.log(this.foo); } var thing = new Thing2();
能夠在對象的任何函數中使用this
來引用該對象上的其餘屬性。這與使用new
實例不一樣。
var obj = { foo: "bar", logFoo: function () { console.log(this.foo); } }; obj.logFoo(); //logs "bar"
不使用new
,Object.create
,function
去建立一個對象,也能夠像實例化同樣綁定到對象上。
var obj = { foo: "bar" }; function logFoo() { console.log(this.foo); } logFoo.apply(obj); //logs "bar"
當你像下面使用this
時,沒有順着對象的層次結構。只有直接父對象上的屬性才能經過this
進行訪問
var obj = { foo: "bar", deeper: { logFoo: function () { console.log(this.foo); } } }; obj.deeper.logFoo(); //logs undefined
你能夠直接使用你想要的屬性。
var obj = { foo: "bar", deeper: { logFoo: function () { console.log(obj.foo); } } }; obj.deeper.logFoo(); //logs "bar"
在一個HTML DOM event處理程序中,this
一般是指DOM element event綁定的對象
function Listener() { document.getElementById("foo").addEventListener("click", this.handleClick); } Listener.prototype.handleClick = function (event) { console.log(this); //logs "<div id="foo"></div>" } var listener = new Listener(); document.getElementById("foo").click();
除非你綁定新的上下文
function Listener() { document.getElementById("foo").addEventListener("click", this.handleClick.bind(this)); } Listener.prototype.handleClick = function (event) { console.log(this); //logs Listener {handleClick: function} } var listener = new Listener(); document.getElementById("foo").click();
在HTML屬性中能夠放js代碼,this
指向當前的元素
<div id="foo" onclick="console.log(this);"></div> <script type="text/javascript"> document.getElementById("foo").click(); //logs <div id="foo"... </script>
this的覆蓋
你不可以複寫this
,由於它是一個關鍵詞
function test () { var this = {}; // Uncaught SyntaxError: Unexpected token this }
可使用eavl
訪問this
function Thing () { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { eval("console.log(this.foo)"); //logs "bar" } var thing = new Thing(); thing.logFoo();
這種作法有安全隱患,可使用Function
訪問this
function Thing () { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = new Function("console.log(this.foo);"); var thing = new Thing(); thing.logFoo(); //logs "bar"
可使用with
將this
添加到當前的範圍來讀取和寫入值,而不用顯式調用。
function Thing () { } Thing.prototype.foo = "bar"; Thing.prototype.logFoo = function () { with (this) { console.log(foo); foo = "foo"; } } var thing = new Thing(); thing.logFoo(); // logs "bar" console.log(thing.foo); // logs "foo"
不少人認爲這是錯的作法,鑑於with
引發的歧義。
像HTML DOM elements的事件處理程序同樣,jQuery在不少地方使用this
指向DOM元素。好比$.each
<div class="foo bar1"></div> <div class="foo bar2"></div> <script type="text/javascript"> $(".foo").each(function () { console.log(this); //logs <div class="foo... }); $(".foo").on("click", function () { console.log(this); //logs <div class="foo... }); $(".foo").each(function () { this.click(); }); </script>
鑑於筆者翻譯水平有限,有什麼問題歡迎提出指教。
原文地址:all this