由於有了this,並且this的指向是玄學,指向不固定,誰調用他就指向誰,這個時候咱們就須要有人能夠站出來爲this指引咱們須要的方向,他們就是call,bind,apply
前端
可是學習call,bind,apply的時候,咱們須要瞭解this到底指向誰
傳送門:重學前端之 讓人心態爆炸的this究竟是個什麼玩意node
<input type="text">
<script>
var spa = {
init:function(node){
this.int = node.querySelector('input')
this.str = '你對節點進行操做了'
this.bind()
},
bind:function(){
var _this = this
this.int.onkeyup = function(){
console.log(_this.str)
}
}
}
let node = document.querySelector('body')
spa.init(node)
</script>
複製代碼
上述代碼中,應爲DOM節點的操做,因此執行的函數內部this指向變成了這個被操做的dom節點,這個時候咱們想添加前綴打印str這個值是單純的使用this是獲取不到的,咱們在這個節點操做外部使用了一個小手法暫存了this的做用域,複製給_this,這個時候在函數內部就能夠獲取到與外面相同的做用域來獲取str這個屬性值了,那麼既然改變this的指向,咱們爲何還須要學習call,bind,apply呢,其實我以爲吧,這種寫法沒有逼格,既然js提供了相對應的API,咱們就應該去學習使用,這樣能夠減小代碼量使代碼美觀,也能夠加強js內功,在第四節會奉上使用call,apply以及bind修改this指向代碼,首先咱們來了解一下他們吧數組
他們三個做用都是同樣的,都是用於改變this的指向,具體使用方法使用代碼來實現上述的相同的效果(此博文中不考慮嚴格模式)bash
學習call,bind,apply的使用時候,若是咱們想要更好的理解,咱們必須打破原先的認知,在之前咱們使用函數時,寫法是app
function add(x,y){
return console.log(x+y)
}
add(1,2) //3
複製代碼
這種寫法咱們能夠理解成是JS給咱們提供的語法糖,能夠減小代碼量使代碼簡潔,其實真正使用應該是dom
add.call(underfind,1,2) //3
複製代碼
在MDN中對call的定義是函數
call() 方法使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數。post
語法學習
fun.call(thisArg, arg1, arg2, ...)ui
咱們須要使用函數的時候,使用call這個方法能夠傳入兩個或兩個以上參數,第一個參數咱們執行上下文,也就是咱們的this,若是傳入的是underfind,那麼他就會指向全局對象,後續參數即函數須要的參數,那若是咱們使用曾經默認的函數調用方法,他默認爲func.call(underfind,...),這樣就會函數的this指向全局,因此說爲何通常狀況下函數是全局對象window的方法
看到了基本使用方法,咱們試一試如何去使用他,有什麼好玩的地方
var a = 'hello'
function printStr(){
var a = 'world'
return a
}
printStr() //'world'
複製代碼
這個時候咱們想讓他打印'world',而是想讓他打印'hello'呢
var a = 'hello'
function printStr(){
var a = 'world'
return console.log(this.a)
}
printStr.call(undefined) //hello
複製代碼
咱們經過this來專門指向特定的變量a,而後經過call改變this的指向以此來達到打印輸出的是全局變量a,再來一個例子來看一下
var a = 1,
b = 2,
c = 3,
obj = {
a:'hello ',
b:'world ',
c:'!'
}
function add(){
return console.log(this.a+this.b+this.c)
}
add() //6 等同於add.call(underfind)
add.call(obj) //'hello world !' 修改了this指向,讓this指向了obj
複製代碼
apply的使用方法和call基本相同,只不過在穿入執行上下文的時候,後面的參數是個數組而已
MDN定義
apply() 方法調用一個具備給定this值的函數,以及做爲一個數組(或相似數組對象)提供的參數。
語法
func.apply(thisArg, [argsArray])
bind也是穿入參數改變執行上下文,可是他會返回一個已經被改變this的函數
<input type="text">
<script>
var value = 'str'
var node = document.querySelector('input')
node.onkeyup = strValue.bind(this) //str
function strValue(){
console.log(this.value)
}
</script>
複製代碼
keyup事件觸發的時候,咱們會發現咱們打印的是str,由於咱們在bind函數內穿入了執行上下文this,這個時候this的指向就是全局,因此打印的value就是str
若是咱們想讓他打印input框內容,只須要把代碼修改成
node.onkeyup = strValue.bind(node)
複製代碼
var spa = {
init:function(node){
this.int = node.querySelector('input')
this.str = '你對節點進行操做了'
this.bind()
},
bind:function(){
this.int.onkeyup = ()=>{
this.printStr.call(spa)
}
},
printStr:function(){
console.log(this.str)
}
}
let node = document.querySelector('body')
spa.init(node)
}
複製代碼
var spa = {
init:function(node){
this.int = node.querySelector('input')
this.str = '你對節點進行操做了'
this.bind()
},
bind:function(){
this.int.onkeyup = ()=>{
this.printStr.apply(spa)
}
},
printStr:function(){
console.log(this.str)
}
}
let node = document.querySelector('body')
spa.init(node)
複製代碼
apply的用法是幾乎是同樣的,可是具體差異在哪,一會咱們再說
var spa = {
init:function(node){
this.int = node.querySelector('input')
this.str = '你對節點進行操做了'
this.bind()
},
bind:function(){
this.int.onkeyup = this.printStr.bind(this)
},
printStr:function(){
console.log(this.str)
}
}
let node = document.querySelector('body')
spa.init(node)
}
複製代碼