// apply第一个参数是函数的执行环境this,第二个参数是一个数组,这个数组会自动散开成为函数的参数
Function.prototype.apply = function (x, y) {
x = x || window
y = y || []
x._apply = this // this为当前函数:使函数指向x
if (!x._apply) { // 如果作用域x不可修改:则给它的原型添加函数
x.constructor.prototype._apply = this
}
var r , j = y.length
switch (j) {
case 0: r = x._apply(); break
case 1: r = x._apply(y[0]); break
case 2: r = x._apply(y[0], y[1]); break
case 3: r = x._apply(y[0], y[1], y[2]); break
case 4: r = x._apply(y[0], y[1], y[2], y[3]); break
default: r = eval('x._apply(' + y.join() + ')'); break // eval执行效率底,所以先用js写常用的调用
}
try {
delete x._apply ? x._apply : x.constructor.prototype._apply // 删除为了修改函数作用域的临时指向
} catch (e) {}
return r //返回函数执行的结果
}
// call 第一个参数是函数的执行环境this,从第二个参数开始都是给函数的参数
Function.prototype.call = function () {
let len = arguments.length - 1, x = args[0], y = []
for (let i = 0; i < len; i++) { // 把arguments类数组对象转化为数组 可以简写为:[].slice.apply(arguments, 1)
y[i] = arguments[i + 1]
}
return this.apply(x, y)
}
// bind 修改函数的执行环境,返回一个新函数,参数和call一样
Function.prototype.bind = function () {
// 形成一个闭包,返回一个行函数
let x = arguments[0], len = 0, y = [], i, j, fn = this
for (i = 0, len = arguments.length - 1; i < len; i++) {
y[i] = arguments[i + 1]
}
return function () {
for (j = 0, len = arguments.length; j < len;) {
y[y.length] = arguments[j++]
}
return fn.apply(x, y)
}
}