call、apply、bind
只是了解主要的思路,没有对调用者做限制,也没有处理异常。
call
Function.prototype.myCall = function (context, ...args) {
context = context || window
context.fn = this; // myBind调用者
const result = context.fn(...args)
delete context.fn
return result
}
let obj1 = {
name: '我是obj1',
walking: function () {
let str = `我是${this.name}`
console.log(str);
}
}
let obj2 = {
name: '我是obj2'
}
obj1.walking.myCall(obj2) // 我是我是obj2
从obj1.walking.myCall(obj2) 理解:
- myCall的调用者是一个函数,于是内部的this,指向这个函数:obj1内部的walking
- 调用myCall是obj2本身没有这个walking函数,但是obj1有,于是传入这个对象,也就是context。
apply
Function.prototype.myApply = function (context, args = []) {
context = context || window
context.fn = this; // myBind调用者
const result = context.fn(...args)
delete context.fn
return result
}
- call和apply几乎一样,只是接收参数不一样。apply接收的是数组。call接收单个的参数,就像打电话,一位一位的拨
- call、apply 都只是在内部改变了this的指向,并对函数进行了调用。
bind
Function.prototype.myBind = function (context, ...args) {
const _this = this;
return function F (...arguments) {
if (this instanceof F) {
return _this.apply(this, [...args, ...arguments])
}
return _this.apply(context, [...args, ...arguments])
}
}
let obj1 = {
name: '我是obj1',
walking: function () {
let str = `我是${this.name}`
console.log(str);
}
}
let obj2 = {
name: '我是obj2'
}
console.log(obj1.walking.myBind(obj2));// [Function: F]
console.log(obj1.walking.myBind(obj2)());//我是我是obj2
bind在借助apply,返回一个函数
new
function myNew () {
var obj = new Object()// 创建一个对象,
var Con = [].shift.call(arguments)// 获取传入的对象
obj.__proto__ = Con.prototype;// 把创建的对象连接到原型
let result = Con.apply(obj, arguments)// 改变this指向
return typeof result === 'object' ? result : obj// 返回一个对象
}
function Person (name) {
this.name = name
}
var mm = myNew(Person, '你好好')
console.log(mm);//Person { name: '你好好' }