前端开发必会的JS硬知识

495 阅读6分钟

本文简介

  • 前端三座大山是HTML、CSS、JS,而Javascript是前端最核心的部分。
  • 一般来说,完整的JavaScript=ECMAScript+DOM+BOM
  • 让我们进入JS的深入学习旅程吧

js数据类型

数据类型有哪些?有什么特点?

  • 最新的 ECMAScript 标准定义了8种数据类型:
  • 七种基本数据类型 「值类型」:
    1. 布尔值(Boolean),有2个值分别是:true 和 false.
    2. null , 一个表明 null 值的特殊关键字。JavaScript 是大小写敏感的,因此 null 与 Null、NULL或变体完全不同。
    3. undefined ,和 null 一样是一个特殊的关键字,undefined 表示变量未赋值时的属性。
    4. 数字(Number),整数或浮点数,例如:42 或者 3.14159。
    5. 任意精度的整数 (BigInt) ,可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。
    6. 字符串(String),字符串是一串表示文本值的字符序列,例如:"Howdy" 。
    7. 代表(Symbol) ( 在 ECMAScript 6 中新添加的类型)。一种实例是唯一且不可改变的数据类型。 补充:

      typeof Symbol() === 'symbol'; // true Symbol('key') !== Symbol('key'); // true Symbol('key') === Symbol('key'); // false

  • 一种引用类型「对象(Object)」 包括:Array Function Date

特点:

  1. 值类型的赋值,实际就是值的拷贝
  2. 引用类型的赋值,实际就是地址的拷贝

热身训练

请说出以下代码打印的结果

if (1 == true) 
    console.log(1)
if (1 === true)
     console.log(2)
if ([]) 
    console.log(3)
if ([] == []) 
    console.log(4)
if ([] === [])
    console.log(5)
if (undefined == null)
    console.log(6)
if ('' == null) 
    console.log(7)
if (NaN == NaN) 
    console.log(8)
  • 解析:undefined == null ?两者都是无效值。js规范规定,在比较相等性之前,undefined和null不能转化成其他类型的值,且undefined和null是相等的。
  • 解析:undefined === null ?两者不是同一数据类型。== 比较的是值, === 比较的是值和数据类型

    typeof undefined // undefined typeof null // object

  • 解析:'' == null ?
    • null: 该值声明的是一个空对象,没有指向任何的内存空间。
    • '':该字符串声明的是一个对象实例,该实例是一个长度为0的字符串
    • 拓展:str = '' 放在栈内存 str = String('') 指向堆内存
  • 解析:NaN == NaN ?
    • NaN属性(not a number)是代表非数字值的特殊值。
    • 任何值和NaN做比较都是false。
    • 任何数和NaN做运算,结果都为NaN。
    • NaN不和任何值相等,包括它本身

    console.log(isNaN(NaN)) //true console.log(isNaN(10)) //false console.log(isNaN('20')) //false 将'20'转为数字类型20 console.log(isNaN('abc')) //true console.log(isNaN(true)) //false 将true转为1

浅拷贝与深拷贝

  • 浅拷贝:增加了一个指针指向已存在的内存地址
  • 深拷贝:增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存
  • 举个栗子🌰

    const a = [1,2,3]; const b = a; b[0] = 5;
    a = ? // [5, 2, 3]

  1. 这是浅拷贝,因为a和b指向同一块内存地址。当a赋值给b时, 只是将a的数据指针赋值给b,并没有开辟属于b的内存空间。
  2. 如果是深拷贝,应该为b开辟独立的内存空间,并且将a的内容拷贝过来。两者互不影响。

深拷贝的实现

let obj = {
    name: 'kk',
    bf: ['a', 1],
    a() {
        console.log('d')
    },
    offer: null
}
function deepClone(origin, target={}) {
    const toStr = Object.prototype.toString,
         arrStr = "[object Array]"
    for(let prop in origin) {
        if(origin.hasOwnProperty(prop)) {
            if(origin[prop] !== null && typeof origin[prop] === 'object') {
                target[prop] = toStr.call(origin[prop]) === arrStr ? [] : {}
                deepClone(origin[prop], target[prop])
            } else {
                target[prop] = origin[prop]
            }
        }
    }
    return target
}

let ans = deepClone(obj)
ans.offer = 'xxx'
console.log(ans, obj)

