part0前言
这三种方式 不管是哪一种其实都是通过复制目标属性并将调用目标的方法实现。
比如这个应用场景:
对象调用Array的sort方法==》Array.sort(obj)
part1 call
///call bind apply的应用
///call
let PeoSon = {
name: "里",
say(param) {
console.log(this);
console.log(`我是${this.name}`)
console.log(`我是${param}`)
}
}
PeoSon1 = {
name: "整"
}
// Function.prototype.MyCall = function (context) {
// ///这里的办法是重新覆盖上去
// //context就是demo中的Person1
// // 必须此时调用MyCall的函数是say方法,那么我们只需要在context上扩展一个say方法指向调用MyCall的say方法这样this
// debugger
// console.log(this)
// context.say = this //Mycall里边的this就是我们虚拟的say方法
// console.log(context)
// context.say()
// }
//PeoSon.say.call(PeoSon1)
// PeoSon.say.MyCall(PeoSon1)
/**
* 实现call的方式是覆盖
* 我们在 .MyCall的时候
* 将上下文传入=》即对象传入等待拓展
* 传入后拓展要覆盖的方法=》say
**/
Function.prototype.myCall = function (context) {
context.say = this;
context.say()
}
改进1、call支持多个参数,有可能一个也不没有
Function.prototype.myCall1 = function (context) {
context = context || window
context.say = this;
context.say()
}
// 改进2、 考虑多参数时要把参数传给扩展方法。
// 改进3、 给上下文定义的函数要保持唯一不能是say
// 改进4、 扩展完我们需要吧自定义函数删除
Function.prototype.myCall2 = function (context) {
context = context || window;
//给上下文定义的函数要保持唯一不能是say
let fn = mySymbol(context);
context[fn] = this;
//考虑多参数时要把参数传给扩展方法。
let arg = [...arguments].slice(1);//除了复制目标对象外的所有参数
context[fn](..arg);
delete context[fn];
}
///自定义Symbol方法 得到唯一值
mySymbol = function (obj) {
let unique = (Math.random() + new Date().getTime()).toString(32).slice(0, 8);
if (obj.hasOwnProperty(unique)) {
mySymbol(unique);
} else {
return unique
}
}
let PeoSon3 = {
name: "里",
age: 18,
say() {
console.log(this);
console.log(`我是${this.name} +++ ${this.age}`)
}
}
PeoSon4 = {
name: "整 ",
age: 20,
}
PeoSon3.say.myCall2(PeoSon4)
part2 apply
类似call
part3 bind
bind的方式与apply/call不同==》这个函数要支持柯里化的!
let Peoson = {
name: "人",
say(param) {
console.log(`${this.name}`)
console.log(`${param}`)
},
hello() {
alert("hello")
}
}
let Chinese = {
name: "中国人"
}
// Peoson.say.bind(Chinese);
// bind
Function.prototype.bind = function (context) {
let self = this;
let arg = [...arguments].slice(1)
return function () {
let newArg = [...arguments]
self.apply(context, arg.concat(newArg))
}
}
let fn = Peoson.say.bind(Chinese, "123");
fn();