JavaScript 中的原始值(undefined,null、布尔值、数字和字符串)与对象(包括数组和函数)有着根本区别。原始值是不可更改的:任何方法都无法更改(或“突变”)一个原始值。对数字和布尔值来说显然如此一改变数字的值本身就说不通,而对字符串来说就不那么明显了,因为字符串看起来像由字符组成的数组,我们期望可以通过指定索引来修改字符串中的字符。实际上,JavaScript 是禁止这样做的。字符串中所有的方法看上去返回了一个修改后的字符串,实际上返回的是一个新的字符串值。例如:
| > var s = "hello"; |
| > s.toUpperCase(); |
| > s |
| var h = "hzh"; |
| console.log("转换为大写字母:"); |
| console.log(h.toUpperCase()); |
| console.log(""); |
| console.log("输出hzh变量:"); |
| console.log(h); |
| [Running] node "e:\HMV\JavaScript\JavaScript.js" |
| 转换为大写字母: |
| HZH |
| |
| 输出hzh变量: |
| hzh |
| |
| [Done] exited with code=0 in 0.174 seconds |
原始值的比较是值的比较:只有在它们的值相等时它们才相等。这对数字、布尔值、null 和 undefined来说听起来有点儿难懂,并没有其他办法来比较它们。同样,对于字符串来说则并不明显:如果比较两个单独的字符串,当且仅当它们的长度相等且每个索引的字符都相等时,JavaScript 才认为它们相等。
对象和原始值不同,首先,它们是可变的——它们的值是可修改的:
| var o = { x:1 }; |
| o.x = 2; |
| o.y = 3; |
| |
| var a = [1,2,3] |
| a[0] = 0; |
| a[3] = 4; |
| var hzh1 = { x:1 }; |
| hzh1.x = 2; |
| hzh1.y = 3; |
| |
| var a = [1,2,3] |
| a[0] = 0; |
| a[3] = 4; |
| |
| console.log("检查hzh1对象的x属性是否发生变化:"); |
| console.log("hzh1.x = " + hzh1.x); |
| console.log(""); |
| console.log("检查hzh1对象是否新增y属性:"); |
| console.log("hzh1.y = " + hzh1.y); |
| console.log(""); |
| console.log("检查a[0]的值是否发生变化:"); |
| console.log("a[0] = " + a[0]); |
| console.log(""); |
| console.log("检查是否新增a[3]元素:"); |
| console.log("a[3] = " + a[3]); |
| [Running] node "e:\HMV\JavaScript\JavaScript.js" |
| 检查hzh1对象的x属性是否发生变化: |
| hzh1.x = 2 |
| |
| 检查hzh1对象是否新增y属性: |
| hzh1.y = 3 |
| |
| 检查a[0]的值是否发生变化: |
| a[0] = 0 |
| |
| 检查是否新增a[3]元素: |
| a[3] = 4 |
| |
| [Done] exited with code=0 in 0.17 seconds |
对象的比较并非值的比较:即使两个对象包含同样的属性及相同的值,它们也是不相等的。各个索引元素完全相等的两个数组也不相等。
| var o = {x:1}, p = {x:1}; |
| o === p |
| var a = [], b =[]; |
| a === b |
| var h = { hzh1: "黄子涵" }; |
| var H = { hzh1: "黄子涵" }; |
| console.log("判断对象h和对象H是否严格相等:"); |
| console.log( h === H ); |
| console.log(""); |
| var z = []; |
| var Z = []; |
| console.log("判断数组z和数组Z是否严格相等:"); |
| console.log( z === Z ); |
| [Running] node "e:\HMV\JavaScript\JavaScript.js" |
| 判断对象h和对象H是否严格相等: |
| false |
| |
| 判断数组z和数组Z是否严格相等: |
| false |
| |
| [Done] exited with code=0 in 0.173 seconds |
我们通常将对象称为引用类型(reference type),以此来和JavaScript的基本类型区分开来。依照术语的叫法,对象值都是引用(reference),对象的比较均是引用的比较:当且仅当它们引用同一个基对象时,它们才相等。
| var a = []; |
| var b = a; |
| b[0] = 1; |
| a[0] |
| a === b |
| var a = []; |
| console.log("输出a:"); |
| console.log(a); |
| console.log(""); |
| var b = a; |
| console.log("输出b:"); |
| console.log(b); |
| b[0] = 1; |
| console.log(""); |
| console.log("看看a[0]有没有被修改:"); |
| console.log(a[0]); |
| console.log(""); |
| console.log("判断a和b是否相等:"); |
| console.log(a === b); |
| [Running] node "e:\HMV\JavaScript\JavaScript.js" |
| 输出a: |
| [] |
| |
| 输出b: |
| [] |
| |
| 看看a[0]有没有被修改: |
| 1 |
| |
| 判断a和b是否相等: |
| true |
| |
| [Done] exited with code=0 in 0.2 seconds |
就像你刚看到的如上代码,将对象(或数组)赋值给一个变量,仅仅是赋值的引用值:对象本身并没有复制一次。如果你想得到一个对象或数组的副本,则必须显式复制对象的每个属性或数组的每个元素。下面这个例子则是通过循环来完成数组复制:
| var a = ['a','b','c']; |
| var b = []; |
| for(var i = 0; i < a.length; i++) { |
| b[i] = a[i]; |
| } |
| var a = ['a','b','c']; |
| console.log("输出数组a:"); |
| console.log(a); |
| console.log(""); |
| var b = []; |
| for(var i = 0; i < a.length; i++) { |
| b[i] = a[i]; |
| } |
| console.log("输出数组b:"); |
| console.log(b); |
| console.log(""); |
| console.log("判断数组a和数组b是否相等:"); |
| console.log(a == b); |
| console.log(""); |
| console.log("判断数组a和数组b是否严格相等:"); |
| console.log(a === b); |
| [Running] node "e:\HMV\JavaScript\JavaScript.js" |
| 输出数组a: |
| [ 'a', 'b', 'c' ] |
| |
| 输出数组b: |
| [ 'a', 'b', 'c' ] |
| |
| 判断数组a和数组b是否相等: |
| false |
| |
| 判断数组a和数组b是否严格相等: |
| false |
| |
| [Done] exited with code=0 in 0.193 seconds |
同样的,如果我们想比较两个单独的对象或者数组,则必须比较它们的属性或元素。下面这段代码定义了一个比较两个数组的函数:
| function equalArrays(a,b) { |
| if (a.length != b.length) return false; |
| for(var i = 0; i < a.length; i++) |
| if (a[i] !== b[i]) return false; |
| return true; |
| } |
| var hzh1 = ["黄", "子", "涵"]; |
| var hzh2 = ["黄", "子", "涵"]; |
| var hzh3 = ["黄", "春", "钦"]; |
| |
| function equalArrays(a,b) { |
| if (a.length != b.length) return false; |
| for(var i = 0; i < a.length; i++) |
| if (a[i] !== b[i]) return false; |
| return true; |
| } |
| |
| console.log("判断hzh1和hzh2是否相等:"); |
| console.log(equalArrays(hzh1, hzh2)); |
| console.log(""); |
| console.log("判断hzh1和hzh2是否相等:"); |
| console.log(equalArrays(hzh1, hzh3)); |
| [Running] node "e:\HMV\JavaScript\JavaScript.js" |
| 判断hzh1和hzh2是否相等: |
| true |
| |
| 判断hzh1和hzh2是否相等: |
| false |
| |
| [Done] exited with code=0 in 0.176 seconds |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?