码万行代码不如懂其原理,问题千变万化,答案也随着问题变化而变化,但是你掌握套路(原理),所有的变化都是鸿毛;
call和apply
-
相同点
- 改变this指向
- 首个传参都是要指向的对象
- Function.call(target,one,two...)
- Function.apply(target,Array)
- 立即执行
-
不同点
- 传参方式
- call一个个的传入
- apply传入一个数组
- 传参方式
-
例子
var user = { name:'louiebb' }
var sayHello = function(...args){
console.log(this.name+' say hello world!',args)
}
sayHello.call(user,1,2,3)
sayHello.apply(user,[1,2,3])
- 例子剖析
- 上述call和apply可以翻译装饰器模式:成给user新增函数,执行函数,删除函数
- user.fn = sayHello
- user.fn()
- delete user.fn 备注:装饰器模式自行百度
- 上述call和apply可以翻译装饰器模式:成给user新增函数,执行函数,删除函数
- 源码
Function.prototype.MyCall = function(context, ...args) {
context = context || window // 默认指向window
context.fn = this // this代表函数
context.fn(...args) // 执行改该函数并通过es6扩展字符拆分数组
delete context.fn
}
Function.prototype.MyApply = function(context, ...args) {
context = context || window
context.fn = this
context.fn(args) // apply传递数组
delete context.fn
}
bind
- 特点:
- 传参与call的一致
- 返回一个改变this的捆绑this函数
- 即使用bind返回的函数再用三大函数改this是无法更改,因为改函数捆绑了this
- 例子
var user = { name:'louiebb' }
var sayHello = function(...args){
console.log(this.name+' say hello world!',args)
}
let temp = sayHello.bind(user,1,2,3)
temp(4,5,6)
- 例子剖析
- bind通过闭包的特点,内部函数(即返回的函数)访问外部函数的变量,使得1,2,3和4,5,6合并
- 源码
Function.prototype.myBind = function (context, ...args) {
var fn = this;//即当前函数sayHello属于函数,会通过原型寻找到myBind
var temArgs = args
return function(...crArgs) {
// 内部访问外部变量temArgs
return fn.apply(context,temArgs.concat(crArgs))
}
}