bind
bind,在Function.prototype上,返回一个新函数,并且使函数内部的this为传入的第一个参数
用法
var name = 'globle'
var App = {
name: 'app',
sayName: function(){
console.log(this.name)
}
}
var obj = {
name: 'SeaMountC'
}
App.sayName() //"app"
App.sayName.bind(window)() //"globle"
App.sayName.bind(obj)() //"SeaMountC"
使用场景
var Page = {
init: function(){
this.node = document.body
this.bind()
},
bind: function(){
this.node.addEventListener('click', function(){
this.sayHello()//①
})
},
sayHello: function(){
console.log('hello...' + this.node.innerText)
}
}
Page.init() //报错
上述代码会报错,因为①处的this指的是this.node,而不是我们期待的Page,而document.body中并没有sayHello方法,所以报错。
修改方法:
第一种:将this存下来
var Page = {
init: function(){
this.node = document.body
this.bind()
},
bind: function(){
var _this = this
this.node.addEventListener('click', function(){
_this.sayHello()
})
},
sayHello: function(){
console.log('hello...' + this.node.innerText)
}
}
Page.init() //"hello...海山城"
参考前一遍写的this的判断方法,_this.sayHello() 相当于Page.sayHello.call(Page),因此sayHello中的this是指Page,没有问题
第二种:使用bind改变this
var Page = {
init: function(){
this.node = document.body
this.bind()
},
bind: function(){
this.node.addEventListener('click', function(){
this.sayHello()
}.bind(this))
},
sayHello: function(){
console.log('hello...' + this.node.innerText)
}
}
Page.init()
第三种:换种写法,同样使用bind改变this
var Page = {
init: function(){
this.node = document.body
this.bind()
},
bind: function(){
this.node.addEventListener('click', this.sayHello.bind(this))
},
sayHello: function(){
console.log('hello...' + this.node.innerText)
}
}
Page.init() //"hello...海山城"
注:
- 注意这种写法,是直接将sayHello作为click事件的回调函数
- 这种方法如果不bind(this),会报错,因为sayHello中的this指的是document.body,最后就变成document.body.node.innerText
apply、call
bind与apply、call相同点:
- 都是用来改变函数的this对象的指向的;
- 第一个参数都是this要指向的对象;
- 都可以利用后续参数传参;
bind与apply、call区别:
- bind不会立即调用,其他两个会立即调用
- 因为bind不会立即调用,因此可以有两种传参形式,
一种是向call一样fn.bind(context, param1, param2...)(),
另一种是fn.bind(context)(param1, param2...)
apply与call区别:
- call方法接收参数列表fn.call(context, param1, param2...),而apply接收参数数组fn.apply(context, paramArray)
使用事例1
求和函数,直接arguments.forEach会报错,借用数组的forEach方法,通过call将forEach内部的this从数组改成arguments
function sum(){
// ------------------报错-----------------
// arguments.forEach(function(value){
// console.log(value)
// })
// --------------------------------------
var result = 0
Array.prototype.forEach.call(arguments, function(value){
console.log(value)
result += value
})
console.log(result)
}
sum(9,5,4,3)
- forEach正常调用形式为[1,2,3].forEach(function(val){}),相当于[1,2,3].forEach.call([1,2,3], function(val){}),因此forEach中的this指的是数组本身
- Array.prototype.forEach(function(val){}),相当于Array.prototype.forEach.call(Array.prototype, function(val){}),这样forEach方法中的this指的是Array.prototype,将第一个参数改成arguments,即可改变forEach方法中的this,相当于此时forEach方法中的代码都是针对arguments处理的
- 因此[1,2,3].forEach.call([1,2,3], function(val){}),可以写Array.prototype.forEach.call([1,2,3], function(val){})
使用事例2
将arguments变成数组,这样就可以使用数组的方法了
function argsToArray(){
var args = Array.prototype.slice.call(arguments, 0)
console.log(args instanceof Array) //true
}
argsToArray(1,3,4,5,6)
使用事例3
借用Math.max(),Math.min()方法,求数组最大,最小值
var arr = [5, 0, 2, 9]
//------正常是这么调用的-------------
//Math.max(5, 0, 2, 9)
//-------------------------------------------
//使用apply
Math.max.apply(Math, arr)
Math.max.apply(null, arr)
- 上面apply的context参数(第一个参数)无所谓是什么,max方法本来就是针对传入的参数做处理的,而不是针对传入的this。
- apply传入的第二个参数是数组,如果是call的话,就得这样Math.max.call(null, 5, 0, 2, 9)
网友评论