布尔值作为原始类型和作为对象属性有什么区别?

6
我正在学习一些有关HTML5画布的教程,以下是其中的一部分代码。
在这段代码中,为什么他们不选择将runAnimation设置为一个简单的布尔值?我认为x = !x语句无论如何都可以工作,但当我尝试改变代码使用布尔变量时,代码并没有起作用。
那么,原始布尔值和对象属性布尔值之间有什么区别呢?
   /*
   * define the runAnimation boolean as an object
   * so that it can be modified by reference
   */
  var runAnimation = {
    value: false
  };

  // add click listener to canvas
  document.getElementById('myCanvas').addEventListener('click', function() {
    // flip flag
    runAnimation.value = !runAnimation.value;
1个回答

8
在JavaScript中,所有参数都是按“值”传递的。这意味着传递参数时会传递变量存储内容的副本。
原始值(如布尔值)存储它们所代表的实际数据,因此当传递原始值时,会发送数据的副本,从而产生两个数据副本。对一个副本进行更改不会影响另一个。
但是,当你将对象分配给变量时,变量存储该对象可以被找到的内存位置,而不是对象本身。将对象作为参数传递会导致传递内存地址的副本。在这些情况下,您可能会得到两个变量,它们存储相同的内存地址,因此无论使用哪个变量,都会影响相同的基础对象。
在您的场景中,您肯定可以只使用布尔变量使其工作,但似乎教程想要封装它成为一个对象,以便不会出现浮动布尔数据的副本,并且有更少的机会意外更改一个变量而不更改另一个。
以下是一些基本示例:

// This function takes a single argument, which it calls "input"
// This argument will be scoped to the function.
function foo(input){
  // The function is going to alter the parameter it received
  input = input + 77;
  console.log(input); 
}

var input = 100;  // Here's a higher scoped variable also called "input"

foo(input);       // We'll pass the higher scoped variable to the function

// Now, has the higher level scoped "input" been changed by the function?
console.log(input);  // 100 <-- No, it hasn't because primitives pass a copy of their data

// ************************************************

// Now, we'll do roughly the same thing, but with objects, not primitives
function foo2(obj){
  obj.someProp = 100;
  console.log(obj.someProp);
}

var obj = {
  someProp : 50
};

foo2(obj);

// Here, we see that the original object has been changed by the funciton we passed it to
console.log(obj.someProp);


你说过:“原始类型(如布尔值)存储它们所代表的实际数据,因此当传递原始类型时,会发送数据的副本,导致数据有两个副本。” 字符串也是原始类型 - 这是否意味着传递字符串会导致两个字符串的副本? - Mark
@ScottMarcus 我在谈论字符串原始类型。所以,如果我有一个包含1000万个字符的原始字符串,并将其作为参数传递给函数,那么现在会有两个字符串,其中数百万字节在内存中被复制?这不是非常低效吗? - Mark
@Mark 不,这不会发生,因为那样会改变代码的行为。如果我有一个字符串原始值,我需要知道当我与变量交互时,我将处理实际的字符串数据(并且可以通过传递它来获取副本)。这就是为什么我们有制作String对象或string原始值的选项,以便开发人员在需要你所说的行为时使用。规范确实规定了实现如何处理原始值和对象。 - Scott Marcus
@ScottMarcus 哦,那很有趣 - 那么似乎我对“不可变”的理解是错误的。你能给我指出一些代码,展示字符串数据实际上是被复制的,并且不仅仅是两个对同一数据的引用吗? - Mark
@Mark Immutable发生是因为字符串的内存分配实际上不能像其他已知内存需求的基元那样动态。如果一个字符串随着时间的推移增长或缩小,系统实际上没有选择,只能创建一个新的内存位置以适合该新字符串的正确大小,而不是使用现有字符串的内存。然而,这与如何传递基元(按值)是分开的。我真的想不出任何演示按值过程的方法,因为修改副本字符串将创建一个新字符串... - Scott Marcus
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接