#题目描述#
增强所有函数,使其具有 callPolyfill 方法。该方法接受一个对象 obj 作为第一个参数,以及任意数量的附加参数。obj 成为函数的 this 上下文。附加参数将传递给该函数(即 callPolyfill 方法所属的函数)。
例如,如果有以下函数:
function tax(price, taxRate) {
const totalCost = price * (1 + taxRate);
console.log(`The cost of ${this.item} is ${totalCost}`);
}
调用 tax(10, 0.1) 将输出 "The cost of undefined is 11" 。这是因为 this 上下文未定义。
然而,调用 tax.callPolyfill({item: "salad"}, 10, 0.1) 将输出 "The cost of salad is 11" 。this 上下文被正确设置,函数输出了适当的结果。
请在不使用内置的 Function.call 方法的情况下解决这个问题。
#示例#
1、示例1
输入:
fn = function add(b) {
return this.a + b;
}
args = [{"a": 5}, 7]
输出:12
解释:
fn.callPolyfill({"a": 5}, 7); // 12
callPolyfill 将 "this" 上下文设置为 {"a": 5} ,并将 7 作为参数传递。
2、示例2
输入:
fn = function tax(price, taxRate) {
return `The cost of the ${this.item} is ${price * taxRate}`;
}
args = [{"item": "burger"}, 10, 1,1]
输出:"The cost of the burger is 11"
解释:callPolyfill 将 "this" 上下文设置为 {"item": "burger"} ,并将 10 和 1.1 作为附加参数传递。
#提示#
typeof args[0] == 'object' and args[0] != null
1 <= args.length <= 100
2 <= JSON.stringify(args[0]).length <= 105
#题目解析#
1、准入准出:增强所有函数,使其具有 callPolyfill 方法,其中prototype可以用于动态增强对象,那么有些js的原生类,没有提供我们想要的功能的时候,我们就可以用prototype对其增强
/**
* @param {Object} context
* @param {Array} args
* @return {null|boolean|number|string|Array|Object}
*/
Function.prototype.callPolyfill = function(context, ...args) {
// ....逻辑代码
}
2、 参数定义:其中obj作为第一个参数,是函数的上下文context,其余的参数个数不定通过...args来表示。
3、结果解析:当第一个参数为null时,说明callPolyfill函数里this上下文未定义,我们需要让window来作为函数的默认上下文,如果传入了一个对象obj,则可以直接作为函数上下文。
将函数添加到传入的对象中成为对象的一个方法,通过对象调用该方法便可以隐式绑定this为该对象,获取返回值后将对象新增的方法删除,使对象恢复如初。
为了防止新增方法覆盖对象原来的属性/方法,可以使用symbol产生唯一的key。
#答案解析#
/**
* @param {Object} context
* @param {Array} args
* @return {null|boolean|number|string|Array|Object}
*/
Function.prototype.callPolyfill = function(context, ...args) {
let cxt = context || window;
// 如果context对象里已经有fn属性,则容易被覆盖,故最好使用唯一的key
cxt.fn = this;
// 这边改使用key的时候,最好每次拿到函数执行返回值后,对新增的属性进行删除
return cxt.fn(...args);
}
/**
* @param {Object} context
* @param {Array} args
* @return {null|boolean|number|string|Array|Object}
*/
Function.prototype.callPolyfill = function(context, ...args) {
const sym = Symbol();
context[sym] = this; // 这里的this为调用call的函数本身
const res = context[sym](...args);
delete context[sym];
return res;
}