new
new用来创建一个新的对象
new的过程:
- 以构造函数原型对象为原型创建一个新对象
- 以新对象为 this,执行函数的
- 如果函数的返回值是对象,返回这个对象,否则返回第一步创建的新对象
实现
function myNew(fn, ...args) {
const obj = Object.create(fn.prototype)
const res = fn.call(obj, ...args)
return res instanceof Object ? res : obj
}
call
call用来指定函数调用的this
call的使用
fn.call(thisArg, arg1, arg2, arg3 ...)
call的过程:
- 改变执行函数的this指向为第一个参数
- 执行函数
实现:实际上就是把方法挂在指定对象上,执行然后删除
Function.prototype.myCall = function(context, ...args) {
// fn.call(...) this就是fn
if (typeof this !== 'function') {
throw new TypeError('this is not a function')
}
context = context || window
context.fn = this
const res = context.fn(...args)
delete context.fn
return res
}
apply
apply同call 只是使用时传参不同
apply的使用
fn.apply(thisArg, [arg1, arg2, arg3...])
实现
Function.prototype.myApply = function (context, arg) {
if (typeof this !== 'function') {
throw new TypeError('this is not a function')
}
context = context || window
context.fn = this
let res
if (arg) {
res = context.fn(...args)
} else {
res = context.fn()
}
delete context.fn
return res
}
bind
bind不同于call和apply,bind返回的是一个新的函数
bind的使用
fn.bind(thisArg, arg1, arg2, arg3)
bind的过程:
-
返回一个新的函数
-
第一个参数被指定为新函数的this
实现
Function.prototype.myBind = function(context, ...args) {
const that = this
return function() {
that.apply(context, args.concat(...arguments))
}
}
由于bind返回的是一个函数,函数可以用new运算符
通过new运算符操作bind生成的函数时,bind绑定的this会失效,此时的this会指向new生成的实例
改造下:
Function.prototype.myBind = function(context, ...args) {
const that = this
const Fn = new Function()
function resFn() {
// 判断这里面的this是否是构造函数的实例,如果是说明是用了new运算符
that.apply(this instanceof resFn ? this : context, args.concat(...arguments))
}
Fn.prototype = this.prototype
//避免污染原型,new一个新对象
resFn.prototype = new Fn()
return resFn
}