JS知识点回顾(1)

var let const 区别

var

es5 之前只有var 会有声明提升问题 也就是声明会提前到它所在的作用域顶部 且允许重复声明 var 痛点:

  1. 变量声明提升 在声明前可以访问,不报错,值为undefined,违反编码直觉
  2. 缺乏块级作用域 if块和for循环中用var声明的变量会泄露到外部

let const

es6中用let const 来解决这两个问题

  1. 会和花括号{}形成块级作用域
  2. 不允许重复声明
  3. 声明前无法访问 声明前想要使用会抛出错误 当块级作用域中提前访问变量出现暂时性死区,即使外部有声明这个变量但是依旧无法访问
  4. 在全局作用域声明不会被挂载在window上但是var会

const 声明的原始类型无法修改值,但是声明的引用类型无法修改引用地址,比如说指向一个新的对象。可以修改内部的值,例如修改对象的值,或者数组的内容

const 声明的变量必须要有值

js中的数据类型

原始类型

在栈中直接存储数据的值 赋值是值的拷贝

引用类型

在堆中通过地址索引存放内容, 在栈中存放地址 赋值的地址的拷贝

js 复制代码
function modify(obj){
  obj.name = 'Modified'
  obj = {
    name:'new obj'
  }
}
let myObj ={ name:'old obj'}
modify(myObj)
console.log(myObj.name)

调用modify(myObj)的时候就就相当于让形参obj和myObj指向同一片地址 ,这时候修改obj.name myObj会受到牵连,obj = { name:'new obj' }这里是让obj指向另一片地址,也就是和myObj断开了连接,后续修改不相干了,因此最后输出Modified

===

引用类型的全等判断是比较地址 原始类型的全等判断是比较值

数据类型

js中数据类型分为两大类

  1. 原始类型 number string boolean null undefined bigint symbol
  2. 引用(对象)类型 array object function map set Date RegExp(正则)等等

typeof

typeof可以精准的判断所有原始类型除了null、 对引用类型只能判断function 除此之外都是object

typeof null 判断出来是object

在js中判断数据类型是通过类型标签来实现的,类型标签都是由二进制数构成 对象的类型标签是000 然后null的转为二进制是全0 因此被判断成object

那我们该怎么判断null呢? 用null === null

该如何判断引用类型

instance of 可以判断所有的引用类型,但是不能判断原始类型,他的原理是原型链 判断数组 Array.isArray()

通杀所有类型方式

Object.prototype.toString.call()

深浅拷贝

拷贝只针对引用类型

浅拷贝shallowCopy

创建一个新对象 复制原对象的第一层属性,如果是原始类型就复制值,如果是引用类型就复制引用地址

  1. object.assign({},originalObj)
  2. ...originalArray\],{...originalObj}

  3. object.create

深拷贝deepCopy

创建一个新对象 复制原对象的所有层级属性,新旧对象完全独立

  1. JSON.parse(JSON.stringify()) 会忽略undefined symbol function date对象变成字符串 有循环引用直接报错
  2. structuredClone() 最推荐这个
  3. 复杂场景 要拷贝函数用lodash.cloneDeep 库

手写深浅拷贝

js 复制代码
fucntion shallowClone(obj){
  if(obj === null || typeof obj !== 'object') return obj
  const copy = Array.isArray(obj)?[]:{}
   for(let key in obj){
    if(obj.hasOwnProperty(key)){
      copy[key] = obj[key]
    }
  }
  return copy
}

function deepClone(obj, cache = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj
  if (cache.has(obj)) return cache.get(obj) //如果是循环引用就直接返回值
  const copy = Array.isArray(obj) ? [] : {}
  cache.set(obj, copy) //避免循环引用
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepClone(obj[key], cache) //递归复制
    }
  }
  return copy
}

深拷贝要注意循环引用的情况

为什么要深拷贝?

避免修改副本时,污染原始数据 创建一份独立的数据快照

数组身上的方法

map

转换数组,创建新数组,保持原数组不变,返回新数组

filter

筛选数组,创建新数组,保持原数组不变,返回包含满足条件的元素的新数组

reduce

汇总累加数组 接受两个参数,一个回调函数,第二个参数是回调函数中的第一个参数,遍历数组,将每次返回的值作为下一次回调的第一个参数,进行累加

splice 和 slice

splice改变原数组,返回被删除的数组 接受三个参数 第一个是删除/增加的位置索引,第二个参数是删除的个数,第三个是增加的元素 slice不改变原数组,返回数组的浅拷贝片段,接受两个参数,第一个是起始位置是,第二个是结束位置

map 和 forEach 区别

  1. map 返回新数组 forEach 返回 undefined
  2. 如果要对数据进行转换就用 map forEach 用于执行无返回值的操作 比如说仅仅只要获取值
  3. map 可以链式调用 forEach 不可以

reduce 里面的 initialValue 提供与否的区别

如果给了这个参数就由这个参数开始累加,从数组的第一个元素开始遍历 index:0,如果不给的话初始值就默认是数组的第一个元素,然后从数组第二个元素开始遍历也就是 index:1

开始不给初始值对空数组会直接报错

修改原数组的方法

push pop shift unshift splice sort reverse

不修改原数组 返回新副本

map filter reduce slice concat

对象属性的遍历

对象属性

自有属性和原型链属性 可枚举属性和不可枚举属性 字符串属性和 symbol 属性

for in

遍历自有以及原型链上的可枚举字符串属性 因此必须搭配 hasOwnProperty 来使用,只拿自有属性来过滤原型链属性

Object.keys()

返回自有的可枚举字符串属性 官方的 for in + hasOwnProperty且效率更高 可以直接拿到干净的属性列表

Object.getOwnPropertyNames()

返回所有字符串属性

Object.getOwnPropertySymbols()

返回所有 Symbol 属性

Reflect.ownKeys()

返回所有属性 Reflect.ownKeys(obj) = Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj))

相关推荐
LuckySusu2 小时前
【js篇】Promise 解决了什么问题?—— 彻底告别“回调地狱”
前端·javascript
程序员海军2 小时前
如何让AI真正理解你的需求
前端·后端·aigc
passer9812 小时前
基于Vue的场景解决
前端·vue.js
yinke小琪2 小时前
说说Java 中 Object 类的常用的几个方法?详细的讲解一下
java·后端·面试
用户458203153172 小时前
CSS过渡(Transition)详解:创建平滑状态变化
前端·css
春秋半夏2 小时前
本地项目一键开启 HTTPS(mkcert + Vite / Vue 配置教程)
前端
沐怡旸2 小时前
【算法】【链表】328.奇偶链表--通俗讲解
算法·面试
沐怡旸2 小时前
【底层机制】std::weak_ptr解决的痛点?是什么?如何实现?如何正确用?
c++·面试
穿花云烛展2 小时前
实习日记2(与form表单的爱恨情仇1)
前端