《javascript高级程序设计》学习笔记|4.1.原始值与引用值

小讴      2022-02-13     536

关键词:

关注前端小讴,阅读更多原创技术文章

原始值与引用值

  • 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.原始值与引用值

关注前端小讴,阅读更多原创技术文章原始值与引用值JS变量是松散类型的:①不必规定变量的数据类型②变量的值和数据类型可随时改变JS变量可以包含2种类型的数据:原始值和引用值原始值是简单数据(6种原始值:Undefined、... 查看详情

《javascript高级程序设计(第四版)》学习笔记第4章(代码片段)

...在这肆意生活里大放光彩📢这是阅读《JavaScript高级程序设计(第四版)》的第四天,本书已阅读102/865第四章:变量、作用域与内存4.1原始值与引用值原始值:最简单 查看详情

《javascript高级程序设计(第四版)》学习笔记第4章(代码片段)

...在这肆意生活里大放光彩📢这是阅读《JavaScript高级程序设计(第四版)》的第四天,本书已阅读102/865第四章:变量、作用域与内存4.1原始值与引用值原始值:最简单 查看详情

javascript高级程序设计---学习笔记

面向对象程序设计1、属性类型、定义多属性、读取属性特性对象的属性在创建时都带有一些特征值,JavaScript通过这些特征值来定义它们的行为。这些特性是为了实现JavaScript引擎用的,因此不能直接访问它们。ECMAScript中有两种... 查看详情

js-javascript高级程序设计学习笔记9

依然第十三章事件1、页面上的所有元素都支持鼠标事件,除了mouseenter和mouseleave,所有鼠标事件都会冒泡。2、修改键:shift、ctrl、alt、meta。四个属性表示修改键的状态:shiftKey等。3、event对象的relatedTarget属性提供了相关元素的... 查看详情

《javascript高级程序设计》学习笔记|10.1-10.8.函数基础

关注前端小讴,阅读更多原创技术文章函数是对象,每个函数都是Function类型的实例,都与其他引用类型一样具有属性和方法函数名是指向函数对象的指针,不会与某个函数绑定(一个函数可能会有多个名字)相关代码→4种定义... 查看详情

javascript高级程序设计学习笔记

知识补充:varbox=document.querySelector(‘#box‘);//"beforebegin",在当前元素之前插入一个紧邻的同辈元素;box.insertAdjacentHTML(‘beforebegin‘,‘<div>beforebegin</div>‘);//"afterend",在当前元素之后插入一个紧邻的同辈元素。box.insertAdj... 查看详情

js-javascript高级程序设计学习笔记21改善javascript性能的方法

第24章最佳实践1、性能1、避免全局查找将在一个函数中会用到多次的全局对象保存在局部变量。比如多次使用document.getElement。。。,可以首先vardoc=document,把document对象保存在本地的doc变量中。2、避免with语句。with会创建自己... 查看详情

java程序猿的javascript学习笔记(1——理念)

计划按例如以下顺序完毕这篇笔记:Java程序猿的JavaScript学习笔记(1——理念)Java程序猿的JavaScript学习笔记(2——属性复制和继承)Java程序猿的JavaScript学习笔记(3——this/call/apply)Java程序猿的JavaScript学习笔记(4——this/闭... 查看详情

javascript高级程序设计学习笔记

...,我觉得我的基础不够牢靠所以我开始从《JavaScript高级程序设计》开始学习起来:第一章: 查看详情

js-javascript高级程序设计学习笔记19

 第22章高级技巧1、高级函数1、安全的类型检测。typeof,instanceof并非完全可靠。安全的类型检测:使用Object原生的toString()方法。functionisArray(value){returnObject.prototype.toString.call(value)=="[objectArray]";}2、作用域安全的构造函数构... 查看详情

javascript高级程序设计学习笔记02

纯属个人笔记,全为原创,仅供参考第二章 在HTML中使用JavaScript              <script>元素    向HTML页面插入JavaScript的主要方法,就是使用< 查看详情

javascript高级程序设计(第三版)学习笔记202123章

第20章,JSONJSON(JavaScriptObjectNotation,JavaScript对象表示法),是JavaScript的一个严格的子集。JSON可表示一下三种类型值:简单值:字符串,数值,布尔值,null,不支持js特殊值:undefined对象:一组无序的键值对数组:一组有序的... 查看详情

《javascript高级程序设计》学习笔记|9.3.代理模式

关注前端小讴,阅读更多原创技术文章代理模式相关代码→跟踪属性访问通过捕获get、set、has等操作,可以监控对象何时何处被访问过constuser={name:'Jake',}constproxy=newProxy(user,{get(target,property,receiver){console.log(`Getting${property}`)returnRefl... 查看详情

《javascript高级程序设计》学习笔记|8.3.继承

关注前端小讴,阅读更多原创技术文章继承面向对象语言支持2种继承方式:接口继承和实现继承JS函数没有签名(不必提前声明变量的类型),只支持实现继承,依靠原型链相关代码→原型链子类型构造函数的原型,被重写为超... 查看详情

javascript高级程序设计(第三版)学习笔记111217章

第11章, DOM扩展选择符 APISelectorAPILevel1核心方法querySelector 、querySelectorAll,兼容的浏览器可以使用 Document,Element 实例调用它们,支持浏览器:IE8+,Firefox3.5+,Safari3.1+,chrome,Opera10+querySelector方法接收一个& 查看详情

javascript高级程序设计学习笔记01

纯属个人笔记,全为原创,仅供参考第一章JavaScript简介                    JavaScript 诞生于1995年。它是在 一个星期内 被创造出 查看详情

javascript高级程序设计(第三版)学习笔记222425章

第22章,高级技巧高级函数安全的类型检测typeof会出现无法预知的行为instanceof在多个全局作用域中并不能正确工作调用Object原生的toString方法,会返回[ObjectNativeConstructorName]格式字符串。每个类内部都有一个[[Class]]属性,这个属... 查看详情