本篇内容参考连结
PJCHENder
Data Type
首先必须了解, 在Javascript中, 有需多资料型别, 主要分成两大类. 分别是基本型别(primitive type)和物件型别(Object).
Primitive type:BooleanNullUndefinedNumberBigIntStringSymbolObject:Array, function, map, ...etc一般来说, Primitive type会是Call by Value, 而Object则是 Call by Reference. 接下来会用几个程式範例来解释.
Call by Value
直接来看简单的範例, 先建立一个变数 a
并赋予值 3
. 再来建立变数 b
, 并把b
的值等于a
. 最后再把 a
的值改成2
.
var a = 3;var b;b = a;a = 2;console.log(a);console.log(b);
再来我们看到结果很直观的呈现
a is 2
b is 3
由此可知道当把一个变数等于另一个变数时, 只把值赋予给另一个变数, 之后两者是独立的, 操作并不互相影响. 往更底层去了解的话, 即是当我们在建立 primitive type 的变数时, 会把他存在记忆体的某个地方(假设为 0x001), 而当我们宣告另一个变数, 并把前一个的值赋予给他的时候, 他其实会建立自己的记忆体位址(假设为 0x002). 所以当之后操作的时候, 因为本身就处于不同的记忆体位址, 所以不会互相干扰. 这个就是所谓的 Call by Value.
Call by Value 大部分都会发生在 primitive type 的变数
Call by Reference
直接来看简单的範例, 先建立一个变数 a
并赋予一个Object { text: "Hello"}
. 再来建立变数 b
, 并把b
的值等于a
. 最后再把 a
里的Property text的值改成Hi
.
var a = { text: "Hello"};var b;b = a;a.text = "Hi";console.log(a);console.log(b);
结果b的值也一起被更新了
{ text: 'Hi' }
{ text: 'Hi' }
当变数为Object时, 赋予给先的变数. 两者会相依, 在之后的操作也会互相影响. 从记忆体的方面来说, 当建立a时, 会存在位址(假设为 0x001). 而当建立b并把a的值赋予b时, 这时候并不会再给他一个新的位址, 而是把b指定到相同位址(0x001). 所以当在操作更改值时, 从变数a或变数b, 其实都是对存在位址0x001的值做操作, 所以才会更改a的时候, b也一起被更新. 这个就是所谓的 Call by Reference.
Call by Reference 大部分都会发生在 Object 的变数
Call by Reference - Additional Information
等于(== 或是 ===)被用reference type上, 则会比较reference不会是value. 参考以下例子
var a = { text: "Hello"};var b;console.log(a == b); // truevar c = { text: "Hello"};var d = { text: "Hello"};console.log(c == d); // false
所以在比较时, 可以先把其转成primitive type: string
var c = { text: "Hello" };var d = { text: "Hello" };console.log(c == d); // falsevar e = JSON.stringify({ text: "Hello" });var f = JSON.stringify({ text: "Hello" });console.log(e == f); // true
Call by Sharing
这次来看一个比较特别的例子, 对上面call by reference的例子做点修改, 这次不是更新Object里的Property, 而是直接给一个新的Object.
var a = { text: "Hello" };var b;b = a;a = { text: "Hi" };console.log(a);console.log(b);
这次结果则不会一起更新
{ text: 'Hi' }
{ text: 'Hello' }
当Object被重新赋予值时(并非更新Property), 则会记忆体给予一个新个位置. 事实上, Javascript不属于单纯的by value 或是 by Reference. 更準确来说就是Call by sharing. 所以当Object被重新赋值时, 基本上就会跟Pass by Value的结果一模一样. 当Object仅内容被更新时, 则会回到call by reference的结果.