能否定义单个通用函数修改任意变量及对象属性?
嘿,这个问题问到点子上了——在JavaScript里直接通过函数修改任意变量(尤其是基本类型)确实不像你想的那么直接,咱们先看看你给出的例子为什么没生效,再讲可行的解决方案。
为什么你的代码没起作用?
先看第一个基本类型的例子:
var x, y; function foo(parameter1, parameter2) { parameter1 = parameter2; } foo(x, 'Hello World'); foo(y, 'Bye Bye World');
这里的核心问题是:JavaScript的基本类型(字符串、数字、布尔、undefined、null、Symbol)是按值传递的。当你把x传给parameter1时,函数拿到的是x当前值(也就是undefined)的副本,修改这个副本完全不会影响外面的原变量x——就像你复制了一张纸,在复印件上写字,原纸不会有任何变化。
再看对象属性的例子:
function Object() { this.x; this.y; } function foo(param1, param2) { param1 = param2; } var object = new Object(); foo(object.x, 'Hello World'); foo(object.y, 'Bye Bye World');
本质上和上面是同一个问题:object.x是读取对象属性的值(这里也是undefined),传递给param1的还是这个值的副本,修改副本和原对象的x属性没有任何关联。而且要注意:别用Object当自定义构造函数名,会覆盖JavaScript内置的Object对象,容易出问题。
可行的解决方案
1. 修改基本类型变量:用对象包裹
既然基本类型没法直接传递引用,咱们可以把变量放到对象里——对象是按引用传递的,函数里修改对象的属性会直接影响原对象:
// 把需要修改的变量放到一个对象里 const store = { x: undefined, y: undefined }; // 定义修改函数:接收对象、属性名、新值 function updateVariable(obj, propName, newValue) { obj[propName] = newValue; } // 使用函数修改指定变量 updateVariable(store, 'x', 'Hello World'); updateVariable(store, 'y', 'Bye Bye World'); console.log(store.x); // 输出 "Hello World" console.log(store.y); // 输出 "Bye Bye World"
2. 修改基本类型变量:用返回值重新赋值
如果不想用对象包裹,也可以让函数返回新值,然后在外面手动把变量重新赋值——这是更常见的做法:
function getUpdatedValue(newValue) { // 这里可以加一些逻辑,比如验证newValue的合法性 return newValue; } let x, y; x = getUpdatedValue('Hello World'); y = getUpdatedValue('Bye Bye World'); console.log(x); // "Hello World" console.log(y); // "Bye Bye World"
3. 修改对象属性:传递对象+属性名
要修改对象的指定属性,你需要把对象本身和属性名传给函数,这样函数就能直接操作原对象的属性了:
// 自定义构造函数,别用Object当名字 function MyObject() { this.x = undefined; this.y = undefined; } // 修改对象属性的函数 function updateObjectProp(obj, propName, newValue) { obj[propName] = newValue; } const myObj = new MyObject(); updateObjectProp(myObj, 'x', 'Hello World'); updateObjectProp(myObj, 'y', 'Bye Bye World'); console.log(myObj.x); // "Hello World" console.log(myObj.y); // "Bye Bye World"
(不推荐)用eval修改变量
还有一种方法是用eval,把变量名作为字符串传给函数,然后通过eval修改:
function updateVarByName(varName, newValue) { eval(`${varName} = newValue`); } let x, y; updateVarByName('x', 'Hello World'); updateVarByName('y', 'Bye Bye World');
但强烈不推荐这种方式:eval有安全风险(如果变量名来自用户输入,可能注入恶意代码),而且性能差、代码可读性低,日常开发尽量别用。
总结一下
- 基本类型变量无法直接通过函数修改原变量,必须借助对象包裹或者返回值重新赋值;
- 修改对象属性时,要传递对象本身和属性名,而不是属性的值;
- 尽量避免用
eval这种不安全的写法。
内容的提问来源于stack exchange,提问作者Jakub Chaloupka

