手写js函数原生实现call,apply 和 bind
call、apply和bind用法
概念
1、call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数
2、apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
function getName(name) {
console.log('name', this.name)
}
var obj = {
a: 1,
name: 'aaa'
}
obj调用getName方法,getName中的this指向obj
getName.call(obj) // name aaa
以apply为例
第一个参数为thisArg,调用时采用传入的thisArg代替函数体中this的指向
第二个参数 为一个数组(也可以是类数组arguments),函数会用数组的值取代“参数列表”
apply的调用方式,除了替换函数体中this的指向之外,函数的其他逻辑没有发生任何变化,‘借用’的函数的效果,就跟对象自己拥有这个函数一样
apply:如果第一个传入的参数是null,那么,在函数体中的this会指向全局对象,在浏览器中就是window
call和apply的区别 和bind的区别
1、 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组
call和apply方式的差别主要体现在传入的形式参数不一样
2、bind的返回值是函数,参数是bind中参数的基础上再往后排
function.bind(thisArg[, arg1[, arg2[, …]]])
手写js函数原生实现call,apply 和 bind
测试用例
var obj = {
name: 'obj'
}
function test(...rest) {
console.log(this.name)
console.log(rest)
return rest[0]
}
原生实现call
纯ES5 实现call
// 纯ES5 实现call
Function.prototype.myCall = function(obj) {
obj = (typeof obj === 'object') ? obj : window
var args = []
for(let i = 1, len = arguments.length; i<len; i++) {
args.push('arguments['+i+']')
}
obj._fn = this
var res = eval('obj._fn('+ args +')')
obj._fn = undefined
return res
}
ES6实现call
Function.prototype.myCall = function(obj, ...rest) {
obj = (typeof obj === 'object') ? obj : window
// 防止覆盖掉原有属性
var _fn = Symbol()
obj[_fn] = this
var res = obj[_fn](...rest)
delete obj[_fn]
return res
}
调用测试用例
test.myCall(obj, 1, 2, 3) // 'name'为obj
原生实现apply
纯ES5 实现apply
Function.prototype.myApply = function(obj, arr) {
obj = (typeof obj === 'object') ? obj : window
var args = []
for(let i = 0, len = arr.length; i<len; i++) {
args.push('arr['+i+']')
}
obj._fn = this
var res = eval('obj._fn('+ args +')')
obj._fn = undefined
return res
}
ES6实现apply
Function.prototype.myApply = function(obj, arr) {
obj = (typeof obj === 'object') ? obj : window
var _fn = Symbol()
obj[_fn] = this
var res
if (!arr) {
res = obj[_fn]()
} else {
res = obj[_fn](...arr)
}
delete obj[_fn]
return res
}
原生实现bind
纯ES5 实现bind
Function.prototype.myBind = function(obj) {
obj = (typeof obj === 'object') ? obj : window
var _this = this
var args = []
var argArr = []
for(let i = 1, len = arguments.length; i<len; i++) {
args.push(arguments[i])
argArr.push('args['+(i-1)+']')
}
return function() {
for(let i = 0, len = arguments.length; i<len; i++) {
argArr.push('arguments['+i+']')
}
obj._fn = _this
const val = eval('obj._fn('+ argArr +')')
delete obj._fn
return val
}
}
ES6实现bind
Function.prototype.myBind = function(obj, ...arg1) {
obj = (typeof obj === 'object') ? obj : window
var _this = this
return function(...arg2) {
obj._fn = _this
const val = obj._fn(...arg1, ...arg2)
delete obj._fn
return val
}
}
使用call实现bind
Function.prototype.myBind = function(obj, ...arg1) {
obj = (typeof obj === 'object') ? obj : window
return (...arg2) => {
this.call(obj, ...arg1, ...arg2)
}
}