call的实现:
思路很简单:
- 1、将函数设置为对象的属性:obj.fn = func
- 2、执行函数:obj.fn()
- 3、删除函数:
delete obj.fn
注意的地方:
- 4、this 参数可以传
null
或者undefined
,此时 this 指向 window - 5、this 参数可以传基本类型数据,原生的 call 会自动用 Object() 转换
- 6、函数是可以有返回值的
思路的来源:
var obj = {
value: 2,
fn: function() {
console.log(this.value);
}
};
obj.fn(); // 2
(1)es3的实现:
Function.prototype.call2 = function(context) {
context = context ? Object(context) : window;
context.fn = this;//用this获取调用call2的函数,即func
var args = [];
var len = arguments.length;
var result;
for(var i = 1; i < len; i++) {
args.push('arguments[' + i + ']'); // arguments[1] = 'kevin' arguments[2] = 18
}
// console.log(args);['arguments[1]','arguments[2]']
result = eval('context.fn(' + args +')');//context.fn(args)
console.log(result);
delete context.fn;
return result;
}
// 测试一下
var value = 2;
var obj = {
value: 1
};
function func(name, age) {
console.log(name);
console.log(age);
console.log(this.value);
}
func.call2(null); //2
func.call2(obj, 'kevin', 18);
example:
Function.prototype.call2 = function (context) {
context = context ? Object(context) : window;
context.fn = this;//将函数设置为对象的属性,也可以写成context.fn = func;用this获取调用call2的函数
var result = context.fn();//执行函数
delete context.fn;//删除函数
return result;//将函数执行结果返回
}
// 测试一下
function func() {
console.log(this);
}
func.call2(123); // Number {123, fn: ƒ}
(2):es6的实现:
Function.prototype.call2 = function(context) {
context = context ? Object(context) : window;
context.fn = this;//context.fn = func;获取调用call2的函数
let args = [...arguments].slice(1);
let result = context.fn(...args);
delete context.fn;
return result;
}
// 测试一下
let value = 1;
let obj = {
value: 2
};
function func(name, age) {
console.log(name);
console.log(age);
console.log(this.value);
}
func.call2(null); //1
func.call2(obj, 'kevin', 18);// 'kevin' 18 2
call和apply的区别:
call()是挨个传递过去,而apply()是以数组的形式传递 / arguments类数组对象
apply的实现:
(1) es3的实现:
Function.prototype.apply = function (context, arr) {
context = context ? Object(context) : window;
context.fn = this;
var result;
// 判断是否存在第二个参数
if (!arr) {
result = context.fn();
} else {
var args = [];
var len = arr.length;
for (var i = 0; i < len; i++) {
args.push('arr[' + i + ']');
}
result = eval('context.fn(' + args + ')');
}
delete context.fn;
return result;
}
(2)es6的实现:
Function.prototype.apply1 = function (context, arr) {
context = context ? Object(context) : window;
context.fn = func;
let result;
if (!arr) {//判断是否存在第二个参数
result = context.fn();
} else {
result = context.fn(...arr);
}
delete context.fn;
return result;
}
// 测试一下
let value = 1;
let obj = {
value: 2
};
function func(name, age) {
console.log(name);
console.log(age);
console.log(this.value);
}
func.apply1(null); //1
func.apply1(obj, ['kevin',18]);// 'kevin' 18 2
bind的es3实现:
首先我们来实现以下四点特性:
- 1、可以指定
this
- 2、返回一个函数
- 3、可以传入参数
- 4、柯里化
什么是柯里化?
调用函数的时候只传递一部分参数,让它返回的函数再去处理其他的参数
var add = function(x) {
return function(y) {
return x + y;
};
};
var increment = add(1);
var addTen = add(10);
increment(2);
// 3
addTen(2);
// 12
add(1)(2);
// 3
这里定义了一个 add
函数,它接受一个参数并返回一个新的函数。调用 add
之后,返回的函数就通过闭包的方式记住了 add
的第一个参数。所以说 bind
本身也是闭包的一种使用场景。
es3实现如下:
Function.prototype.bind2 = function (context) {
//判断调用bind的是不是函数
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;//this指向调用者
// 使用 arguments 获取参数数组,因为第1个参数是指定的this,所以只截取第1个之后的参数
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};//创建一个空对象
// 直接修改 fBound.prototype 的时候,也会直接修改 this.prototype,所以要创建一个空对象,接着下面的(2)
var fBound = function () {
// 这时的arguments是指bind返回的函数传入的参数
var bindArgs = Array.prototype.slice.call(arguments);
//将参数合并成一个参数数组,作为apply()的第二个参数
// 当作为构造函数时,this 指向实例,此时 this instanceof fBound 结果为 true,this指向调用者
// 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 context
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
fNOP.prototype = this.prototype;//空对象的原型指向绑定函数的原型(2)
fBound.prototype = new fNOP();//fBound.prototype作为空对象的实例
return fBound;
}
var value = 1;
var obj = {
value: 2
};
function func(name, age) {
console.log(this.value);
console.log(name);
console.log(age);
};
var bindFunc = func.bind2(obj, "Jack");
bindFunc(20);
原文在此:
https://muyiy.vip/blog/3/3.4.html#使用场景