我的两分钱...这就是我的理解方式。(如果我错了,请随时纠正我)
现在该丢掉您所知道的关于按值/引用传递的所有信息。
因为在JavaScript中,按值,按引用或其他方式传递都无关紧要。重要的是传递给函数的参数的变异与赋值。
好,让我尽力解释我的意思。假设您有几个对象。
var object1 = {};
var object2 = {};
我们要做的是“赋值” ...我们已经为变量“ object1”和“ object2”分配了2个单独的空对象。
现在,让我们说我们更喜欢object1 ...因此,我们“分配”了一个新变量。
var favoriteObject = object1;
接下来,无论出于何种原因,我们决定我们更喜欢对象2。因此,我们只需进行一些重新分配。
favoriteObject = object2;
对象1或对象2均未发生任何事情。我们根本没有更改任何数据。我们所做的只是重新分配了我们最喜欢的对象。重要的是要知道object2和favoriteObject都已分配给同一对象。我们可以通过这些变量之一来更改该对象。
object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe
好了,现在让我们来看诸如字符串之类的图元
var string1 = 'Hello world';
var string2 = 'Goodbye world';
同样,我们选择一个收藏夹。
var favoriteString = string1;
我们的收藏夹字符串和字符串1变量都分配给了“ Hello world”。现在,如果我们想更改我们的收藏夹字符串?会发生什么???
favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'
呃哦...发生了什么事。我们无法通过更改favoriteString来更改string1 ...为什么?因为我们没有更改字符串对象。我们所做的只是将“ favoriteString” 变量 “重新分配” 为新字符串。这实际上将其与string1断开了连接。在上一个示例中,当我们重命名对象时,我们没有分配任何东西。(但是,不是将变量本身分配给...,但是,我们确实将name属性分配给了新的字符串。)相反,我们仅对对象进行了突变,以保持2个变量与基础对象之间的连接。(即使我们想修改或变异了字符串对象本身,我们没有,因为字符串实际上在JavaScript中是不可变的。)
现在,介绍函数并传递参数...。当您调用函数并传递参数时,您实际上要做的是对新变量的“赋值”,它的工作原理与您使用等号(=)。
举这些例子。
var myString = 'hello';
// Assign to a new variable (just like when you pass to a function)
var param1 = myString;
param1 = 'world'; // Re assignment
console.log(myString); // Logs 'hello'
console.log(param1); // Logs 'world'
现在,同样的东西,但是有一个功能
function myFunc(param1) {
param1 = 'world';
console.log(param1); // Logs 'world'
}
var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString);
console.log(myString); // logs 'hello'
好的,现在让我们举几个使用对象的示例……首先,不使用函数。
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;
// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'
// Now, let's reassign the variable
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';
现在,同样的事情,但是有一个函数调用
function myFunc(otherObj) {
// Let's mutate our object
otherObj.firstName = 'Sue';
console.log(otherObj.firstName); // Logs 'Sue'
// Now let's re-assign
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
console.log(otherObj.firstName); // Logs 'Jack'
// Again, otherObj and myObject are assigned to 2 very different objects
// And mutating one object doesn't magically mutate the other
}
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);
console.log(myObject.firstName); // Logs 'Sue', just like before
好吧,如果您通读了整篇文章,也许您现在对函数调用在JavaScript中的工作方式有了更好的了解。无论是通过引用还是通过值传递,都没有关系。重要的是赋值与变异。
每次将变量传递给函数时,都将“赋值”参数变量的名称,就像使用了等号(=)一样。
始终记住,等号(=)表示赋值。永远记住,将参数传递给JavaScript中的函数也意味着赋值。它们是相同的,并且2个变量以完全相同的方式连接(也就是说,它们不是一样,除非您算出它们已分配给同一对象)。
“修改变量”唯一会影响其他变量的时间是基础对象发生突变时(在这种情况下,您尚未修改变量,而是对象本身。
在对象和基元之间进行区分是没有意义的,因为它的工作方式与您没有函数并且只是使用等号分配给新变量的方式相同。
唯一的难题是,当您传递给函数的变量名称与函数参数的名称相同时。发生这种情况时,您必须将函数内部的参数视为是函数专有的全新变量(因为它是)
function myFunc(myString) {
// myString is private and does not affect the outer variable
myString = 'hello';
}
var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';
myFunc(myString);
console.log(myString); // Logs 'test'