日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

JavaScript中this的運行機制及爬坑指南

瀏覽:166日期:2023-11-11 09:04:39

在 JavaScript 中,this 這個特殊的變量是相對比較復雜的,因為 this 不僅僅用在面向對象環境中,在其他任何地方也是可用的。 本篇博文中會解釋 this 是如何工作的以及使用中可能導致問題的地方,最后奉上最佳實踐。

JavaScript中this的運行機制及爬坑指南

為了更好理解 this,將 this 使用的場景分成三類:

在函數內部 this 一個額外的,通常是隱含的參數。

在函數外部(頂級作用域中): 這指的是瀏覽器中的全局對象或者 Node.js 中一個模塊的輸出。

在傳遞給eval()的字符串中: eval() 或者獲取 this 當前值值,或者將其設置為全局對象,取決于 this 是直接調用還是間接調用。

我們來看看每個類別。

 this 在函數中

這是最常用的 this 使用方式,函數通過扮演三種不同的角色來表示 JavaScript 中的所有可調用結構體:

普通函數(this 在非嚴格模式下為全局對象,在嚴格模式下為undefined)

構造函數(this 指向新創建的實例)

方法(this 是指方法調用的接收者)

在函數中,this 通常被認為是一個額外的,隱含的參數。

this 在普通函數中

在普通函數中,this 的值取決于模式:

非嚴格模式: this 是指向全局對象 (在瀏覽器中為window對象)。

