// this是什麼
// 全局環境中的this
// 函數中的this
// 方法中的this
// 事件中的函數中的this
// 構造函數中this
// call和apply
// bind
// 箭頭函數中的this
// 嚴格模式下的一些狀況數組
js中的this關鍵字是包含它的函數做爲方法被調用時所屬的對象。瀏覽器
看似很抽象的一句話,但實際理解起來比較困難,咱們能夠分3部分來理解它!
一、包含它的函數。二、做爲方法被調用時。三、所屬的對象。app
首先咱們先來看一下js中非嚴格模式下的this分別都是什麼函數
在全局執行上下文中(在任何函數體外部)this 都指代全局對象。this
// 在瀏覽器中, window 對象同時也是全局對象: console.log(this === window); // true a = 37; console.log(window.a); // 37 this.b = "MDN"; console.log(window.b) // "MDN" console.log(b) // "MDN"
絕大多數狀況下,函數的調用方式決定了this的值。prototype
在嚴格模式和非嚴格模式之間也會有一些差異。code
function f1(){ return this; } //在瀏覽器中: f1() === window; //在瀏覽器中,全局對象是window
然而,在嚴格模式下,this將保持他進入執行上下文時的值,因此下面的this將會默認爲undefined。對象
function f2(){ "use strict"; // 這裏是嚴格模式 return this; } f2() === undefined; // true
自執行函數執行,方法中的this通常都是window繼承
var obj = { fn: (function() { // this -> window })() }; ~function() { // this -> window }()
咱們說定義在對象內的函數叫作方法,而這個方法執行的時候,它的this就是它的調用者事件
var obj = { fn: function () { console.log(this); } }; obj.fn();
此時fn方法的調用者爲obj,因此fn中的this就是obj對象;
但咱們把這個方法賦值給一個自由變量的時候
var f1 = obj.fn; f1();
此時f1執行,實際是obj.fn執行,但f1的調用者其實是 window, window.f1() 因此fn中的this是window
下面再看一個例子,
咱們調用數組上的slice方法,
[].slice(); // this -> [] [].__proto__.slice(); // this -> [].__proto__ Array.prototype.slice(); // this -> Array.prototype
三種調用的slice方法是同樣的,但調用的方式不一樣,裏面的this也不一樣
給元素的某個事件綁定了一個方法,當事件觸發,函數執行的時候,綁定的這個方法中的this通常是當前操做的這個DOM元素
'二般'狀況下
IE6~8下,若是咱們使用DOM2事件綁定,方法執行的時候,裏面的this不是當前元素,而是window
ele.attachEvent('onclick', function() { console.log(this); // window });
構造函數執行的時候,函數體中的this都是當前實例;
function Fn() { // this -> 當前Fn的實例 // this.name 是給當前實例設置私有屬性 this.name = '1000phone' } var f = new Fn();
當一個函數在其主體中使用 this 關鍵字時,能夠經過使用函數繼承自Function.prototype 的 call 或 apply 方法將 this 值綁定到調用中的特定對象。
var school = {name: '1000phone'}; function sum(num1, num2) { this.total = num1 + num2; } sum(20, 30); // this -> window sum.call(school, 20, 30);
首先讓 sum 中的this指向call方法中的第一個參數,而後執行sum這個函數
此時 sum 中的 this -> school num1 -> 20 num2 -> 30
參數位置是固定的,若是第一個參數不是 school
sum.call(20, 30);
這時候 sum 的this 是 20,num1 -> 30 num2 -> undefined
若是咱們一個參數都不傳
sum.call();
sum 的 this -> window num1 = num2 = undefined
至關於 sum 直接執行,不傳參
sum();
但若是第一個參數爲null或者undefined
那麼就表明沒有this,函數中的this依然是window
apply語法與做用,和call相似,只有一個區別,apply傳入一組參數
sum.call(school, 20, 30); sum.apply(school, [20, 30]);
apply的語法要求寫成一個數組,但實際和call同樣,也是一項一項的給形參賦值的
~function () { console.log(this); }.call(school);
此時 自執行函數中的this被call指向爲 school
Array.prototype.slice.call(arguments);
此時slice方法執行的時候中的this將再也不是 Array.prototype,而是arguments
call和apply以前的規則,遇到call/apply時,都將以用戶自主指向的this爲主
ECMAScript 5 引入了 Function.prototype.bind。調用f.bind(someObject)會建立一個與f具備相同函數體和做用域的函數,可是在這個新函數中,this將永久地被綁定到了bind的第一個參數,不管這個函數是如何被調用的。
var school = {name: '1000phone'}; function sum(num1, num2) { this.total = num1 + num2; } sum.call(school, 20, 30);
this -> school 而且執行sum
sum.bind(school, 20, 30);
雖然改變了this指向,但並無執行sum,它是預先處理this和實參,不會當即執行,
一般咱們讓它在某個特定條件,纔會被觸發 IE6~8不兼容
例如咱們有個需求,一秒後執行sum,此時須要定時器,執行sum時,sum中this指向school,而且傳參。
setTimeout(sum, 1000);
咱們一秒後執行sum函數
但此時sum中的this是window
setTimeout(sum.call(school, 20, 30), 1000);
此時實現了this的指向而且傳了參數,但sum當即執行了,不是一秒後
setTimeout(function() { sum.call(school, 20, 30); }, 1000);
咱們能夠達到一秒後執行sum,this指向爲shool,而且傳參,執行,但代碼並不理想,咱們能夠使用bind預處理可以達到咱們的目的
setTimeout(sum.bind(school, 20, 30), 1000);
var obj = { fn: function() { setTimeout(function() { // this -> window }, 1000); var that = this; setTimeout(function() { // that -> obj }, 1000); setTimeout(function() { // this -> obj }.bind(this), 1000); setTimeout(() => { // this -> obj }, 1000); } };
在箭頭函數中,this與封閉詞法上下文的this保持一致,也就是說箭頭函數中繼承了詞法做用域的this
非嚴格模式下,不明確執行主體,瀏覽器認爲執行主體默認爲window,因此this是window
嚴格模式下,執行主體不明確,this是undefined
'use strict' ~function(){ // this -> undefined }(); fn() // undefined window.fn() // window fn.call() // undefined fn.call(window) // window fn.call(null) // null fn.call(undefined) // undefined
apply同call
能夠理解爲含有this的函數的調用者。而且this和函數在哪執行的,以及定義的位置沒有直接關係。
歡迎來噴!