关于JS小知识点

121 阅读5分钟

1.可选链运算符(?.)

  • 允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效;
  • ?. 运算符的功能类似于 . 链式运算符,不同之处在于,可选链运算符会在链路上遇到 null 或者 undefined 时,直接返回 undefined,而不会抛出错误异常;
  • 与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。MDN

2.空值合并运算符(??)

  • 当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数;
  • 逻辑或运算符(||)不同,逻辑或运算符会在左侧操作数为假值时返回右侧操作数。

3.为什么 JS 对象内部属性遍历的顺序乱了

  • 对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定,所以对象(Object)没有默认部署 Iterator 接口,所以不会被for...of循环遍历;
  • 首先JS代码本身是不会直接被计算机执行,计算机只能接收二进制的汇编代码,所以,中间需要一层转化,而这个转化,在Chrome就是v8引擎;
  • Chrome 的 JS 引擎遍历对象属性时,会先提取所有 key 的 parseFloat 值为非负整数的属性,再根据数字顺序对属性排序首先遍历出来,然后按照对象定义的顺序遍历余下的所有属性。
let obj = {
    'b': 'testb',
    'a': 'testa',
    '2': 'test1',
    '测': 'test测',
    '1': 'test2'
}
console.log(Object.keys(obj));
// [1, 2, 'b', 'a', '测']
  • Chrome有这样的表现是因为V8引擎为了提高对象的访问速度,V8 里的对象就维护两个属性,会把数字放入线性的 elements 属性中,并按照顺序存放。会把非数字的属性放入 properties 中,不会排序,寻找属性时先 elements 而后在 properties。 image.png

4.枚举属性和可迭代属性

  • 枚举属性:指将对象中的所有的属性全部获取,for..in用来遍历可枚举属性。
let obj = {
    name: "艾斯",
    age: 8,
    sex: "男",
    address: "五指山",
    [Symbol()]: "test", // Symbol添加的属性不能被枚举
    [name]: 'chris' 
}
for(let proName in obj) {
    console.log(proName, obj[proName]) // 因为proName是个变量,变量里面存的属性名,传变量不能用" . "的形式,得用中括号获取属性值
}
  • 可迭代属性:for..of用来遍历可迭代属性
const arr = ['孙悟空', '沙僧', '猪八戒', '唐僧'];
for(let value of arr) {
    console.log(value)
}

5.Set和WeakSet的区别

  • Set在其他语言中又叫集合,是一堆无序的、相关联的、不重复的内存结构的组合,集合中的元素可以是任意类型,键名与键值一致,或者说只有键值,没有键名。
  • WeakSet中的元素只能是对象,不能是其他类型的值。WeakSet是弱引用(弱引用是指不能确保其引用的对象不会被垃圾回收器回收的引用),如果该对象不再被其他变量引用,那么垃圾回收机制就会自动回收该对象的内存,由于垃圾回收机制运行机制是不确定的,所以WeakSet是不可遍历的。

【强引用:把一个对象赋给一个引用变量,这个引用变量就是一个强引用,类似var obj = new Object(),当一个对象被强引用变量引用时,它处于可达状态,是不可能被垃圾回收器回收的,即使该对象永远不会被用到也不会被回收。】

6.Map和WeakMap的区别

  • Map类似对象,也是键值对的集合,对象的键只能是字符串,Map的键可以是任意类型。
  • WeakMap只接受对象作为键名(不包括null),键名所指向的对象,不计入垃圾回收机制(同WeakSet)

7.立即执行函数(IIFE)

立即执行函数是一个匿名的函数,并且只会调用一次;可以利用IIFE创建一个一次性的函数,避免变量冲突。

image.png js解析成(...)(...)这样的结构,由于括号有计算优先级,还是函数调用的一种方式;这里把前一个当成函数去调用,所以报错。所以在前一个立即执行函数后面加上“ ; ”,这样就可以规避这样问题,虽然js解析器会自动尝试在合适位置补上分号,但有时也会出现问题。(这里js解析器在第二个IIFE后面加“ ; ”所以说别偷懒,分号好好加)

image.png

在实际开发中应尽量减少在全局作用中编写代码,防止被意外修改,尽量编写局部作用域,可以使用let创建代码块,也可用IIFE创建作用域

8.变量的可变类型和不可变类型

可变类型和不可变类型

  • 简单数据类型属于不可变类型,一旦创建不可更改;在内存中不会创建重复的原始值;
  • 复杂数据类型属于可变类型,对象创建完成后,可以任意的添加删除修改对象中的属性;
    • 如果有两个变量同时指向一个对象,对另外一个变量也会产生影响。
    • 当对两个对象进行全等或相等比较时,返回false,比较的内存地址。 修改对象时,如果有其他变量指向该对象,则所有其他指向该对象的变量都会受到影响;修改变量时,只会影响当前的变量。
      const只能赋值一次,只是禁止变量被重新赋值,对对象的修改没有影响。

9.Object.hasOwn()

指定的对象自身有指定的属性,则静态方法 Object.hasOwn()  返回 true。如果属性是继承的或者不存在,该方法返回 false。 【Object.hasOwn() 旨在取代 Object.hasOwnProperty()】

  • hasOwn(instance, prop):instance要测试的 JavaScript 实例对象;prop要测试属性的 String 类型的名称或者 Symbol