Menu

js知识总结—基础知识篇

1.js判断变量类型

  1. typeof可以判断一般类型。但无法准确识别对象。所有对象或类对象类型(null)都为”object”,比如数组typeof [] == "object"。JS数据类型在底层都是以二进制的形式表示的,二进制的前三位为 0 会被 typeof 判断为对象类型,而 null 的二进制位恰好都是 0 ,因此,null 被误判断为 Object 类型。
  2. typeof 与其他条件组合判断:typeof arr=="object" && !!arr.push
  3. instanceof可以判断具体对象类型。用来判断对象是否为某个构造函数的实例。[] instanceof Array==true
  4. Object.prototype.toString.call()可以判断任意变量类型。Object.prototype.toString.call([])=="[object Array]"
  5. .constructor.name可以判断变量类型(nullundefined除外)。true.constructor.name=="Boolean"
  6. 判断数组也可以用Array.isArray(arr)方法

2.数组常用方法

  1. pop()尾部删除,返回尾部元素,会改变原数组
  2. push()尾部插入,会改变原数组
  3. unshift()头部插入,会改变原数组
  4. shift()头部删除 ,这两个别搞混。返回头部元素,会改变原数组
  5. join()把数组元素放入字符串,使用指定的分隔符进行分割
  6. reverse()倒序数组元素顺序,返回倒序后的新数组。会改变原数组
  7. splice()删除元素,并向数组添加新元素。会改变原数组
  8. sort()对数组对象进行排序—字符串排序按每一个英文字母先后/数字排序按字符串处理(实际上是每一位的排序),会改变原数组
  9. slice()从开始和结束位置截取数组中的元素返回新数组
  10. concat()连接(合并)两个数组
  11. arr.length=0 清空数组
  12. map()/find()/filter()/reduce()/forEach()/some()/every():ES6数组新方法。(every:一假即假,some:一真即真)

3.数组去重

  1. indexOf/includes循环去重:申明一个新新数组,判断新数组中是否包含当前项,若没有,则push
  2. ES6 Set对象去重:Array.from(new Set(arr))
  3. Object键值对去重:把数组的值存为key,判断obj[arr[i]]是否存在,若存在则重复。
  4. 利用ES6的数组reduce方法(第二个参数[]为初始值):arr.reduce((unique,item) =>unique.includes(item)?unique:[...unique,item], []);

4.去除字符串首尾空格

  1. str.trim()
  2. 正则:str.replace(/(^\s*)|(\s*$)/g,"")

5.requestAnimationFrame

requestAnimationFrame()方法用于代替使用定时器开发的动画。此方法的回调函数会在浏览器重绘之前调用。此方法的执行频率与显示器的刷新频率相关。回调函数执行次数通常是每秒60次,但在大多数浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。为了提高性能和电池寿命,因此在大多数浏览器里,当requestAnimationFrame() 运行在后台标签页或者隐藏的<iframe> 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命。

大部分显示器的刷新频率为每秒60次,也就是每次刷新间隔为16.7ms,我们在渲染动画时只有每一帧间隔时间<=16.7ms才能让用户觉得不卡顿。

6.引用类型常见有哪些对象

Object、Array、RegExp、Date、Function、Math、String、Number、Boolean

7.对象深拷贝、浅拷贝

对象引用:只引用对象,没有真正的复制。只复制引用(内存地址指向/栈内存),没有复制真正的值(堆内存),对其进行修改会影响原对象。

浅拷贝:只复制一层对象的属性。如果对象还有嵌套对象,则无法复制。如Object.assign()

深拷贝:复制了对象真正的值。对其任何操作都不会影响被拷贝的对象。

实现浅拷贝:

  1. 扩展运算符
  2. Object.assign
  3. 数组通过slice()的方法
