在Javascript中通过引用传递variables
如何在JS中通过引用传递variables? 我有3个variables,我想执行几个操作,所以我想把它们放在一个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"
现在,就你的情况而言,就我所知,你还没有传递任何东西。 如果需要,可以使用数字索引遍历数组的属性,并修改数组的每个单元格。
重要的是要注意“通过引用”是一个非常具体的术语。 这并不意味着可以将引用传递给可修改的对象。 相反,这意味着可以通过一个简单的variables来允许函数在调用上下文中修改该值。 所以:
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 ++这样的语言中,可能会这样做,因为该语言具有传递引用的function。
编辑 – 最近这个(2015年3月)再次在Reddit上爆炸了一个类似于我的下面提到的博客文章,虽然在这个例子中关于Java。 我在阅读Reddit的评论时发现,很大一部分的混淆源于“参考”一词的不幸碰撞。 术语“通过引用”和“按值传递”早于具有“对象”在编程语言中工作的概念。 这根本不是关于物体的; 它是关于函数参数的,特别是函数参数如何“连接”(或不)到呼叫环境。 尤其要注意的是,在一个真正的按引用引用的语言中 – 一个涉及对象的语言 – 仍然能够修改对象内容 ,而且看起来与JavaScript中的内容非常相似。 但是, 也可以在调用环境中修改对象引用,这是您在JavaScript中无法做到的关键。 通过引用的语言不会传递引用本身,而是引用引用 。
编辑 – 这里是关于这个话题的博客文章。 (注意这篇文章的评论,说明C ++并没有真正的传递引用,但是C ++确实有能力创build对普通variables的引用,或者明确地在函数调用来创build指针,或者在调用其参数types签名要求完成的函数时隐式地执行,这些是JavaScript不支持的关键。
- 像string和数字这样的原始typesvariables总是按值传递的。
-
数组和对象通过引用或基于这些条件的值被传递:
-
如果您正在设置对象或数组的值,则为“按值传递”。
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
解决方法像引用一样传递variables:
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]; } }
variables声明
rvar('test_ref'); test_ref = 5; // test_ref.value = 5
要么:
rvar('test_ref', 5); // test_ref.value = 5
testing代码
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');
testing控制台结果
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
另一种通过引用来传递任何(本地,原始)variables的方法是通过用eval
“dynamic地”封闭variables来封装variables。 这也适用于“严格使用”。 (请注意, eval
对JS优化器不友好,同时在variables名称周围缺less引号可能会导致不可预知的结果)
"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); })()
我一直在用语法来做这种事情,但是它需要一些有点不同寻常的帮手。 它始于不使用“var”,而是一个简单的“DECLARE”助手,它创build一个局部variables并通过匿名callback为其定义一个范围。 通过控制如何声明variables,我们可以select将它们包装到对象中,以便它们始终可以通过引用传递,本质上。 这与上面Eduardo Cuomo的答案类似,但下面的解决scheme不需要使用string作为variables标识符。 这里有一些简单的代码来展示这个概念。
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); });
其实这很简单,
问题在于,一旦传递经典参数,您将被限制到另一个只读区域。
解决scheme是使用JavaScript的面向对象devise来传递参数,
这是一样的把参数放在一个全局/范围的variables,但更好…
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()
实际上有一个相当的溶剂:
function updateArray(context, targetName, callback) context[targetName] = context[targetName].map(callback); end var myArray = ['a', 'b', 'c']; updateArray(this, 'myArray', item => {return '_' + item}); console.log(myArray); //(3) ["_a", "_b", "_c"]