待会实现的自定义call函数,会用下面简单的函数调用系统的call函数进行对比
function foo() { console.log('foo函数执行', this); } function sum(num1, num2) { console.log('sum函数执行', this, num1, num2); return num1 + num2; }
系统的call 函数是可以直接被函数调用的,因此,我们自定义的 dycall 方法需要挂载到函数对象的原型上
Function.prototype.dycall = function() { console.log('dycall方法执行') }
foo.dycall();
在自定义的 dycall 方法中,我们要获取到调用 dycall 方法的函数对象,然后在 dycall 方法中,进行调用
foo.dycall() 相当于 this 的隐式绑定,直接通过this获取被调用的函数对象
Function.prototype.dycall = function () { // 1.获取需要被执行的函数 var fn = this; fn(); }
传入空对象对比调用
foo.call({}); // foo函数执行 {}
foo.dycall({}); // foo函数执行 Window {...}
对比系统call调用,自定义的 dycall 方法this指向的是 window,因此绑定this,将获取的 fn 函数添加到传入的对象上,相当于this的隐式绑定,this就指向了传入的空对象
// 给所有函数添加一个 dycall 的方法 Function.prototype.dycall = function (thisArgs) { // 1.获取需要被执行的函数 var fn = this; thisArgs.fn = fn; thisArgs.fn(); };
foo.dycall({}); // foo函数执行 {fn: ƒ}
在此调用后,输出的this就是我们传入的空对象,但是对比系统call,我们多了绑定的 fn 函数,因此需要在dycall调用fn后,删除多余的属性。输出的时候会看到,但,无伤大雅
// 给所有函数添加一个 dycall 的方法 Function.prototype.dycall = function (thisArgs) { // 1.获取需要被执行的函数 var fn = this; thisArgs.fn = fn; // 2.调用需要被改变this的函数 thisArgs.fn(); delete thisArgs.fn; };
foo.call(123); // foo函数执行 Number {123} foo.call("abc"); // foo函数执行 String {'abc'}
我们自定义的 dycall 绑定的this是对象,因此可以进行 fn 添加调用,如果传入的是简单数据类型,需要我们转换为对应类型的对象,需要使用到 Objecet(),方法
// 给所有函数添加一个 dycall 的方法 Function.prototype.dycall = function (thisArgs) { // 1.获取需要被执行的函数 var fn = this; // 2.将thisArgs转成对象类型(防止传入的是非对象类型),非对象类型不能添加属性 thisArgs = Object(thisArgs) thisArgs.fn = fn; // 3.调用需要被改变this的函数 thisArgs.fn(); delete thisArgs.fn; };
foo.dycall(123); // foo函数执行 Number {123, fn: ƒ} foo.dycall("abc"); // foo函数执行 String {'abc', fn: ƒ}
3.传入 null 、undefined 或 空参
foo调用系统call,this指向 Window
foo.call(); // foo函数执行 Window {...} foo.call(undefined); // foo函数执行 Window {...} foo.call(null); // foo函数执行 Window {...}
// 给所有函数添加一个 dycall 的方法 Function.prototype.dycall = function (thisArgs) { // 1.获取需要被执行的函数 var fn = this; // 2.将thisArgs转成对象类型(防止传入的是非对象类型),非对象类型不能添加属性 thisArgs = thisArgs ? Object(thisArgs) : window; thisArgs.fn = fn; // 3.调用需要被改变this的函数 thisArgs.fn(); delete thisArgs.fn; };
sum.call({}, 20, 30); // sum函数执行 {} 20 30
tips:用剩余运算符 ...args 接收多个参数,调用的时候使用 扩展运算符 ...args
// 给所有函数添加一个 dycall 的方法 Function.prototype.dycall = function (thisArgs, ...args) { // 1.获取需要被执行的函数 var fn = this; // 2.将thisArgs转成对象类型(防止传入的是非对象类型),非对象类型不能添加属性 thisArgs = thisArgs ? Object(thisArgs) : window; thisArgs.fn = fn; // 3.调用需要被改变this的函数 var result = thisArgs.fn(...args); delete thisArgs.fn; // 4.将调用后的结果返回 return result; };