call()方法接受的是参数列表
apply()方法接受的是一个参数数组。
它们的共同之处:都可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由this指定的新对象。
call()方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。 fun.call(thisArg, arg1, arg2, ...) thisArg 表示在 fun 函数运行时指定的 this 值。 arg1, arg2, ... 表示指定的参数列表。
apply()方法调用一个具有给定this值的函数, 以及作为一个数组(或类似数组对象)提供的参数。 func.apply(thisArg, [argsArray]) thisArg 在 func 函数运行时使用的 this 值 argsArray 一个数组或者类数组对象,其中的数组元素将作为单独的参数传给func 函数
实际上,apply和call的功能是一样的,只是传入的参数列表形式不同。
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
var foo = { value: 1 }; function bar() { console.log(this.value); } bar.call(foo); // 1 上述代码实现了 call改变this指向 和 执行bar函数
调用call函数需要改变this指向,如下代码this指向foo的value属性,但是给foo添加了一个value属性。
var foo = { value: 1, bar: function() { console.log(this.value) } }; foo.bar(); // 1
给对象添加的属性用完及时删除就可以了
所以模拟步骤:(fn为对象的属性名,可以随便起)
所以我们可以实现代码,改变this指向
Function.prototype.newcall = function (context) { // 首先要获取调用call的函数,使用this获取 context.fn = this; context.fn(); delete context.fn; } var foo ={ value:1 }; function bar() { console.log(this.value); } bar.newcall(foo);
var foo = { value: 1 }; function bar(name, age) { console.log(name) console.log(age) console.log(this.value); } bar.call(foo, 'aaaa', 18); // aaaa // 18 // 1 // 我们可以从arguments对象中提取值为: // arguments = { // 0: foo, // 1: 'kevin', // 2: 18, // length: 3 // } // 因为arguments是类数组对象,所以可以用for循环 var args = []; for(var i = 1, len = arguments.length; i < len; i++) { args.push('arguments[' + i + ']'); } // 执行后 args为 //["arguments[1]", "arguments[2]", "arguments[3]"] //不定长的参数问题解决了,我们接着要把这个参数数组 //放到要执行的函数的参数里面去。 eval('context.fn(' + args +')')
以下代码解决参数个数不确定的问题
Function.prototype.newcall = function (context) { context.fn = this; // 将函数设为对象的属性 var args = []; for(var i=1,len=arguments.length;i<len;i++){ args.push('arguments['+i+']'); } eval('context.fn('+args+')') // 执行该函数 delete context.fn; // 删除该函数 } var foo ={ value:1 }; function bar(name,age) { console.log(name) console.log(age) console.log(this.value); } bar.newcall(foo,'aaaa',18); // aaaa // 18 // 1
if (typeof context === 'object' || typeof context === 'function') { context = context || window } else { context = Object.create(null) }
Function.prototype.call1 = function (context) { console.log(context) if (typeof context === 'object' || typeof context === 'function') { context = context || window } else { context = Object.create(null) } context.fn = this; // console.log(this) // [Function: ClassA] var args = []; for(var i = 1, len = arguments.length; i < len; i++) { args.push('arguments[' + i + ']'); // console.log(arguments[i]+'---------------------') // string--------------------- // function(){ // var fnStr = 'this is a string in function'; // console.log(fnStr) // }--------------------- // [object Object]--------------------- // 1,2,3--------------------- } console.log(args) // [ 'arguments[1]', 'arguments[2]', 'arguments[3]', 'arguments[4]' ] var result = eval('context.fn(' + args +')'); console.log(result) delete context.fn return result; } function ClassA(str, fn, obj, arr) { console.log(this.name); console.log(str); fn(); console.log(obj); console.log(arr); } var obj = { name: 'aaaaaaaaaa' }; ClassA.call1(obj, 'string', function(){ var fnStr = 'this is a string in function'; console.log(fnStr) }, { color: 'red' }, [1, 2, 3]); // name // string // this is a string in function // { color: 'red' } // [ 1, 2, 3 ]
Function.prototype.newCall = function(context, ...arr) { if (typeof context === 'object' || typeof context === 'function') { context = context || window } else { context = Object.create(null) } context.fn = this const res =context.fn(...arr) delete context.fn; return res } let person = { name: 'Abiel' } function sayHi(age,sex) { console.log(this.name, age, sex); } sayHi.newCall (person, 25, '男'); // Abiel 25 男
apply的实现跟call类似,只是处理参数的方式不同。
Function.prototype.apply = function (context, arr) { var context = Object(context) || window; // console.log(context) // { name: 'Abiel' } context.fn = this; // console.log(context.fn) // [Function: sayHi] var result; if (!arr) { result = context.fn(); } else { var args = []; for (var i = 0, len = arr.length; i < len; i++) { // console.log(arr[i]) args.push('arr[' + i + ']'); } result = eval('context.fn(' + args + ')') // console.log(args) // [ 'arr[0]', 'arr[1]' ] } delete context.fn return result; } let person = { name: "Abiel" }; function sayHi(age, sex) { console.log(this.name, age, sex); } sayHi.apply (person,[ 25, '男']) //Abiel 25 男 // sayHi.apply(person,[]) // Abiel undefined undefined