Function.prototype.call(thisArg,arg1,arg2,...):call()接受多个参数,第一个参数为调用call()的函数this所指向的对象,后面的参数列表为调用call()的函数所需的参数。
Function.prototype.call = function (context, ...args) {
//这里默认不传就是给window
context = context || window
args = args ? args : []
//给context新增一个独一无二的属性以免覆盖原有属性
const key = Symbol()
context[key] = this //这里的this指的是调用myCall()的对象,把这个对象给到context新增的key属性上
//调用函数
const result = context[key](...args)
//删除添加的属性
delete context[key]
//返回函数调用的返回值
return result
}
//Symbol()是es6中才有的语法,而我们可以自己实现这个类似的方法
function Symbol(obj) {
//toString(32)将数字转为32进制
//toString(16):转为16进制
let unique = (Math.random() + new Date().getTime()).toString(32).slice(0, 8)
if (obj.hasOwnProperty(unique)) { //如果obj中包含unique,则继续递归
return mySymbol(obj)
} else {
return unique
}
}
//修改一下
Function.prototype.call = function (context, ...args) {
//这里默认不传就是给window
context = context || window
args = args ? args : []
//给context新增一个独一无二的属性以免覆盖原有属性
const key = Symbol(context)
context[key] = this //这里的this指的是调用myCall()的对象,把这个对象给到context新增的key属性上
//调用函数
const result = context[key](...args)
//删除添加的属性
delete context[key]
//返回函数调用的返回值
return result
}
let Person = {
name: 'Tom',
say:function(age,height) {
console.log(this)
console.log(`我叫${this.name},今年${age}岁了,身高${height}米`)
}
}
let Person1 = {
name:'Jack'
}
Person.say.call(Person1,18,2)//我叫Jack,今年18岁了,身高2米
Function.prototype.apply(thisArg,args):与call()基本一样,只不过传入的参数形式不一样
Function.prototype.apply = function (context, args) {
//这里默认不传就是给window
context = context || window
args = args ? args : []
//给context新增一个独一无二的属性以免覆盖原有属性
const key = Symbol(context)
context[key] = this //这里的this指的是调用myCall()的对象,把这个对象给到context新增的key属性上
//调用函数
const result = context[key](...args)
//删除添加的属性
delete context[key]
//返回函数调用的返回值
return result
}
Function.prototype.bind(thisArg,arg1,arg2,...):调用时返回一个新的函数,新函数中会改变调用bind()的函数的this指向,让这个this指向bind()的第一个参数,bind()中的其余参数作为调用bind()的函数的参数使用。
Function.prototype.bind = function(context,...args){
context = context || window
args = args?args:[]
let self = this
return function(){
let newArgs = args.concat(Array.prototype.slice.call(arguments))//拼接后面新添加的参数
return self.apply(context,newArgs)
}
}
示例1:
function doSum(){ //实现对传入的参数的累加求和
let arg = Array.prototype.slice.call(arguments)
return arg.length?arg.reduce((prev,next)=>prev+next):''
}
let doSumOne = doSum.bind(null,1,2,3,4)
console.log(doSumOne())//10
console.log(doSumOne(22,33))//65
示例2:
const obj = {
a:20,
sum:function(x,y){
return this.a + x + y
}
}
let res = obj.sum()
console.log(res)
//换一种写法:
let res1 = obj.sum
console.log(res1())//undefined,为什么?此时this指向的是window对象,window中没有a属性。
//针对上面的情况,使用bind()就能派上用场
let dd = obj.sum
let ss = dd.bind(obj,10,20)
console.log(ss())//50
参考:https://juejin.im/post/6844903773979033614#heading-4、https://juejin.im/post/6844903891092389901#heading-10