let a = {
    age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1

//-------------------------------------------

let a = {
    age: 1
}
let c = {...a}
c.age = 2
console.log(a.age) // 1

实现深拷贝:

  1. 递归浅拷贝(可行)。
  2. 深度遍历对象,递归嵌套对象,将其键值对赋值给另外一个新创建的对象,但性能堪忧。
  3. 使用JSON反序列化和序列化,性能最快JSON.parse(JSON.stringify(oldObj))(缺点:只能深拷贝对象和数组,会忽略undefined和symbol,不能序列化函数,不能序列化循环引用的对象)
  4. 第三方库如 jQuery.extend
  5. ProxyObject.defineProperty来拦截 set 和 get 就能阻止拷贝对象修改原对象(性能高,无缺点),深拷贝点此参考

注意:数组的slice方法和concat方法无法进行深拷贝,只能浅拷贝。因为嵌套对象或数组会被引用。对象的Object.assign()方法同样如此。

8.判断两个对象是否相等

"a==b"或者Object.is(a,b)可以判断两个对象是否相等,但仅限于两个对象引用相同,是同一个对象。深浅拷贝对象无法判断。

若要判断两个不同引用的对象是否相等,得通过深度遍历及递归方法(递归时判断值是否是Object)进行值的判断(遍历及递归之前先通过Object.getOwnPropertyNames拿到两个对象的所有键名,比较键名是否相等)。

这时候不能用JSON.stringify()方法去比对对象,因为序列化之后,键是有序的,无法比较。

9.js变量类型

基本类型有六种nullundefinedbooleannumberstringsymbol

其中 JS 的数字类型是浮点类型的,没有整型。NaN 也属于 number 类型,并且 NaN 不等于自身。对于基本类型来说,如果使用字面量的方式,那么这个变量只是个字面量,只有在必要的时候才会转换为对应的类型。

typeof 对于基本类型,除了 null 是object,其他都可以显示正确的类型。(在 JS 的最初版本中,使用的是 32 位系统,为了性能考虑使用低位存储了变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object

引用类型:objectfunctionarraymapset

引用类型在使用过程中会遇到浅拷贝和深拷贝的问题。typeof 对于引用类型,除了函数都会显示 object

10.隐式类型转换

使用if条件判断或使用==/&&/||等运算符时会对变量进行隐式类型转换。

隐式类型转换时,除了 undefined, null, false, NaN, '', 0, -0[],其他所有值都转为 true,包括所有对象(这里注意空数组会被转为false)。

对象在隐式类型转换时,首先会调用其原型上的 valueOf 方法或 toString方法。valueOf 优先于toString。并且这两个方法你是可以重写的。

let a = {
  valueOf() {
    return 0;
  },
  toString() {
    return '1';
  },
}
1 + a // => 1
'1' + a // => '10'

//-------------------

let a = {
  toString() {
    return '1';
  },
}
1 + a // => '11'
'1' + a // =>  '11'

只有当加法运算时,其中一方是字符串类型,就会把另一个也转为字符串类型。其他运算只要其中一方是数字,那么另一方就转为数字。并且加法运算会触发三种类型转换:将值转换为原始值,转换为数字,转换为字符串。

1 + '1' // '11'
2 * '2' // 4
[1, 2] + [2, 1] // '1,22,1'
// [1, 2].toString() -> '1,2'
// [2, 1].toString() -> '2,1'
// '1,2' + '2,1' = '1,22,1'

对于加号需要注意这个表达式 'a' + + 'b'

'a' + + 'b' // -> "aNaN"
// 因为 + 'b' -> NaN
// 你也许在一些代码中看到过 + '1' -> 1

console.log(+'1') // 1
console.log(-'1') // -1
console.log(+'a') // NaN
console.log(-'a') // NaN

console.log(+'') // 0
console.log(+[]) // 0
console.log(+true) // 1
console.log(+false) // 0
console.log(-true) // -1
console.log(-false) // -0
console.log(-false) // -0
console.log(-[]) // -0
console.log(-'') // -0
console.log(+[123]) // 123
console.log(+['123']) // 123
console.log(+[true]) // NaN
console.log(+[123,1]) // NaN

// 'a' + + 'b'  等同于 'a' + (+'b') 等同于  'a' + NaN
console.log('a' + (+'b'))  // "aNaN"
console.log( 'a' + NaN)  // "aNaN"

空数组会被转为false

[] == ![] // -> true
[]==false //true

11.++运算

++在前,返回值是新值

++在后,返回值是旧值

var a = -1
if(++a){ // 这里++a的值为新值0
  console.log(666)
}else{
  console.log(888)
}
// 结果为888

// ---------------------------------------

var a = -1
if(a++){ // 这里a++的值为旧值-1
  console.log(666)
}else{
  console.log(888)
}
// 结果为666

本文固定连接:https://code.zuifengyun.com/2020/03/1963.html,转载须征得作者授权。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

¥ 打赏支持