说多无益, 直接上代码, 肯定还有一些不完善的地方, 我参考了一下
原生js源码之JavaScript的call方法,自己来实现
call()
'use strict'var person = {name: "Tom",sayHi(a, b) {// console.log('a', a)// console.log('b', b)// return this.name + " 在向你问好!" + a + breturn this.name + " 在向你问好!" + a.name + b.name;}
}var pig = {name: 'Jerry'
}/*** 只处理了 参数为 string, number, object 的情况* @returns any*/
Function.prototype.myCall = function() {if (arguments.length === 0) {return this()} else {// 第一个参数作为上下文let context = arguments[0]// 这两行判断写不写都行其实, 严格模式下不管怎样都会报错的if (context === null || context === undefined) return this()if (typeof context !== 'object') context = {}// this 是传入进来的函数, this.name 是函数名, 给传进来的 context 添加方法context[this.name] = thislet func = this.name + '('let arglet myArgs = []for (let i = 1; i < arguments.length; i++) {arg = arguments[i]console.log('arg', arg)if (typeof arg === 'string') {if (i === 1) {func += `'${arg}'`} else {func += `,'${arg}'`}} else if (typeof arg === 'number') {if (i === 1) {func += arg} else {func += "," + arg}} else if (typeof arg === 'object') {myArgs.push(arg)if (i === 1) {func += `myArgs[${i - 1}]`} else {func += `,myArgs[${i - 1}]`}}}func += ')'console.dir(func)// 拿到执行后的结果const result = eval('context.'+ func)// 删除新增的属性delete context[this.name]// 返回执行后的结果return result}
}// console.log(person.sayHi.myCall(pig, 1, 2))
console.log(person.sayHi.myCall(pig, { name: 'c' }, { name: 'd' }))
console.log(pig)
apply()
其实和 call() 没区别, 只是换了一下参数传入的形式
'use strict'var person = {name: "Tom",sayHi(a, b) {// console.log('a', a)// console.log('b', b)return this.name + " 在向你问好!" + a + b// return this.name + " 在向你问好!" + a.name + b.name;}
}var pig = {name: 'Jerry'
}/*** 只处理了 参数为 string, number, object 的情况* @returns any*/
Function.prototype.myApply = function() {if (arguments.length === 0) {return this()} else {// 第一个参数作为上下文let context = arguments[0]// 这两行判断写不写都行其实, 严格模式下不管怎样都会报错的if (context === null || context === undefined) return this()if (typeof context !== 'object') context = {}// this 是传入进来的函数, this.name 是函数名, 给传进来的 context 添加方法context[this.name] = thislet func = this.name + '('let arglet myArgs = []for (let i = 0; i < arguments.length; i++) {arg = arguments[1][i]console.log('arg', arg)if (typeof arg === 'string') {if (i === 0) {func += `'${arg}'`} else {func += `,'${arg}'`}} else if (typeof arg === 'number') {if (i === 0) {func += arg} else {func += "," + arg}} else if (typeof arg === 'object') {myArgs.push(arg)if (i === 0) {func += `myArgs[${i}]`} else {func += `,myArgs[${i}]`}}}func += ')'console.dir(func)// 拿到执行后的结果const result = eval('context.'+ func)// 删除新增的属性delete context[this.name]// 返回执行后的结果return result}
}console.log(person.sayHi.myApply(pig, [1, 2]))
// console.log(person.sayHi.myApply(pig, [{ name: 'c' }, { name: 'd' }]))
console.log(pig)
bind()
只是需要返回一个函数了
'use strict'var person = {name: "Tom",sayHi(a, b) {// console.log('a', a)// console.log('b', b)// return this.name + " 在向你问好!" + a + breturn this.name + " 在向你问好!" + a.name + b.name;}
}var pig = {name: 'Jerry'
}/*** 只处理了 参数为 string, number, object 的情况* @returns any*/
Function.prototype.myBind = function() {if (arguments.length === 0) {return this} else {let context = arguments[0]// 这两行判断写不写都行其实, 严格模式下不管怎样都会报错的if (context === null || context === undefined) return this()if (typeof context !== 'object') context = {}context[this.name] = thisconst that = thisreturn function() {let arglet func = that.name + '('let myArgs = []for (let i = 0; i < arguments.length; i++) {arg = arguments[i]if (typeof arg === 'string') {if (i === 0) {func += `'${arg}'`} else {func += `,'${arg}'`}} else if (typeof arg === 'number') {if (i === 0) {func += arg} else {func += "," + arg}} else if (typeof arg === 'object') {myArgs.push(arg)if (i === 0) {func += `myArgs[${i}]`} else {func += `,myArgs[${i}]`}}}func += ')'console.dir(func)const result = eval('context.' + func)delete context[that.name]return result}}
}console.log(person.sayHi.myBind(pig)({ name: 'c' }, { name: 'd' }))
// console.log(person.sayHi())