数据类型

278 阅读4分钟

小知识,大挑战!本文正在参与“  程序员必备小知识  ”创作活动

本文同时参与 「掘力星计划」  ,赢取创作大礼包,挑战创作激励金

分类

基础类型

存储在栈内存,被引用或拷贝时,会创建一个完全相等的变量

  • Undefined
  • Null
  • Boolean
  • String
  • Number
  • Symbol
  • BigInt

引用类型(共享)

存储在堆内存,存储的是地址,多个引用指向同一个地址

  • Object

    • Array
    • RegExp
    • Date
    • Math
    • Function

类型检测

typeof

  • 基础类型

    • 除了null返回'object',其他返回相应类型
  • 引用类型

    • 除了function会返回"function",其他都是'object'

instanceof

  • 基础类型

    • 无法判断
  • 引用类型

    • 可以准确判断

Object.prototype.toString.call()

  • 返回格式为"[Object Xxx]"

类型转换

强制转换

  • Number()

    • 布尔值

      • true=>1
      • false=>0
    • 数值

      • 自身
    • null

      • 0
    • undefined

      • NaN
    • 字符串

      • 数字

        数字或者是 0X / 0x 开头的十六进制数字字符串,允许包含正负号

        • 十进制
      • 有效的浮点格式

        • 浮点数值
      • 空字符串

        • 0
      • 其他

        • NaN
    • Symbol

      • 抛出错误
    • Object

      • 下面细讲
  • parseInt()

  • parseFloat()

  • toString()

  • String()

  • Boolean()

    • undefined、 null、 false、 ''、 0(包括 +0,-0)、 NaN

      • false
    • 其他

      • true

隐式转换

  • ==

    • 类型相同

      • 不用转换
    • null == undefined为true,其他都是false

    • ?== Symbol

      • false
    • string和number相比

      • 字符串转number
    • 与boolean相比

      • 转成number
    • object与(string、number 或者 symbol)

      • object转基本类型
    • 与字符串相加,另一数值调用toString() ; 与数字相加,另-是调用Number();与对象相加,则要将对象转基本类型

      • 数字+数字

        • 加法
      • 字符串+字符串

        • 字符串拼接
      • 字符串+(undefined/null/布尔型/数字)

        '1' + 3 => '13'

        • 调用toString()拼接
      • (字符串/数字)+(纯对象/数组/正则等)

        • 对象转基本类型再拼接
      • 数字+(undefined/null/布尔型/数字)

        • 转成数字(Number())再加法

对象转换

  • 语法

    • Symbol.toPrimitive
    • valueOf(),为基础类型才返回
    • toString(),为基础类型才返回
    • 都不是基础类型,报错
  • 示例

    • [] + []

      • “”
      • [].valueOf()非基础类型,toString()是空字符串,相当于""+""
    • [] + {}

      • '[object Object]'
      • {}.valueOf()非基础类型, toString()是'[object Object]'
    • {} + {}

      • NaN
      • 第一个{}被js引擎解释成空的代码块并忽略,所以相当于+{}=>Number({})=>Number({}.toString())=>Number(['object Object'])=>NaN
    • ({}+{})

      • '[object Object][object Object]'
      • 加上括号就变成表达式,而非代码块
    • {} + []

      • 0
      • 第一个{}被js引擎解释成空的代码块并忽略,所以相当于+[]=>Number([])=>Number({}.toString())=>Number('')=>0
    • 10+{}

      • 10['object Object']
    • {}+10

      • 10
      • {}被当作空代码块忽略

模拟实现浅拷贝

  1. 对基础类型做一个最基本的一个拷贝;
  2. 对引用类型开辟一个新的存储,并且拷贝一层对象属性。
const shallowClone = (target) => {
    if (typeof target === 'object' && target !== null) {
      const cloneTarget = Array.isArray(target) ? [] : {}
      for (let prop in target) {
        if (target.hasOwnProperty(prop)) {
          cloneTarget[prop] = target[prop]
        }
      }
      return cloneTarget
    } else {
      return target
    }
}
// 1.基础类型
let v1 = 'string1'
let v2 = shallowClone(v1)
v2 = 'string2'
console.info('v1:', v1) // v1: string1
console.info('v2:', v2) //v2: string2
// 2.引用类型,属性值为基础类型的不会互相影响,为引用类型的就会
const obj = { a: 2, d: { name: '张三' } }
const newObj = shallowClone(obj)
newObj.a = 33
newObj.d.name = '李四'
console.info(JSON.stringify(newObj), 'newObj') 
// {"a":33,"d":{"name":"李四"}} newObj
console.info(JSON.stringify(obj), 'obj') 
// {"a":2,"d":{"name":"李四"}} obj

JSON.stringify实现深拷贝存在问题

function Obj() {
    this.func = function () {
      alert(1)
    } //消失
    this.und = undefined //消失
    this.sym = Symbol(1) // 消失
    this.obj = { a: 1 }
    this.arr = [1, 2, 3]
    this.reg = /123/ //{}
    this.date = new Date(0) //字符串
    this.NaN = NaN // null
    this.infinity = Infinity // null
   
}

let obj1 = new Obj()
Object.defineProperty(obj1, 'innumerable', {
enumerable: false,
value: 'innumerable'
}) //会消失
console.log('原obj1', obj1)
console.log('obj1', JSON.stringify(obj1))
let str = JSON.stringify(obj1)
let obj2 = JSON.parse(str)
console.log('obj2', JSON.stringify(obj2))

手写递归实现深拷贝

function deepClone(target) {
    let cloneObj = {}
    for (let key in target) {
      if (typeof target[key] == 'object') {
        cloneObj[key] = deepClone(target[key]) //递归
      } else {
        cloneObj[key] = target[key]
      }
    }
    return cloneObj
}
// let obj1 = {
//  a: 2
// }
// let obj2 = deepClone(obj1)
// obj2.a = 55
// console.info('obj2:', obj2) // {a:55}
// console.info('obj1:', obj1) // {a:2}

// let newObj1 = {
//  a: { b: 22 }
// }
// let newObj2 = deepClone(newObj1)
// newObj2.a.b = 55
// console.info('newObj2:', newObj2) // { a: { b: 55 } }
// console.info('newObj1:', newObj1) // { a: { b: 22 } }

// 对各种属性类型做验证
// let newObj1 = {
//  a: { b: 22 },
//  fun1: function () {
//    //函数可以拷贝
//    console.info(22)
//  },
//  und: undefined, // undefined的正常
//  sym: Symbol(2), // symbol正常
//  date: new Date(), //变成字符串
//  reg: new RegExp(/\s+/), //变成空对象
//  nan: NaN, // 正常
//  inf: Infinity // 正常
// }
// Object.defineProperty(newObj1, 'enumeration', {
//  enumerable: false, // 不可枚举的属性拷贝不了
//  value: '枚举'
// })
// let newObj2 = deepClone(newObj1)
// newObj2.a.b = 55
// console.info('newObj2:', newObj2) // { a: { b: 55 } }
// console.info('newObj1:', newObj1) // { a: { b: 22 } }

let arr1 = [1, 2, 3]
let arr2 = deepClone(arr1) //返回的是{0: 1, 1: 2, 2: 3}
arr2.push(33) //因为是非数组对象,所以报错
console.info(arr1, arr2)