Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
源:Loong Panda
一、不同環(huán)境下的this的指向:
1、this的指向是在函數運行時確定下來的,而不是創(chuàng)建的時候,誰調用就指向誰。
2、ES5中普通函數this指向window,ES6中普通函數this指向為undefined;
3、事件的this指向,為事件源本身
4、定時器的this指向,為window.
5、構造函數內部的this指向new出來的這個對象
注: 嚴格模式下,普通函數和全局環(huán)境的this為undefined
consolog.log(this) // window
function test() { console.log(111, this) // window } test()
注: 'use strict' 嚴格模式下
consolog.log(this) // undefined
function test() { console.log(111, this) // undefined } test()
let obj3={
say() {
console.log(6666, this) // obj3
return function () {
console.log(7777, this) // window
}
}
}
obj3.say()()
function Person(e) {
this.name=e console.log(5555, this)
}
let a=new Person('李四1') // Person { name: '李四1'}
let b=new Person('李四2') // Person { name: '李四2'}
let obj2={
name: '張三',
say: function () {
console.log(333, this) // obj2
setTimeout(function () {
console.log(444, this) // window
}, 1000)
}
}
obj2.say()
let obj3={
say() {
console.log(6666, this) // obj3
return ()=> {
console.log(7777, this) // obj3
}
}
}
obj3.say()()
二、改變this指向的方法:
1、箭頭函數 -----> 只適合現代瀏覽器;
2、bind() -----> 第一個是參數是指向誰,第二個以后的參數是自定義的參數,需要單獨調用才執(zhí)行,如: bind(obj)()
3、call(xx, arg1, arg2) -----> 第一個是參數是指向誰,第二個以后的參數是自定義的參數
4、apply(xx, [arg1, arg2]) -----> 第一個是參數是指向誰,第二個的參數是自定義的參數,數據類型必須是數組
在 Java 等面向對象的語言中,this 關鍵字的含義是明確且具體的,即指代當前對象。一般在編譯期確定下來,或稱為編譯期綁定。而在 JavaScript 中,this 是動態(tài)綁定,或稱為運行期綁定的,這就導致 JavaScript 中的 this 關鍵字有能力具備多重含義,帶來靈活性的同時,也為初學者帶來不少困惑。本文僅就這一問題展開討論,閱罷本文,讀者若能正確回答 JavaScript 中的 What 's this 問題,那就會覺得花費這么多功夫,撰寫這樣一篇文章是值得的。
在 Java 中定義類經常會使用 this 關鍵字,多數情況下是為了避免命名沖突,比如在下面例子的中,定義一個 Point 類,很自然的,大家會使用 x,y 為其屬性或成員變量命名,在構造函數中,使用 x,y 為參數命名,相比其他的名字,比如 a,b,也更有意義。這時候就需要使用 this 來避免命名上的沖突。另一種情況是為了方便的調用其他構造函數,比如定義在 x 軸上的點,其 x 值默認為 0,使用時只要提供 y 值就可以了,我們可以為此定義一個只需傳入一個參數的構造函數。無論哪種情況,this 的含義是一樣的,均指當前對象。
清單 1. Point.java
由于其運行期綁定的特性,JavaScript 中的 this 含義要豐富得多,它可以是全局對象、當前對象或者任意對象,這完全取決于函數的調用方式。JavaScript 中函數的調用有以下幾種方式:作為對象方法調用,作為函數調用,作為構造函數調用,和使用 apply 或 call 調用。下面我們將按照調用方式的不同,分別討論 this 的含義。
在 JavaScript 中,函數也是對象,因此函數可以作為一個對象的屬性,此時該函數被稱為該對象的方法,在使用這種調用方式時,this 被自然綁定到該對象。
清單 2. point.js
函數也可以直接被調用,此時 this 綁定到全局對象。在瀏覽器中,window 就是該全局對象。比如下面的例子:函數被調用時,this 被綁定到全局對象,接下來執(zhí)行賦值語句,相當于隱式的聲明了一個全局變量,這顯然不是調用者希望的。
清單 3. nonsense.js
對于內部函數,即聲明在另外一個函數體內的函數,這種綁定到全局對象的方式會產生另外一個問題。我們仍然以前面提到的 point 對象為例,這次我們希望在 moveTo 方法內定義兩個函數,分別將 x,y 坐標進行平移。結果可能出乎大家意料,不僅 point 對象沒有移動,反而多出兩個全局變量 x,y。
清單 4. point.js
這屬于 JavaScript 的設計缺陷,正確的設計方式是內部函數的 this 應該綁定到其外層函數對應的對象上,為了規(guī)避這一設計缺陷,聰明的 JavaScript 程序員想出了變量替代的方法,約定俗成,該變量一般被命名為 that。
清單 5. point2.js
JavaScript 支持面向對象式編程,與主流的面向對象式編程語言不同,JavaScript 并沒有類(class)的概念,而是使用基于原型(prototype)的繼承方式。相應的,JavaScript 中的構造函數也很特殊,如果不使用 new 調用,則和普通函數一樣。作為又一項約定俗成的準則,構造函數以大寫字母開頭,提醒調用者使用正確的方式調用。如果調用正確,this 綁定到新創(chuàng)建的對象上。
清單 6. Point.js
讓我們再一次重申,在 JavaScript 中函數也是對象,對象則有方法,apply 和 call 就是函數對象的方法。這兩個方法異常強大,他們允許切換函數執(zhí)行的上下文環(huán)境(context),即 this 綁定的對象。很多 JavaScript 中的技巧以及類庫都用到了該方法。讓我們看一個具體的例子:
清單 7. Point2.js
在上面的例子中,我們使用構造函數生成了一個對象 p1,該對象同時具有 moveTo 方法;使用對象字面量創(chuàng)建了另一個對象 p2,我們看到使用 apply 可以將 p1 的方法應用到 p2 上,這時候 this 也被綁定到對象 p2 上。另一個方法 call 也具備同樣功能,不同的是最后的參數不是作為一個數組統(tǒng)一傳入,而是分開傳入的。
如果像作者一樣,大家也覺得上述四種方式不方便記憶,過一段時間后,又搞不明白 this 究竟指什么。那么我向大家推薦 Yehuda Katz 的這篇文章:( http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/)。在這篇文章里,Yehuda Katz 將 apply 或 call 方式作為函數調用的基本方式,其他幾種方式都是在這一基礎上的演變,或稱之為語法糖。Yehuda Katz 強調了函數調用時 this 綁定的過程,不管函數以何種方式調用,均需完成這一綁定過程,不同的是,作為函數調用時,this 綁定到全局對象;作為方法調用時,this 綁定到該方法所屬的對象。
通過上面的描述,如果大家已經能明確區(qū)分各種情況下 this 的含義,這篇文章的目標就已經完成了。如果大家的好奇心再強一點,想知道為什么 this 在 JavaScript 中的含義如此豐富,那就得繼續(xù)閱讀下面的內容了。作者需要提前告知大家,下面的內容會比前面稍顯枯燥,如果只想明白 this 的含義,閱讀到此已經足夠了。如果大家不嫌枯燥,非要探尋其中究竟,那就一起邁入下一節(jié)吧。
JavaScript 中的函數既可以被當作普通函數執(zhí)行,也可以作為對象的方法執(zhí)行,這是導致 this 含義如此豐富的主要原因。一個函數被執(zhí)行時,會創(chuàng)建一個執(zhí)行環(huán)境(ExecutionContext),函數的所有的行為均發(fā)生在此執(zhí)行環(huán)境中,構建該執(zhí)行環(huán)境時,JavaScript 首先會創(chuàng)建 arguments變量,其中包含調用函數時傳入的參數。接下來創(chuàng)建作用域鏈。然后初始化變量,首先初始化函數的形參表,值為 arguments變量中對應的值,如果 arguments變量中沒有對應值,則該形參初始化為 undefined。如果該函數中含有內部函數,則初始化這些內部函數。如果沒有,繼續(xù)初始化該函數內定義的局部變量,需要注意的是此時這些變量初始化為 undefined,其賦值操作在執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功后,函數執(zhí)行時才會執(zhí)行,這點對于我們理解 JavaScript 中的變量作用域非常重要,鑒于篇幅,我們先不在這里討論這個話題。最后為 this變量賦值,如前所述,會根據函數調用方式的不同,賦給 this全局對象,當前對象等。至此函數的執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功,函數開始逐行執(zhí)行,所需變量均從之前構建好的執(zhí)行環(huán)境(ExecutionContext)中讀取。
有了前面對于函數執(zhí)行環(huán)境的描述,我們來看看 this 在 JavaScript 中經常被誤用的一種情況:回調函數。JavaScript 支持函數式編程,函數屬于一級對象,可以作為參數被傳遞。請看下面的例子 myObject.handler 作為回調函數,會在 onclick 事件被觸發(fā)時調用,但此時,該函數已經在另外一個執(zhí)行環(huán)境(ExecutionContext)中執(zhí)行了,this 自然也不會綁定到 myObject 對象上。
清單 8. callback.js
button.onclick=myObject.handler;
這是 JavaScript 新手們經常犯的一個錯誤,為了避免這種錯誤,許多 JavaScript 框架都提供了手動綁定 this 的方法。比如 Dojo 就提供了 lang.hitch,該方法接受一個對象和函數作為參數,返回一個新函數,執(zhí)行時 this 綁定到傳入的對象上。使用 Dojo,可以將上面的例子改為:
清單 9. Callback2.js
button.onclick=lang.hitch(myObject, myObject.handler);
在新版的 JavaScript 中,已經提供了內置的 bind 方法供大家使用。
JavaScript 中的 eval 方法可以將字符串轉換為 JavaScript 代碼,使用 eval 方法時,this 指向哪里呢?答案很簡單,看誰在調用 eval 方法,調用者的執(zhí)行環(huán)境(ExecutionContext)中的 this 就被 eval 方法繼承下來了。簡單看個eval示例:
本文介紹了 JavaScript 中的 this 關鍵字在各種情況下的含義,雖然這只是 JavaScript 中一個很小的概念,但借此我們可以深入了解 JavaScript 中函數的執(zhí)行環(huán)境,而這是理解閉包等其他概念的基礎。掌握了這些概念,才能充分發(fā)揮 JavaScript 的特點,才會發(fā)現 JavaScript 語言特性的強大。
原文:https://dev.to/bhagatparwinder/arrow-function-basics-34cm
箭頭函數是在 ES6 引入的,相對于函數表達式來說是一種更簡潔的方式。
箭頭函數名稱的來源是因為使用了 =>。
const functionName = (arg1, arg2, ... argN) => {
return value;
}
const multiply = (a, b) => {
return a * b;
}
console.log(multiply(7, 8)); // 56
console.log(multiply(3, 2)); // 6
const square = x => {
return x * x;
}
console.log(square(2)); // 4
console.log(square(7)); // 49
這個情形的唯一陷阱是當只有一個參數且需要解構時:
const foo = ({name = "New User"}) => name;
console.log(foo({})); // New User
console.log(foo({name: "Parwinder"})); // Parwinder
const greeting = () => {
return "Hello World!";
}
console.log(greeting()); // Hello World!
const greeting = () => "Hello World!";
console.log(greeting()); // Hello World
現在我們知道了所有的關鍵特點,讓我們來重寫獲取正方形的面積:
const square = x => x * x;
console.log(square(4)); // 16
JavaScript 中的 this 關鍵字是執(zhí)行上下文的一個屬性,它可能是全局的、函數內的或者是 eval 中的。對于普通的函數,this 會根據調用它方式不同而變化。
我們使用這種行為已經很久了,以至于大多數JavaScript開發(fā)者都已經習慣了。
function foo() {
return this;
};
console.log(foo()); // window object in a browser, global object for node execution
function Order(main, side, dessert) {
this.main = main;
this.side = side;
this.dessert = dessert;
this.order = function () {
return `I will have ${this.main} with ${this.side} and finish off with a ${this.dessert}`;
}
}
const newOrder = new Order("sushi", "soup", "yogurt");
console.log(newOrder.order());
// I will have sushi with soup and finish off with a yogurt
const myObject = {
main: "butter chicken",
side: "rice",
dessert: "ice cream",
order: function () {
return `I will have ${this.main} with ${this.side} and finish off with ${this.dessert}`;
}
}
console.log(myObject.order());
// I will have butter chicken with rice and finish off with ice cream
上面的例子中,this 指向 myObject,可以獲取它上面的屬性。
"use strict";
function foo() {
return this;
};
console.log(foo() === undefined); // true
*請認真填寫需求信息,我們會在24小時內與您取得聯(lián)系。