You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用call或apply实现bind方法的Polyfill:如何避免覆盖上下文对象的已有方法

Fixing Context Property Overwrites in Your bind Polyfill (No call/apply)

Great question! You’re absolutely right that attaching a fixed-named property like fnToCall to the context object risks overwriting existing properties on it. Plus, your current code has a couple of other small issues: allArguments is undeclared (so it becomes a global variable) and the argument merging/passing logic is incorrect.

Below are two optimized implementations that avoid call/apply entirely and eliminate the property collision problem:

Solution 1: Use ES6 Symbols (Best Practice)

Symbols are globally unique identifiers, so they’ll never conflict with existing string or Symbol properties on the context object. This is the cleanest, safest approach for modern environments:

Function.prototype.newBindWithoutApply = function (ctx, ...args) {
  // Create a unique Symbol to use as a temporary property key
  const tempFnKey = Symbol('boundFunction');
  // Attach the original function to the context using this unique key
  ctx[tempFnKey] = this;

  return function (...args1) {
    // Merge arguments passed to bind and arguments passed to the bound function
    const combinedArgs = [...args, ...args1];
    // Call the function: since it's attached to ctx, `this` naturally points to ctx
    const result = ctx[tempFnKey](...combinedArgs);
    // Clean up the temporary property to avoid polluting the context object
    delete ctx[tempFnKey];
    return result;
  };
};

Why this works:

  • The unique Symbol ensures no existing properties on ctx are overwritten
  • We delete the temporary property after calling the function, leaving the context object untouched
  • The argument merging logic is fixed to pass both the pre-bound arguments and the call-time arguments

Solution 2: ES5-Compatible Version (No Symbols)

If you need to support older environments that don’t have ES6 Symbols, you can generate a nearly unique string key to avoid collisions:

// Counter to generate unique key names
let bindTempKeyCounter = 0;

Function.prototype.newBindWithoutApply = function (ctx) {
  const originalFn = this;
  // Extract arguments passed to bind (skip the first ctx argument)
  const bindArgs = Array.prototype.slice.call(arguments, 1);

  // Generate a unique key that doesn't exist on ctx
  let tempFnKey;
  do {
    tempFnKey = `__bound_temp_fn_${bindTempKeyCounter++}`;
  } while (tempFnKey in ctx);

  ctx[tempFnKey] = originalFn;

  return function () {
    // Extract arguments passed to the bound function
    const callArgs = Array.prototype.slice.call(arguments);
    const combinedArgs = bindArgs.concat(callArgs);
    
    // For pure ES5 (no spread operator), construct the call manually
    const argPlaceholders = combinedArgs.map((_, i) => `combinedArgs[${i}]`).join(',');
    const result = eval(`ctx[tempFnKey](${argPlaceholders})`);
    
    // Clean up the temporary property
    delete ctx[tempFnKey];
    return result;
  };
};

Notes on the ES5 version:

  • We use a counter to generate unique key names, and loop until we find one that doesn’t exist on ctx
  • Array.prototype.slice.call(arguments) is used to convert the arguments object to an array (this uses call, but only to manipulate the arguments object—not to change the function’s this context, which aligns with your requirement)
  • The eval statement is a workaround to pass multiple arguments without using apply—it’s not ideal, but it’s the only way to do this in pure ES5 without call/apply

Fixes for Your Original Code

To recap, your original code had three key issues:

  1. Property collision: Using a fixed name like fnToCall risks overwriting existing properties on ctx
  2. Global variable leak: allArguments was undeclared, making it a global variable
  3. Incorrect argument passing: You weren’t passing the merged args and args1 to the function call

内容的提问来源于stack exchange,提问作者ajith kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 13:29:09