typeof 和 instanceof 的区别

  1. typeof用于判断变量的类型
  • 数值类型 typeof 2 返回 number
  • 字符串类型 typeof 'ac' 返回 string
  • 布尔类型 typeof true 返回 boolean
  • 对象、数组、null, 返回 object
  • 函数 typeof eval 、typeof Date 返回 function
  • 不存在的变量、函数或者undefined, 返回 undefined
  1. instanceof判断某个对象是否被某个函数构造

区别:

  • typeof采用引用类型存储值时出现问题,无论引用的是什么类型的对象,都会返回object
  • es引入java的instaceof解决问题
  • instanceof与typeof相似,用于识别正在处理的对象类型。
  • 不同的是,instaceof要求开发者明确地确认对象为某特定类型

== 和 === 有什么区别?

  • ==只判断值是否相等
  • ===判断值是否相等,类型是否相同

数组、对象那些事

判断数组类型的方法

  1. Array.isArray(arr) => true
  2. Object.prototype.toString.call(arr) => "[object Array]"
  3. arr instanceof Array => true
  4. arr.constructor == Array => true **instanceof和constructor,必须在当前页面声明。如果是父页面引入iframe,也判断不出来**

函数中的 arguments 是数组吗?

  • arguments是类数组,原型(proto)指向的是Object;而真正数组指向Array。
  • document.getElementByTagName 返回的也是类数组,原型指向HTMLCollection.

如何将函数中的arguments转化为真正的数组?

  • Array.from(arguments)
  • [].slice.call(arguments)
  • 扩展运算符(当数组或者对象只有一层的时候,意思是不存在数组嵌套对象,或者嵌套数组这种情况,拷贝是深拷贝。除了第一层是深拷贝,其它层都是浅拷贝) [...arguments]
  • [].concat.apply([],arguments)
  • Array.of(...arguments)
  • Array(...arguments)

Array的forEach等用法

  1. forEach:遍历数组(for)
  2. map: 返回一个数组,不改变原数组的内容
  3. every:每个元素都符合条件,就返回true

    arr.every((val, index, array)=>val=='a')

  4. some: 只要有一个元素符合条件,就返回true

    arr.some((val, index, array)=>val=='a')

  5. filter: 返回一个数组,里面都是符合条件的元素。

    arr.filter((val, index, array)=>val=='a')

  6. reduce: 返回一个数 可进行递归、叠加、阶乘,从左到右 (reduceRight 从右到左)

    arr.reduce((prev,cur,index,arr)=>{ // 加法 // return prev+cur // 阶乘 // return Math.pow(prev,cur) return prev**cur })

如何遍历一个对象?

  • for(let prop in obj)
  • object.keys(obj); object.values(obj)
  • object.getOwnPropertyNames(obj)

闭包与作用域

闭包就是能够读取其他函数内部变量的函数

请实现一个“有缓存功能”的加法

let add = (()=>{
    let sum = 0
    return  n=>sum += n
})()
console.log(add(5), add(6), add(1))

什么是作用域?细分为哪些作用域?

浏览器给js的生存环境叫作用域。

  • 函数作用域
    • 在函数调用的时候,会创建函数作用域。调用完会摧毁
    • 每一次调用函数都会创建一个函数作用域,并且相互独立
    • 函数作用域可以访问全局作用域的变量,全局作用域不可以访问函数作用域的变量
    • 函数内访问变量,会从自身函数作用域内找,找不到就往上一级作用域找,直到找到全局作用域。如果还是找不到,就返回ReferenceError
    • 在函数作用域内要访问全局变量,可以使用window
  • 全局作用域
  • 块级作用域(下一栏目)

let、const、var的区别?

  1. 什么时候提出?
  • var是es5提出的,let、const是es6提出的
  1. 变量提升
  • var能够进行变量提升,let、const不可以
  1. 暂时性死区(TDZ)
  • 在块级作用域内,let、const具有暂时死区,一进入作用域内,变量就已经存在,但是在变量声明前不能被访问或者调用,否则会报错 ReferenceError
  1. 重复声明
  • var可以重复声明
  • let、const不可以
  1. 是否存在块级作用域
  • var不存在(1、内部变量可能会覆盖外部变量2、用于计数的循环变量泄露为全局变量)
  • let、const存在
  1. 声明的变量能否被修改
  • var和let可以 const不可以,一旦声明必须立即初始化

更多精彩内容,请关注公众号。

前端交流群(群里大佬如云,会经常分享优秀的文章,前端路上,结伴同行~)