关注前端小讴,浏览更多原创技术文章

原始值与援用值

  • 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 = 27name2.age = 26console.log(name1.age) // undefined,原始类型不能有属性console.log(name2.age) // 26,援用类型能够有属性console.log(typeof name1) // string,原始类型console.log(typeof name2) // object,援用类型

复制值

  • 原始值复制时,新值是旧值的正本,新值和旧值互相独立应用、互不烦扰
let num1Prim = 5let num2Prim = num1Primconsole.log(num2Prim) // 5,原始值,复制的值是正本num2Prim = 6 // 正本产生扭转console.log(num2Prim) // 6console.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) // undefinedconsole.log(obj2Refer.name) // undefined,影响另一个对象

传递参数

  • ECMAScript 中所有函数的参数都是按值传递的——函数外的值被复制到函数外部的参数时,和一个变量复制到另一个变量一样:

    • 原始值作为参数时,函数外部扭转参数,函数外的值不受影响
    • 援用值作为参数时,函数外部扭转对象的属性,函数外的对象受影响
/* 原始值作为参数 */let count = 10 // 函数外,原始值作为参数function addTen(num) {  num += 10 // 函数内,参数的值产生扭转  return num}let result = addTen(count)console.log(result) // 30console.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 = 30let boo = truelet ulet n = nulllet 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会返回objectconsole.log(typeof o) // object,除Function之外的援用值都返回objectconsole.log(typeof a) // object,除Function之外的援用值都返回objectconsole.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 的变量是涣散类型的?
  • 在拜访形式和操作形式上,原始值和援用值有什么不同?
  • 在通过变量复制时,原始值和援用值有什么不同?
  • 作为函数的参数传递时,原始值和援用值有什么不同?
  • 如何“按值传递函数的参数”?为什么援用值作为函数的参数也是按值传递而不是按援用传递的?
  • 如何判断一个原始值或援用值的具体类型?