this的值表示當前代碼所在的執行環境
複製代碼
當一進入函數上下文中,可是尚未開始執行函數體內的代碼時,此時js引擎會找到該上文 中全部的function declarations(FD)、variableDeclaration、arguments、thisValue、scopeChain等進行初始化,在這個階段(也就是說在函數調用階段)this的值才肯定。注意不是函數定義的時候知道的。node
事實上函數定義時的第一個參數就是this,只不過js將它隱藏了,咱們看不到,因此說this的值在調用階段才能肯定,由於不知道你會以什麼方式調用函數或者說不肯定你每次調用函數時傳入的參數值是什麼。瀏覽器
看下列代碼:
function fn() {
console.log(this)
}
fn() //window
1.以上代碼在函數被調用時並無傳入相應的參數那麼this值是怎麼獲取到的?
以前已經說過js將它隱藏了而已。
2.那爲何this的值是window呢?
當你在全局環境中或者在全局環境下調用函數時,this的值默認爲window(在非嚴格模式下)
3.call、apply、bind能夠修改this的值
將上述代碼當作下面這種形式就好理解了:
function fn() {
console.log(this) //window
}
fn.call(window) //實際上js給你傳了一個參數window進去,故你打出的this爲window
fn.apply(window)
複製代碼
好,到這裏你又有疑問了,那我經過fn.call(window)將window傳進去了,那麼在函數定義 的時候並無一個變量接收這個window參數啊,那this怎麼仍是可以打出來呢?bash
能夠參考arguments對象。app
function fn() {
console.log(arguments) //[5, 10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
}
fn.call(window, 5, 10)
在這裏函數fn定義的時候也沒有形式參數,那麼實參仍然能夠經過arguments獲取到,
那麼this的道理也是同樣的,this其實是函數定義時候的第一個參數,js將它隱藏了。
你能夠將上面代碼當作下面這種形式:
function fn(/*this這是隱藏的變量*/) {
console.log(arguments) //[5, 10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
}
fn.call(window, 5, 10)
複製代碼
經過以上能夠知道,在函數內部,this的值是取決於函數被調用的方式而不是定義的方式。函數
3.1 簡單調用ui
function f() {
return this
}
f() //在瀏覽器中爲window,在node中爲global,至關於下面這種調用方式
f.call(window/global) //這裏至關於將this的值指定爲window或global
複製代碼
在嚴格模式下,this將保持它進入執行環境時的值。若是this沒有被執行環境定義,那它的默認值就爲undefined。this
function f() {
"use strict"
return this
}
f() //undefined,至關於下面這樣
f.call(undefined)
複製代碼
3.2 做爲對象的方法spa
當函數做爲對象裏的方法被調用時,它們的this指向的是調用該函數的那個對象。prototype
let obj = {
age: 18,
getAge: function () {
return this.age
}
}
obj.getAge() //18,這裏的this指向obj;至關於下面這種調用方式
obj.getAge.call(obj) //18
複製代碼
3.3 做爲構造函數code
當一個函數用做構造函數時(使用new關鍵字),它的this被綁定到正在構造的新對象(實例)。
function Fn() {
this.age = 23
}
let fn = new Fn()
console.log(fn.age) //23
複製代碼
3.4 bind方法
ECMAScript5 引入了Function.prototype.bind。調用fn.bind(obj)會建立一個與fn具備相同函數體和做用域的函數,可是在這個新函數中,this將永久地被綁定到了bind的第一個參數,不管這個函數是如何被調用的。
let obj = {
name: 'jack',
address: 'china'
}
let name = 'tom'
function fn () {
console.log(this.name)
}
let f = fn.bind(obj)
f() //jack
f.call() //"jack"
f.call(obj) //"jack"
以上能夠看到不管函數f被如何調用,this都是指向obj
複製代碼
//在瀏覽器中window對象同時也是全局對象
this === window //true
a = 'l'
this.a === window.a //true
複製代碼
箭頭函數事實上根本沒有this,其this值是箭頭函數所在的那個最近環境中this的值。在全局環境中,它將被設置爲全局對象:
let arrow = () => this
console.log(arrow()) //window
複製代碼
var name = 'tony'
let obj = {
name: 'jack',
age: 25,
getName () {
return () => this.name
}
}
console.log(obj.getName()()) //'jack'
複製代碼
以上getName函數中返回的那個箭頭函數中的this值是該箭頭函數所在的那個最近環境中的this值,離該箭頭函數最近的一個環境是函數getName,而getName中的this爲obj,故箭頭函數中的this也爲obj,故打印出jack。
注意:在箭頭函數中,若是將this傳遞給call、bind、或者apply,它將被忽略。不過你仍然能夠爲調用添加參數,不過第一個參數應該設置爲null。看下列例子:
var name = 'tony'
let obj = {
name: 'jack',
age: 25,
getName() {
return () => this.name
}
}
let obj2 = {
name: 'ma'
}
console.log(obj.getName()()) //'jack'
console.log(obj.getName().call()) //'jack'
console.log(obj.getName().call(obj2)) //'jack'
複製代碼
注意如下一點要進行區分:
var name = 'tony'
let obj = {
name: 'jack',
age: 25,
getName() {
return () => this.name
}
}
let obj2 = {
name: 'ma'
}
let temp = obj.getName()
console.log(temp()) //'jack' 注意temp()的結果是'jack',不是'tony'。
//可是若是你只是引用了obj的方法,而沒有調用它,那麼調用箭頭函數後,this
//指向window
let temp2 = obj.getName
console.log(temp2()()) //此時爲'tony'
//以上那句至關於,故結果爲tony。由於在調用temp2()的時候,內部箭頭函數的this
就被永久的綁定成了temp2函數環境內部的this值,也即window。
console.log(temp2.call(window)()) //'tony'
當obj.getName()進行調用時,此時getName函數環境內的this值爲obj。因爲內部返回了一個箭頭函
數,而箭頭函數自己並無this,它取得其實是離它最近的那個環境中this的值,this值被永久的置
爲了obj.getName函數的this,即爲obj。當將obj.getName()的返回值賦值給了temp,因此即便被調用
的方式一般將其設置爲undefined或全局對象,它的this也仍然是 obj。
綜上:
箭頭函數自己沒有this,它的this值其實是離它最近的那個環境中this的值,因爲沒有this值
故沒法做爲構造函數而使用。
複製代碼