如何在JavaScript中通过引用传递变量?我想对3个变量执行几个操作,因此我想将它们放在for循环中并对每个变量执行操作。
伪代码:
myArray = new Array(var1, var2, var3);
for (var x = 0; x < myArray.length; x++){
//do stuff to the array
makePretty(myArray[x]);
}
//now do stuff to the updated vars
做这个的最好方式是什么?
JavaScript中没有可用的“通过引用传递”。您可以传递一个对象(也就是说,您可以按值传递对一个对象的引用),然后让一个函数修改该对象的内容:
function alterObject(obj) {
obj.foo = "goodbye";
}
var myObj = { foo: "hello world" };
alterObject(myObj);
alert(myObj.foo); // "goodbye" instead of "hello world"
您可以使用数字索引遍历数组的属性,并根据需要修改数组的每个单元格。
var arr = [1, 2, 3];
for (var i = 0; i < arr.length; i++) {
arr[i] = arr[i] + 1;
}
重要的是要注意“通过引用传递”是一个非常具体的术语。这并不意味着可以将引用传递给可修改的对象。相反,这意味着可以以允许函数在调用上下文中修改该值的方式传递简单变量。所以:
function swap(a, b) {
var tmp = a;
a = b;
b = tmp; //assign tmp to b
}
var x = 1, y = 2;
swap(x, y);
alert("x is " + x + ", y is " + y); // "x is 1, y is 2"
在像C ++这样的语言中,这样做是有可能的,因为该语言确实具有(通过)引用传递。
编辑-最近(2015年3月)在Reddit上再次通过类似于下面提到的我的博客文章引起轰动,尽管在本例中是关于Java的。在阅读Reddit评论中的来回内容时,我突然想到,很大一部分困惑源于涉及“参考”一词的不幸碰撞。术语“按引用传递”和“按值传递”早于使“对象”与编程语言一起工作的概念。它实际上根本不是关于对象;它与函数参数有关,尤其是关于函数参数如何“连接”(或不连接)到调用环境。特别是,,看起来几乎与JavaScript完全一样。但是,还可以在调用环境中修改对象引用,这是您无法在JavaScript中完成的关键操作。引用传递语言不会传递引用本身,而是传递对reference的引用。
编辑-这是有关该主题的博客文章。(请注意该帖子的注释,该注释解释了C ++确实没有传递引用。的确如此。但是,C ++的功能是能够创建对纯变量的引用,无论是在函数的显式位置调用以创建指针,或者在调用参数类型签名要求完成的函数时隐式调用。这是JavaScript不支持的关键。)
- 诸如字符串和数字之类的基本类型变量始终按值传递。
-
根据以下条件,通过引用或值传递数组和对象:
-
如果要设置对象或数组的值,则为按值传递。
object1 = {prop: "car"};
array1 = [1,2,3]; -
如果要更改对象或数组的属性值,则为“按引用传递”。
object1.prop = "car";
array1[0] = 9;
-
码
function passVar(obj1, obj2, num) {
obj1.prop = "laptop"; // will CHANGE original
obj2 = { prop: "computer" }; //will NOT affect original
num = num + 1; // will NOT affect original
}
var object1 = {
prop: "car"
};
var object2 = {
prop: "bike"
};
var number1 = 10;
passVar(object1, object2, number1);
console.log(object1); //output: Object {item:"laptop"}
console.log(object2); //output: Object {item:"bike"}
console.log(number1); //ouput: 10
通过引用传递变量的解决方法:
var a = 1;
inc = function(variableName) {
window[variableName] += 1;
};
inc('a');
alert(a); // 2
编辑
是的,实际上您可以在不访问全局的情况下进行操作
inc = (function () {
var variableName = 0;
var init = function () {
variableName += 1;
alert(variableName);
}
return init;
})();
inc();
简单对象
var ref = { value: 1 };
function Foo(x) {
x.value++;
}
Foo(ref);
Foo(ref);
alert(ref.value); // Alert: 3
自订物件
目的 rvar
function rvar (name, value, context) {
if (this instanceof rvar) {
this.value = value;
Object.defineProperty(this, 'name', { value: name });
Object.defineProperty(this, 'hasValue', { get: function () { return this.value !== undefined; } });
if ((value !== undefined) && (value !== null))
this.constructor = value.constructor;
this.toString = function () { return this.value + ''; };
} else {
if (!rvar.refs)
rvar.refs = {};
if (!context)
context = window;
// Private
rvar.refs[name] = new rvar(name, value);
// Public
Object.defineProperty(context, name, {
get: function () { return rvar.refs[name]; },
set: function (v) { rvar.refs[name].value = v; },
configurable: true
});
return context[name];
}
}
变量声明
rvar('test_ref');
test_ref = 5; // test_ref.value = 5
要么:
rvar('test_ref', 5); // test_ref.value = 5
测试代码
rvar('test_ref_number');
test_ref_number = 5;
function Fn1 (v) { v.value = 100; }
console.log("rvar('test_ref_number');");
console.log("test_ref_number = 5;");
console.log("function Fn1 (v) { v.value = 100; }");
console.log('test_ref_number.value === 5', test_ref_number.value === 5);
console.log(" ");
Fn1(test_ref_number);
console.log("Fn1(test_ref_number);");
console.log('test_ref_number.value === 100', test_ref_number.value === 100);
console.log(" ");
test_ref_number++;
console.log("test_ref_number++;");
console.log('test_ref_number.value === 101', test_ref_number.value === 101);
console.log(" ");
test_ref_number = test_ref_number - 10;
console.log("test_ref_number = test_ref_number - 10;");
console.log('test_ref_number.value === 91', test_ref_number.value === 91);
console.log(" ");
console.log("---------");
console.log(" ");
rvar('test_ref_str', 'a');
console.log("rvar('test_ref_str', 'a');");
console.log('test_ref_str.value === "a"', test_ref_str.value === 'a');
console.log(" ");
test_ref_str += 'bc';
console.log("test_ref_str += 'bc';");
console.log('test_ref_str.value === "abc"', test_ref_str.value === 'abc');
测试控制台结果
rvar('test_ref_number');
test_ref_number = 5;
function Fn1 (v) { v.value = 100; }
test_ref_number.value === 5 true
Fn1(test_ref_number);
test_ref_number.value === 100 true
test_ref_number++;
test_ref_number.value === 101 true
test_ref_number = test_ref_number - 10;
test_ref_number.value === 91 true
---------
rvar('test_ref_str', 'a');
test_ref_str.value === "a" true
test_ref_str += 'bc';
test_ref_str.value === "abc" true
通过引用传递任何(局部,原始)变量的另一种方法是通过将变量带闭包“即时”包装eval
。这也适用于“严格使用”。(注意:请注意,这eval
对JS优化器并不友好,变量名周围的引号也可能导致不可预测的结果)
"use strict"
//return text that will reference variable by name (by capturing that variable to closure)
function byRef(varName){
return "({get value(){return "+varName+";}, set value(v){"+varName+"=v;}})";
}
//demo
//assign argument by reference
function modifyArgument(argRef, multiplier){
argRef.value = argRef.value * multiplier;
}
(function(){
var x = 10;
alert("x before: " + x);
modifyArgument(eval(byRef("x")), 42);
alert("x after: " + x);
})()
实时示例https://jsfiddle.net/t3k4403w/
实际上有一个很好的解决方案:
function updateArray(context, targetName, callback) {
context[targetName] = context[targetName].map(callback);
}
var myArray = ['a', 'b', 'c'];
updateArray(this, 'myArray', item => {return '_' + item});
console.log(myArray); //(3) ["_a", "_b", "_c"]
我个人不喜欢各种编程语言提供的“通过引用传递”功能。也许是因为我只是发现函数式编程的概念,但是当我看到引起副作用的函数(例如操纵通过引用传递的参数)时,总会感到鸡皮s。我个人坚决拥护“单一责任”原则。
恕我直言,一个函数应该使用return关键字仅返回一个结果/值。除了修改参数/自变量,我只返回修改后的参数/自变量值,并将所有所需的重分配留给调用代码。
但是有时(希望很少),有必要从同一个函数返回两个或多个结果值。在那种情况下,我会选择将所有这些结果值包括在单个结构或对象中。同样,处理任何重新分配都应由调用代码决定。
例:
假设通过在参数列表中使用特殊关键字(例如“ ref”)来支持传递参数。我的代码可能看起来像这样:
//The Function
function doSomething(ref value) {
value = "Bar";
}
//The Calling Code
var value = "Foo";
doSomething(value);
console.log(value); //Bar
相反,我实际上更喜欢这样做:
//The Function
function doSomething(value) {
value = "Bar";
return value;
}
//The Calling Code:
var value = "Foo";
value = doSomething(value); //Reassignment
console.log(value); //Bar
当我需要编写一个返回多个值的函数时,我也不会使用通过引用传递的参数。所以我会避免这样的代码:
//The Function
function doSomething(ref value) {
value = "Bar";
//Do other work
var otherValue = "Something else";
return otherValue;
}
//The Calling Code
var value = "Foo";
var otherValue = doSomething(value);
console.log(value); //Bar
console.log(otherValue); //Something else
相反,我实际上更喜欢在对象内部返回两个新值,如下所示:
//The Function
function doSomething(value) {
value = "Bar";
//Do more work
var otherValue = "Something else";
return {
value: value,
otherValue: otherValue
};
}
//The Calling Code:
var value = "Foo";
var result = doSomething(value);
value = result.value; //Reassignment
console.log(value); //Bar
console.log(result.otherValue);
这些代码示例已经相当简化,但是粗略地展示了我个人如何处理这些东西。它有助于我将各种职责保持在正确的位置。
快乐的编码。:)
我一直在尝试使用语法来完成这种事情,但是它需要一些辅助工具,这有点不寻常。它从根本不使用'var'开始,而是一个简单的'DECLARE'帮助程序,该帮助程序创建了局部变量并通过匿名回调为其定义了作用域。通过控制变量的声明方式,我们可以选择将它们包装到对象中,以便本质上始终可以通过引用传递它们。这类似于上面的Eduardo Cuomo的答案之一,但是下面的解决方案不需要使用字符串作为变量标识符。这里是一些最小的代码来展示这个概念。
function Wrapper(val){
this.VAL = val;
}
Wrapper.prototype.toString = function(){
return this.VAL.toString();
}
function DECLARE(val, callback){
var valWrapped = new Wrapper(val);
callback(valWrapped);
}
function INC(ref){
if(ref && ref.hasOwnProperty('VAL')){
ref.VAL++;
}
else{
ref++;//or maybe throw here instead?
}
return ref;
}
DECLARE(5, function(five){ //consider this line the same as 'let five = 5'
console.log("five is now " + five);
INC(five); // increment
console.log("five is incremented to " + five);
});
其实真的很容易
问题在于要理解,一旦传递经典参数,您就会陷入另一个只读区域。
解决方案是使用JavaScript的面向对象设计传递参数,
这与将args放入全局/作用域变量相同,但更好...
function action(){
/* process this.arg, modification allowed */
}
action.arg = [ ["empty-array"],"some string",0x100,"last argument" ];
action();
您还可以承诺东西以享受著名的连锁店:这是整个东西,具有类似于承诺的结构
function action(){
/* process this.arg, modification allowed */
this.arg = ["a","b"];
}
action.setArg = function(){this.arg = arguments; return this;}
action.setArg(["empty-array"],"some string",0x100,"last argument")()
或更好。
action.setArg(["empty-array"],"some string",0x100,"last argument").call()
Javascript可以修改函数内部的数组项(将其作为对对象/数组的引用传递)。
function makeAllPretty(items) {
for (var x = 0; x < myArray.length; x++){
//do stuff to the array
items[x] = makePretty(items[x]);
}
}
myArray = new Array(var1, var2, var3);
makeAllPretty(myArray);
这是另一个例子:
function inc(items) {
for (let i=0; i < items.length; i++) {
items[i]++;
}
}
let values = [1,2,3];
inc(values);
console.log(values);
// prints [2,3,4]
JS不是强类型,它可以让您以许多不同的方式解决问题,如本教程所述。
但是,从可维护性的角度来看,我必须同意Bart Hofland的观点。函数应该让args做一些事情并返回结果。使它们易于重用。
如果您认为需要通过引用传递变量,则最好将其构建为对象IMHO。
撇开通过引用的讨论,仍在寻找所述问题的解决方案的人员可以使用:
const myArray = new Array(var1, var2, var3);
myArray.forEach(var => var = makePretty(var));
我确切地知道你的意思。Swift中的相同问题将没有问题。底线是let
不使用var
。
var i
至少可以说,原始函数是通过值传递的,但是迭代点的值没有复制到匿名函数中这一事实令人惊讶。
for (let i = 0; i < boxArray.length; i++) {
boxArray[i].onclick = function() { console.log(i) }; // correctly prints the index
}
我喜欢解决缺乏参考的问题此示例所示的Javascript中。
这样做的本质是,您不必尝试创建by引用,而应使用return功能,并使其能够返回多个值。因此,无需将值插入数组或对象中。
var x = "First";
var y = "Second";
var z = "Third";
log('Before call:',z,y,z);
with (myFunc(x, y, z)) {x = a; y = b; z = c;} // <-- way to call it
log('After call :',z,y,z);
function myFunc(a, b, c) {
a = "Changed first parameter";
b = "Changed second parameter";
c = "Changed third parameter";
return {a:a, b:b, c:c}; // <-- return multiple values
}
function log(txt,p1,p2,p3) {
document.getElementById('msg').innerHTML += txt + '<br>' + p1 + '<br>' + p2 + '<br>' + p3 + '<br><br>'
}
<div id='msg'></div>
如果要通过引用传递变量,最好的方法是在对象中传递参数,然后使用window开始更改值
window["varName"] = value;
例如:
// variables with first values
var x = 1 , b = 0 , f = 15;
//passing variables in object //pass new values in array
function asByReference (argumentHasVars = {} , newValues = []){
let VarsNames = [];
// getting variables names one by one
for(let name in argumentHasVars) VarsNames.push(name);
// accessing variables by using window one by one // set new value
for(let i = 0 ; i < VarsNames.length ; i += 1) window[VarsNames[i]] = newValues[i];
}
console.log(x , b , f); // output with first values
asByReference( {x , b , f} , [5 , 5 , 5] ); // passing as by ref
console.log(x , b , f); // output after changing values
文章标签:javascript , pass-by-reference , variables
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!