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

JavaScript:如何无需eval实现闭包中带默认参数的自动Getter和Setter

嘿,很高兴看到你在之前那个无eval闭包Getter/Setter方案的基础上继续深挖!咱们直接来搞定默认参数的支持,分几种常见场景给你拆解~

为无eval闭包Getter/Setter添加默认参数支持

先快速回顾下之前的核心思路:通过Object.defineProperty在外部访问对象上绑定闭包变量的Getter/Setter,完全避开eval,靠作用域链实现变量访问。接下来我们给这个方案加上默认参数的能力。

场景1:Getter返回默认值(变量未初始化/为undefined时)

如果闭包里的变量可能未初始化,我们希望Getter在读取时返回预设的默认值,而不是undefined。只需要给创建Accessor的函数加一个defaultValue参数即可:

function createAccessor(obj, propName, targetScope, defaultValue) {
  Object.defineProperty(obj, propName, {
    get() {
      // 使用空值合并运算符,仅当变量为undefined/null时返回默认值
      return targetScope[propName] ?? defaultValue;
    },
    set(value) {
      targetScope[propName] = value;
    },
    enumerable: true
  });
}

// 使用示例
function createClosureWithAccessors() {
  let foo; // 未初始化的变量
  let bar = 42;
  const accessors = {};
  
  // 给foo设置默认值'fallback_foo',bar不设置默认
  createAccessor(accessors, 'foo', { foo }, 'fallback_foo');
  createAccessor(accessors, 'bar', { bar });
  
  return accessors;
}

const accessors = createClosureWithAccessors();
console.log(accessors.foo); // 输出 'fallback_foo'
accessors.foo = 'custom_value';
console.log(accessors.foo); // 输出 'custom_value'

场景2:Setter支持默认参数(传undefined时使用默认值)

如果希望调用Setter时,若传入undefined就自动使用预设默认值(类似函数参数的默认值逻辑),可以扩展配置项,支持静态默认值或动态生成的默认值:

function createAccessor(obj, propName, targetScope, { getDefault, setDefault } = {}) {
  Object.defineProperty(obj, propName, {
    get() {
      // Getter默认值支持静态值或函数(动态生成)
      return targetScope[propName] ?? (typeof getDefault === 'function' ? getDefault() : getDefault);
    },
    set(value) {
      // 仅当传入值为undefined时,使用setDefault
      const finalValue = value !== undefined ? value : (typeof setDefault === 'function' ? setDefault() : setDefault);
      targetScope[propName] = finalValue;
    },
    enumerable: true
  });
}

// 使用示例
function createClosureWithAccessors() {
  let foo = 'initial_foo';
  let count = 0;
  const accessors = {};
  
  // 给foo设置静态默认值
  createAccessor(accessors, 'foo', { foo }, {
    setDefault: 'default_foo'
  });
  
  // 给count设置动态默认值(基于当前count值+1)
  createAccessor(accessors, 'count', { count }, {
    setDefault: () => count + 1
  });
  
  return accessors;
}

const accessors = createClosureWithAccessors();
accessors.foo = undefined; // 使用setDefault
console.log(accessors.foo); // 输出 'default_foo'

accessors.count = undefined; // 调用动态默认函数
console.log(accessors.count); // 输出 1

场景3:函数式Getter/Setter支持默认参数

如果你更倾向于用函数调用的方式(比如accessors.foo()读取,accessors.foo(newVal)设置),可以把Accessor改成函数形式,更贴近函数参数默认值的写法:

function createFunctionalAccessor(obj, propName, targetScope, defaultValue) {
  obj[propName] = function(value) {
    if (arguments.length === 0) {
      // 无参数时作为Getter,返回当前值或默认值
      return targetScope[propName] ?? defaultValue;
    } else {
      // 有参数时作为Setter,传undefined则用默认值
      const finalValue = value !== undefined ? value : defaultValue;
      targetScope[propName] = finalValue;
      return this; // 支持链式调用
    }
  };
}

// 使用示例
function createClosureWithAccessors() {
  let foo = 'initial_foo';
  const accessors = {};
  
  createFunctionalAccessor(accessors, 'foo', { foo }, 'default_foo');
  
  return accessors;
}

const accessors = createClosureWithAccessors();
console.log(accessors.foo()); // 输出 'initial_foo'
accessors.foo(undefined); // 设置为默认值
console.log(accessors.foo()); // 输出 'default_foo'
accessors.foo('new_custom_val').foo(); // 链式调用,输出 'new_custom_val'

以上所有方案都完全避开了eval,靠作用域链和JS原生语法实现了默认参数的支持,你可以根据自己的业务场景选择对应的写法~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:06:18