前端重点梳理(二):JS 基础

94 阅读3分钟

JS 数据类型


8种基本数据类型(值类型): String、Number、Boolean、Null、undefined、BigInt、Symbol

  • Symbol:代表独一无二的值,最大的用法是用来定义对象的唯一属性名。
  • BigInt:可以表示任意大小的整数。

引用数据类型: Object、Array、Function

值类型和引用类型的区别: 值类型存在栈里,引用类型存在堆里

typeof 对类型的判断:

  • 可以判断所有值类型和 Function
  • Object、Array、null 都会被识别为 Object 类型

判断数组的方法:

  1. isArray
  2. instanceof Array
  3. arr.constructor === Array

=== 和 ==:

  • === :全等
  • == 会进行类型转换尽量使两边相等,一般只有在判断 null 和 undefined 时才会使用 ==
  • 在进行计算时数据需要先转换为二进制,因此可能会丢失精度

手写深拷贝:

function deepClone(obj) {
    if(obj === null || typeof obj !== Object) return obj
    
    let newObj = obj.isArray ? []:{}
    for(let key in obj){
        // 确保key不是原型的属性
        if(obj.hasOwnProperty(key)){
            newObj[key] = deepClone(obj[key])
        }
    }
    
    return newObj;
}

原型和原型链


原型:

  1. 每个构造函数都有一个显式原型 prototype
  2. 每个实例对象都有一个隐式原型 _ _ proto _ _
  3. 实例对象的_ _ proto _ _指向其构造函数的 prototype
  4. 每个构造函数的 prototype 有一个_ _ proto _ _指向其父类的 prototype
  5. 构造函数的 prototype 的 constructor 指向构造函数本身

原型链:

  1. 实例调用方法时,先在自身寻找
  2. 找不到就通过实例的_ _ proto _ _去其构造函数的prototype上寻找
  3. 找不到再通过构造函数prototype的_ _ proto _ _去其构造函数的prototype上寻找
  • 可以通过对象的 hasOwnProperty 方法判断要调用的方法是否是实例对象自身的方法

new的实现过程:

  1. 先创建一个空对象
  2. 使该对象的_ _ proto _ _指向构造函数的prototype
  3. 让函数的this指向该对象,并执行构造函数代码为对象添加属性
  4. 返回值:如果构造函数的返回值是一个对象,直接返回这个对象,否则返回新创建的对象

instanceof 的作用:

  • 用于判断对象是否是某个构造函数的实例,只要在原型链上就为 true
  • 可以用于判断一个对象是否为数组: obj instanceof Array

作用域和闭包


作用域类型:全局作用域、函数作用域、块级作用域(es6新增)

作用域链:

  1. 如果当前作用域内使用了未定义的变量,则该变量为自由变量
  2. 从当前函数定义位置向外逐层寻找该变量的定义
  3. 如果到到全局作用域仍未找到则该变量为 undefine

闭包: 函数调用的位置跟函数定义的位置不一样

  • 形成条件:函数作为参数或返回值
  • 实质:从函数定义位置向外寻找自由变量

变量提升:

  1. JS预解析把所有 var 变量声明和 函数声明提升到当前作用域最前面
  2. 变量提升只提升声明,不提升赋值(初始化)
  3. 函数表达式声明属于变量提升
  4. 函数提升只提升声明,不提升调用
改变函数this指向:
  1. call:函数会立即执行
  2. apply:函数会立即执行,接收的函数参数为数组形式
  3. bind:接收的函数参数为数组形式,函数不会立即执行,而是返回改绑后的新函数,便于稍后调用

手写bind实现:

Function.prototypr.myBind = function(obj) {
    var self = this  //原函数this
    var args1 = Array.protptype.slice.call(arguments, 1)    //arguments是伪数组
    var fun1 = function() {
        var args2 = Array.prototype.slice.call(arguments)
        self.apply(context, args.concat(newArgs))  //合并两args
    }
}
数组和字符串常用方法:
for...in 和 for...of :
  • for...in:用于遍历对象或数组的 key,主要用于对象
  • for...of:用于遍历数组项 item

手写数组去重:

let newArr = [Array.from(new Set(arr))]  //利用Set数据结构

手写数组扁平化:

//第一种
arr.flat()

//第二种
function flatten(arr) {
    return arr.reduce((flatArr, item)=>{
        Array.isArray(item)? flatArr.push(...flatten(item)) : flatArr.push(item)
        return flatArr
    }, [])
}