《javascript高级程序设计》学习笔记 | 4.1.原始值与引用值
Posted 小讴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《javascript高级程序设计》学习笔记 | 4.1.原始值与引用值相关的知识,希望对你有一定的参考价值。
关注前端小讴,阅读更多原创技术文章
原始值与引用值
- JS 变量是松散类型的:① 不必规定变量的数据类型 ② 变量的值和数据类型可随时改变
JS 变量可以包含 2 种类型的数据:原始值和引用值
- 原始值是简单数据(6 种原始值:Undefined、Null、Boolean、Number、String、Symbol),按值访问,操作实际值
- 引用值是保存在内存中的对象,按引用访问,操作对该对象的引用(而非对象本身)
相关代码 →
动态属性
- 对于引用值,可以随时添加、修改、删除其属性和方法
let personRefer = new Object() // 创建对象
personRefer.name = \'Nicholas\' // 添加属性并赋值
console.log(personRefer.name) // \'Nicholas\'
- 对于原始值,不能拥有属性(尝试添加属性不会报错)
let namePrim = \'Nicholas\' // 原始值
namePrim.age = 27 // 给原始值添加属性
console.log(namePrim.age) // undefined,不报错但无效
- 用 new 关键字创建原始值包装类型对象,属于(类似于原始类型的)特殊引用类型
let name1 = \'Nicholas\' // 原始类型
let name2 = new String(\'Matt\') // 原始值包装类型
name1.age = 27
name2.age = 26
console.log(name1.age) // undefined,原始类型不能有属性
console.log(name2.age) // 26,引用类型可以有属性
console.log(typeof name1) // string,原始类型
console.log(typeof name2) // object,引用类型
复制值
- 原始值复制时,新值是旧值的副本,新值和旧值相互独立使用、互不干扰
let num1Prim = 5
let num2Prim = num1Prim
console.log(num2Prim) // 5,原始值,复制的值是副本
num2Prim = 6 // 副本发生改变
console.log(num2Prim) // 6
console.log(num1Prim) // 5,被复制的值无变化
- 引用值复制时,新值和旧值共同指向堆内存中的同一个对象,新值或旧值发生改变相互影响
let obj1Refer = new Object()
let obj2Refer = obj1Refer // 引用值,复制的值是指针
obj2Refer.name = \'Nicholas\' // 一个对象发生改变
console.log(obj2Refer.name) // \'Nicholas\'
console.log(obj1Refer.name) // \'Nicholas\',影响另一个对象
delete obj1Refer.name // 一个对象发生改变
console.log(obj1Refer.name) // undefined
console.log(obj2Refer.name) // undefined,影响另一个对象
传递参数
ECMAScript 中所有函数的参数都是按值传递的——函数外的值被复制到函数内部的参数时,和一个变量复制到另一个变量一样:
- 原始值作为参数时,函数内部改变参数,函数外的值不受影响
- 引用值作为参数时,函数内部改变对象的属性,函数外的对象受影响
/* 原始值作为参数 */
let count = 10 // 函数外,原始值作为参数
function addTen(num) {
num += 10 // 函数内,参数的值发生改变
return num
}
let result = addTen(count)
console.log(result) // 30
console.log(count) // 20,未受影响
/* 引用值作为参数 */
let person = new Object() // 函数外,引用值作为参数
function setName(obj) {
obj.name = \'Nicholas\' // 函数内,obj和外部参数person指向同一个对象,并改变了这个对象的属性
}
setName(person)
console.log(person.name) // \'Nicholas\',受影响
尽管用引用值作为参数时,函数内部改变对象的属性会影响函数外的对象,但参数仍然是按值传递的,而不是按引用传递:
- 引用值作为参数时,如果在函数内部重写对象,函数外的对象不受影响,原始的引用仍然没变
- 如果是按引用传递,重写函数内的对象参数后,原始引用应当发生改变
let person2 = new Object()
function setName2(obj) {
obj.name = \'Nicholas\' // 改变参数的属性,参数受影响
obj = new Object() // 重写参数,参数不受该影响
obj.name = \'Greg\'
}
setName2(person2)
console.log(person2.name) // \'Nicholas\'
确定类型
let str = \'Nicholas\'
let num = 30
let boo = true
let u
let n = null
let sym = Symbol()
let f = new Function()
let o = new Object()
let a = new Array()
let r = new RegExp()
- typeof 操作符可检测的类型:String、Number、Boolean、Symbol、Undefined、Function(不包含 Null 的所有原始值和 Function)
console.log(typeof str) // string,原始值
console.log(typeof num) // number,原始值,原始值
console.log(typeof boo) // boolean,原始值
console.log(typeof u) // undefined,原始值
console.log(typeof sym) // symbol,原始值
console.log(typeof f) // function,引用值但是Function会返回function
- typeof 操作符检测任何引用值或 null,结果都是 object
console.log(typeof n) // object,原始值但是Null会返回object
console.log(typeof o) // object,除Function之外的引用值都返回object
console.log(typeof a) // object,除Function之外的引用值都返回object
console.log(typeof r) // object,除Function之外的引用值都返回object
- instanceof 操作符可检测的类型:Object(所有引用值)
console.log(o instanceof Object) // true,o是Object的实例
console.log(f instanceof Function) // true,f是Function的实例
console.log(f instanceof Array) // false,f不是Array的实例
console.log(a instanceof Array) // true,a是Array的实例
console.log(r instanceof RegExp) // true,r是RegExp的实例
- 所有引用值都是 Object 的实例
console.log(f instanceof Object) // true,所有引用类型都是Object的实例
console.log(a instanceof Object) // true,所有引用类型都是Object的实例
console.log(r instanceof Object) // true,所有引用类型都是Object的实例
- instanceof 操作符检测任何原始值,结果都是 false
console.log(n instanceof Object) // false,原始值不是对象,不是Object的实例
总结 & 问点
原始值 | 引用值 |
---|---|
简单数据 | 保存在内存中的对象 |
按值访问 | 按引用访问 |
操作实际值 | 操作对该对象的引用(而非对象本身) |
不能拥有属性 | 随时增、删、改其属性和方法 |
复制的值是副本,相互不影响 | 复制的值是指针,相互影响 |
作为参数时,函数内部改变值不影响参数 | 作为参数时,函数内部改变属性会影响参数,重写不影响 |
typeof 判断类型(null 返回 object) | instanceof 判断类型 |
- 如何理解 JS 的变量是松散类型的?
- 在访问方式和操作方式上,原始值和引用值有什么不同?
- 在通过变量复制时,原始值和引用值有什么不同?
- 作为函数的参数传递时,原始值和引用值有什么不同?
- 如何“按值传递函数的参数”?为什么引用值作为函数的参数也是按值传递而不是按引用传递的?
- 如何判断一个原始值或引用值的具体类型?
以上是关于《javascript高级程序设计》学习笔记 | 4.1.原始值与引用值的主要内容,如果未能解决你的问题,请参考以下文章
javascript 高级程序设计 学习笔记01章 javascript的认知
《JavaScript高级程序设计(第四版)》学习笔记第3章