function sloppyFunc() { console.log(this === window); // true}sloppyFunc();嚴格模式: this 的值為 undefined。

function strictFunc() { 'use strict'; console.log(this === undefined); // true}strictFunc();

也就是說,this 是一個設定了默認值(window或undefined)的隱式參數。 但是,可以通過 call() 或 apply() 進行函數調用,并明確指定this的值:

function func(arg1, arg2) {console.log(this); // aconsole.log(arg1); // bconsole.log(arg2); // c } func.call('a', 'b', 'c'); // (this, arg1, arg2) func.apply('a', ['b', 'c']); // (this, arrayWithArgs)this 在構造函數中

如果通過new運算符調用函數,則函數將成為構造函數。 該運算符創建一個新的對象,并通過它通過this傳遞給構造函數:

var savedThis; function Constr() {savedThis = this; } var inst = new Constr(); console.log(savedThis === inst); // true

在JavaScript中實現,new運算符大致如下所示(更精確的實現稍微復雜一點):

function newOperator(Constr, arrayWithArgs) {var thisValue = Object.create(Constr.prototype);Constr.apply(thisValue, arrayWithArgs);return thisValue; }this 在方法中

在方法中,類似于傳統的面向對象的語言:this指向接受者,方法被調用的對象。

var obj = {method: function () { console.log(this === obj); // true} } obj.method(); this 在頂級作用域中

在瀏覽器中,頂層作用域是全局作用域,它指向global object(如window):

console.log(this === window); // true

在Node.js中,通常在模塊中執行代碼。 因此,頂級作用域是一個特殊的模塊作用域:

// `global` (不是 `window`) 指全局對象: console.log(Math === global.Math); // true // `this` 不指向全局對象: console.log(this !== global); // true // `this` refers to a module’s exports: console.log(this === module.exports); // true this 在 eval() 中

eval() 可以被直接(通過真正的函數調用)或間接(通過其他方式)。 詳細解釋在這里。

如果間接調用evaleval() ,則this指向全局對象:

(0,eval)('this === window') true

否則,如果直接調用eval() ,則this與eval()的環境中保持一致。 例如:

// 普通函數 function sloppyFunc() {console.log(eval('this') === window); // true } sloppyFunc(); function strictFunc() {'use strict';console.log(eval('this') === undefined); // true } strictFunc(); // 構造器 var savedThis; function Constr() {savedThis = eval('this'); } var inst = new Constr(); console.log(savedThis === inst); // true // 方法 var obj = {method: function () { console.log(eval('this') === obj); // true} } obj.method(); 與this相關的陷阱

有三個你需要知道的與this相關的陷阱。請注意,在各種情況下,嚴格模式更安全,因為this在普通函數中為undefined,并且會在出現問題時警告。

陷阱:忘記new操作符

如果你調用一個構造函數時忘記了new操作符,那么你意外地將this用在一個普通的函數。this會沒有正確的值。 在非嚴格模式下,this指向window對象,你將創建全局變量:

function Point(x, y) {this.x = x;this.y = y; } var p = Point(7, 5); // 忘記new! console.log(p === undefined); // true // 創建了全局變量: console.log(x); // 7 console.log(y); // 5

幸運的,在嚴格模式下會得到警告(this === undefined):

function Point(x, y) {'use strict';this.x = x;this.y = y; } var p = Point(7, 5); // TypeError: Cannot set property 'x' of undefined陷阱:不正確地提取方法

如果獲取方法的值(不是調用它),則可以將該方法轉換為函數。 調用該值將導致函數調用,而不是方法調用。 當將方法作為函數或方法調用的參數傳遞時,可能會發生這種提取。 實際例子包括setTimeout()和事件注冊處理程序。 我將使用函數callItt() 來模擬此用例:

/**類似setTimeout() 和 setImmediate() */ function callIt(func) {func(); }

如果在非嚴格模式下把一個方法作為函數來調用,那么this將指向全局對象并創建全局變量:

var counter = {count: 0,// Sloppy-mode methodinc: function () { this.count++;} } callIt(counter.inc); // Didn’t work: console.log(counter.count); // 0 // Instead, a global variable has been created // (NaN is result of applying ++ to undefined): console.log(count); // NaN

如果在嚴格模式下把一個方法作為函數來調用,this為undefined。 同時會得到一個警告:

var counter = {count: 0,// Strict-mode methodinc: function () { 'use strict'; this.count++;} } callIt(counter.inc); // TypeError: Cannot read property 'count' of undefined console.log(counter.count);

修正方法是使用[bind()](http://speakingjs.com/es5/ch17.html#Function.prototype.bind): The fix is to use bind():

var counter = {count: 0,inc: function () { this.count++;} } callIt(counter.inc.bind(counter)); // 成功了! console.log(counter.count); // 1

bind()創建了一個新的函數,它總是接收一個指向counter的this。

陷阱:shadowing this

當在一個方法中使用普通函數時,很容易忘記前者具有其自己this(即使其不需要this)。 因此,你不能從前者引用該方法的this,因為該this會被遮蔽。 讓我們看看出現問題的例子:

var obj = {name: 'Jane',friends: [ 'Tarzan', 'Cheeta' ],loop: function () { 'use strict'; this.friends.forEach(function (friend) { console.log(this.name+' knows '+friend);} );} }; obj.loop(); // TypeError: Cannot read property 'name' of undefined

在前面的例子中,獲取this.name失敗,因為函數的this個是undefined,它與方法loop()的不同。 有三種方法可以修正this。

修正1: that = this。 將它分配給一個沒有被遮蔽的變量(另一個流行名稱是self)并使用該變量。

loop: function () {'use strict';var that = this;this.friends.forEach(function (friend) { console.log(that.name+' knows '+friend);}); }

修正2: bind()。 使用bind()來創建一個this總是指向正確值的函數(在下面的例子中該方法的this)。

loop: function () {'use strict';this.friends.forEach(function (friend) { console.log(this.name+' knows '+friend);}.bind(this)); }

修正3: forEach的第二個參數。 此方法具有第二個參數,this值將作為此值傳遞給回調函數。

loop: function () {'use strict';this.friends.forEach(function (friend) { console.log(this.name+' knows '+friend);}, this); } 最佳實踐

從概念上講,我認為普通函數沒有它自己的this,并且想到上述修復是為了保持這種想法。 ECMAScript 6通過[箭頭函數](http://2ality.com/2012/04/arrow-functions.html)支持這種方法 - 沒有它們自己的this。 在這樣的函數里面,你可以自由使用this,因為不會被屏蔽:

loop: function () {'use strict';// The parameter of forEach() is an arrow functionthis.friends.forEach(friend => { // `this` is loop’s `this` console.log(this.name+' knows '+friend);}); }

我不喜歡使用this作為普通函數的附加參數的API:

beforeEach(function () { this.addMatchers({ toBeInRange: function (start, end) { ... } }); });

將這樣的隱含參數變成明確的參數使得事情更加明顯,并且與箭頭函數兼容。

beforeEach(api => {api.addMatchers({ toBeInRange(start, end) {... }}); });

標簽: JavaScript
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲精品电影| 欧美日韩国产探花| 四虎在线精品| 日本伊人久久| 欧美在线观看天堂一区二区三区| 亚洲精选久久| 日本综合视频| 欧美交a欧美精品喷水| 久久精品国产亚洲一区二区三区| 视频在线观看国产精品| 日韩啪啪电影网| 成人亚洲一区| 国产专区一区| 日韩专区在线视频| 日韩在线电影| 久久亚洲精精品中文字幕| 成人国产精品| 激情91久久| 日韩高清在线一区| 综合日韩av| 亚洲午夜视频| 国精品一区二区| 中文字幕一区二区精品区| 日韩福利视频导航| 精品美女视频 | 国产综合亚洲精品一区二| 香蕉精品999视频一区二区| 国产精品久久久久77777丨| 国产精品红桃| 午夜av一区| 另类欧美日韩国产在线| 精精国产xxxx视频在线野外| 欧美久久精品一级c片| 免费在线观看精品| 国产精品nxnn| 欧美午夜不卡| 国产精东传媒成人av电影| 激情婷婷欧美| 久久精品毛片| 欧美日韩在线播放视频| japanese国产精品| 国产免费av国片精品草莓男男| zzzwww在线看片免费| 日本欧美在线看| 福利精品在线| 国产精品久av福利在线观看| 蜜臀91精品国产高清在线观看| 日本伊人午夜精品| 丁香婷婷久久| 91成人精品在线| 影音先锋国产精品| 久久69成人| 国产99久久| 国产亚洲人成a在线v网站| 日韩午夜在线| 999精品在线| 久久久久久夜| 蜜桃精品视频| 欧美激情三区| 久久久久伊人| 欧美偷窥清纯综合图区| 亚洲精品第一| 亚洲乱码一区| 免费观看不卡av| 亚洲a在线视频| 日本va欧美va精品| 日韩一级欧洲| 国产一区白浆| 久久国产福利| 中文字幕日本一区| 少妇精品在线| 97精品国产99久久久久久免费| 久久最新视频| 丝袜国产日韩另类美女| 免费在线观看视频一区| 老牛国产精品一区的观看方式| 久久久影院免费| 99精品综合| 日本亚洲欧美天堂免费| 亚洲开心激情| 国产欧美久久一区二区三区| 日韩精品视频在线看| 国产日韩高清一区二区三区在线 | 国产伦精品一区二区三区千人斩 | 成人精品视频| 精品三级久久| 婷婷综合亚洲| 日韩欧美2区| 久久亚洲道色| 久久一区二区中文字幕| 免费不卡在线视频| 国产伦理久久久久久妇女| 老司机精品视频在线播放| 欧美丰满日韩| 欧美天堂亚洲电影院在线观看| 免费在线视频一区| 亚洲成人日韩| 免费的成人av| 欧美亚洲综合视频| 另类中文字幕国产精品| 中文字幕亚洲在线观看| 美女视频网站久久| 亚洲婷婷在线| 欧美精品中文字幕亚洲专区| 9999国产精品| 亚洲精品影院在线观看| 成年男女免费视频网站不卡| 日韩亚洲在线| 精品国产a一区二区三区v免费| 欧美日韩视频一区二区三区| 在线亚洲观看| 丁香婷婷久久| 亚洲+小说+欧美+激情+另类| 国产精品极品在线观看| 尤物在线精品| 在线天堂中文资源最新版| 视频一区日韩| 亚洲精品一区二区妖精| 国产精品久久久久久久久久妞妞| 欧美成人日韩| 美女国产一区二区三区| 综合激情一区| 日韩亚洲精品在线| 欧美亚洲精品在线| 国产精品自在| 日本aⅴ亚洲精品中文乱码| 99热精品在线观看| 亚洲黄色中文字幕| 日韩中文字幕在线一区| 一本一本久久| 亚洲精品在线观看91| 不卡一二三区| 日韩国产在线| 97se综合| 99视频精品全国免费| 久久uomeier| 国产白浆在线免费观看| 四虎8848精品成人免费网站| 一区二区三区国产在线| 亚洲欧美日韩精品一区二区 | 不卡av一区二区| 九九久久国产| 国产一区二区三区免费在线 | 日本美女一区| 久久天堂成人| 亚洲激情国产| 亚久久调教视频| 日韩av不卡在线观看| 日本中文字幕一区二区视频| 日韩精品一二三| 美女久久久久久| 亚洲高清久久| 国产亚洲一区| 欧美日韩国产免费观看视频| 久久电影一区| 国产videos久久| 亚洲久草在线| 精品亚洲美女网站| 青草综合视频| 蜜桃成人精品| 蜜臀av性久久久久蜜臀aⅴ四虎| 麻豆亚洲精品| 国产一区二区三区探花| 国产资源在线观看入口av| 欧美日韩视频网站| 麻豆成人av在线| 国产传媒av在线| 欧美精品黄色| 国产欧美日韩精品一区二区免费| 亚洲精品大全| 欧美国产不卡| 午夜国产一区二区| 日韩福利在线观看| 欧美激情麻豆| 日韩和的一区二在线| 亚洲大全视频| 日韩国产91| 日韩在线观看| 在线精品国产亚洲| 国产午夜精品一区二区三区欧美 | 国产色99精品9i| 一区二区三区四区日本视频| 成人片免费看| 日本亚洲视频在线| 欧美成a人国产精品高清乱码在线观看片在线观看久 | 亚洲v天堂v手机在线| 精品三级在线观看视频| 国产拍在线视频| 亚洲资源在线| 亚洲午夜av| 亚洲精品免费观看| 亚洲天堂一区二区| 不卡中文字幕| 国产精品亚洲综合色区韩国| 欧美日韩水蜜桃| 国产精品一页| 亚洲欧美日韩国产一区| 伊伊综合在线| 精品三级av| 国产免费播放一区二区|