• 1.数据类型


    值类型和引用类型

    常见的值类型和引用类型

    在es6中js的数据类型分为两种:值类型和引用类型
    值类型有:Number数值类型、Boolean布尔、String字符串、Undefined未定义、Null空、Symbol
    引用类型:Object
    其中Object类型包含Function、Array、Date、RegExp、Error
    附加小知识:

    1. null和undefined两者值相同,但是类型不相同。null是一种类型,代表空对象;undefined代表一个变量未初始化。
    2. Symbol和BigInt的介绍在文末

    值类型和引用类型区别

    1. 存储位置不同,值类型直接存储在栈中,引用类型的值存储在堆中,并把存储地址存储在栈中
    2. 值类型变量赋值时,改变其中一个另外一个不会发生变化
    let a = 20 
    let b = a 
    b = 30 
    console.log(a,b)
    
    • 1
    • 2
    • 3
    • 4
    1. 引用变量赋值时,只要改变其中一个两个都会发生变化
    let a = {
    	age = 10 
    }
    let b = a 
    b.age = 20 
    console.log(a.age,b.age)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    附加深拷贝浅拷贝(面试考点)
    浅拷贝:赋值的时候,一个值改变,另外一个也跟着改变是浅拷贝,也就是说将变量所指的引用地址直接赋值给另外一个变量,他们使用的是同一份资源。
    手写深拷贝

    var obj = {
        "name": "隔壁老王",
        "age": 23,
        "list": {
            "title": "新闻"
        },
        "child": {
            "child": "child"
        },
        "wife": undefined
    }
    //这里循环引用,引入map就是为了解决循环引用
    obj.obj = obj
    
    // 方法一:使用json形式
    console.log('test', JSON.parse(JSON.stringify(obj)))
    
    // 方法二
    function deepCopy(target, map = new WeakMap()) {
        if (typeof target === 'object') {
            let res = Array.isArray(target) ? [] : {}
            if (map.get(target)) {
                return map.get(target)
            }
            //这里先创建一个空地址
            map.set(target, res)
            for (let key in target) {
                if (target.hasOwnProperty(key) && target[key] != null) {
                	//这里就进行存储值了
                    res[key] = deepCopy(target[key], map)
                }
            }
            return res
        } else {
            //这里是出口,如果不是对象类型直接返回
            return target
        }
    }
    console.log(deepCopy(obj))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    Q:为什么要使用弱引用呢?
    主要是为了垃圾回收。后期补上
    附加一个小知识点:
    for…in常用于遍历对象,遍历的是对象的所有属性+对象原型上的所有属性
    hasOwnProperty()函数用于判断属性是否是实例对象,结果是一个布尔值,true说明是实例对象,false说明不是实例属性。in操作符会通过对象能够访问给定属性时返回true,无论属性存在实例中还是原型中。
    for…of 常用于遍历可迭代对象
    不同点时for…in可以操作任何对象,但是for…of必须是带有interator的对象。

    总结:以上的代码中考虑了object和array还有null类型

    获取数据类型

    常见的单词运算符: typeof、void、new、in、instanceof、delete
    常用的获取数据类型有:typeof、Object.prototype.toString.call()、instanceof
    typeof用来判断变量类型 其返回值为字符串类型,所有的值类型,能够判断引用类型(只能区分object和function)
    能够判断的类型有(7种):number、boolean、string、undefined、symbol、object、function

    typeof undefined //undefined 
    typeof null //object 
    typeof 'abc' //string
    typeof 123 //number 
    typeof [] //object 
    typeof {} //object 
    typeof true //boolean 
    typeof b // b没有明,但是还会显示undefined
    typeof Symbol //function 
    typeof Symbol(1) //symbol 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    更准确的类型判断方法

    Object.prototype.toString.call(2) // "[object Number]"
    Object.prototype.toString.call('hello') // "[object String]"
    Object.prototype.toString.call({hello:'hello'}) // "[object Object]"
    Object.prototype.toString.call([2,'hello']) // "[object Array]"
    Object.prototype.toString.call(true) // "[object Boolean]"
    Object.prototype.toString.call(() => {}) // "[object Function]"
    Object.prototype.toString.call(null) // "[object Null]"
    Object.prototype.toString.call(undefined) // "[object Undefined]"
    Object.prototype.toString.call(Symbol(2)) // "[object Symbol]"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    instanceof 方法 可以判断出null不是Object类型

    null instanceof Object  //false
    
    • 1

    判断对象的具体类型,判断实例是否属于某种类型
    instanceof的判断规则如何进行的。参考函数/原型链(面试考点)
    instanceof实现原理 参考函数/instanceof实现原理(面试考点)

    es6新增类型Symbol
    是一种新的数据类型,是独一无二的,是一种类似于字符串的数据类型。
    主要解决的是命令冲突问题,不能用来做运算。
    不能使用for…in遍历,但是可以使用Refect.ownKeys来获取对象的所有键名
    创建Symbol

    var s = Symbol()
    console.log(type s )  //symbol
    var s1 = Symbol("wo shi string")  //这个字符串参数就是标识出来这个Symbol干什么的,类似于注释的功能
    var  s2 = Symbol("wo shi string")
    console.log(s1==s2)   //结果为false
    var s3 = Symbol.for('han')     //此时,Symbol是一个对象,通过这种方式创建的Symbol可以通过参数字符串得到唯一的Symbol值
    var s4 = Symbol.for('han')
    console.log(s3===s4);   //结果为true
    可以检测上下文中是否已经存在使用该方法且相同参数创建的 symbol 值,如果存在则返回已经存在的值,如果不存在则新建。
    Symbol.keyFor(s4)  //结果为han,这个方法返回一个使用Symbol.for定义的Symbol类型值的key
    Symbol.keyFor(s2)   //undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    使用场景借鉴
    1.作为属性名 作为属性名时调用这个属性名

    
    let mySymbol = Symbol()
    let obj = {
        //第一种写法,作为属性名称
        [mySymbol]:"helloworld"
    }
    //第二种写法
    obj[mySymbol] = "helloworld"
    //第三种写法
    Object.defineProperty(obj,mySymbol,{value:"helloworld"})
    
    //获取用Symbol定义的属性名称   以上三种写法的结果都相同
    obj[mySymbol]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.消除魔法字符串

    
    const shapeType = {
        //发现triangle等于哪个值不重要,重要的是不和其他属性名称 冲突就可以
      triangle: Symbol()
    };
    实现一:
    function getArea(shape, options) {
      let area = 0;
      switch (shape) {
        case shapeType.triangle:
          area = .5 * options.width * options.height;
          break;
      }
      return area;
    }
    实现二:
    function getArea(shape ,option){
        let area= 0
        if(shapeType.triangle){
            area = .5 * options.width * options.height;
        }
        return area
    }
    
    getArea(shapeType.triangle, { width: 100, height: 100 });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    3.属性名遍历

    es10新增的BigInt
    本来number表示的最大数为2**53-1,现在BigInt可以表示任意大的整数
    两个注意点:第一不能使用Math对象进行计算 第二不能是Nunber类型数据直接计算,需要转换后使用
    let bignumber = BigInt(12222)
    typeof 1n === ‘bigint’; // true
    typeof BigInt(‘1’) === ‘bigint’; // true

  • 相关阅读:
    使用tinode架设自己的私有聊天服务
    SpringTask基础使用
    DAY 66 数据库缓存服务——NoSQL之Redis配置与优化
    小程序--本地存储API
    【数据结构】二叉树、堆
    FastAPI 快速入门
    FreeMarker
    成年期人类大脑功能网络的重叠模块组织
    leetcode每天5题-Day22
    微信开发者工具如何使用?使用注意事项
  • 原文地址:https://blog.csdn.net/weixin_44789333/article/details/126403528