ES5及ES6

128 阅读9分钟

ES5及ES6

概述

ES(全称ECMAScript ECMA是一个组织名( 欧洲计算机协会),script指代脚本)。利用babel.js的第三方库可以完成ECMAScript的版本转换。它是JavaScript的基础语法支持(除bom,dom相关内容都是es的内容)。

JavaScript的组成
  • DOM (操作HTML文档)
  • BOM (操作浏览器的)
  • ECMAScript (基础语法)
ECMAScript版本
  • ES3 基础内容(基础一些对象及方法 兼容大部分低版本浏览器)
  • ES5 进阶内容 (在es3新增对应的方法及特性 兼容大部分的浏览器 ES5诞生于2009年)
  • ES6 加强内容 (在es5的基础上新增内容及特性 把es6以后都称为es6 兼容部分的浏览器(最新浏览器版本支持) ES5诞生于2015年)

ES5新增特性

es5主要对于es3的内容进行增强,主要增强有对象、数组、严格模式、相关高阶函数等。

严格模式

严格模式是es5的一个新特性,它可以提高代码的执行效率,它对于相关的内容进行了规范(规范性更高 执行效率更快)(普通的写法被称为怪异模式),它使用 use strict 进行声明。

严格模式具备的特性
  • 严格模式通过抛出错误来消除了一些原有静默错误。
  • 严格模式修复了一些导致 JavaScript 引擎难以执行优化的缺陷:有时候,相同的代码,严格模式可以比非严格模式下运行得更快。
  • 严格模式禁用了在 ECMAScript 的未来版本中可能会定义的一些语法。
相关内容
  • 声明变量必须使用var关键词
"use strict"
b = 20 //声明变量必须使用var关键词 
  • 函数内的this指向不能指向window (如果指向window值就为undefined)
function fn(){
    console.log(this)
}
fn() //undefined
  • 函数的声明只能在对应的上下文内声明
//函数的声明只能在上下文对象内容声明 只能声明在函数中或者是全局
if (function () {
    return true //语法错误
}()) {
    console.log('你好')
}
if (true) {
    function f() {} // !!! 语法错误
    f();
}
  • 禁止八进制
//八进制使用0开头
var n = 012  //禁止八进制
  • 函数内的形参名不能重复,及对象内的属性也不可重名
//函数的内的形参不能重名
function fn1(n,n){
    console.log(n)
}
fn1(1,2) //形参不能重名
var obj = {name:'jack',name:'rose'} //属性不能重名
  • arguments中的callee无法访问对应的函数相关内容
function fn2(a,b){
    console.log(arguments.callee) //arguments.callee 无法访问对应的调用的函数
}
fn2(1,2)
  • 无法删除对象自带的属性及声明的变量
var arr = []
delete arr.length  //无法删除本身自带的属性
var x = 10
delete x //报错
  • arguments中的形参和实参不同步
function f(a) {
    "use strict";
    a = 42;
    return [a, arguments[0]];
}
var pair = f(17); 
console.log(pair) //[42,17]

数组的高阶函数

  • forEach 遍历无返回值

  • map 遍历有返回值(返回值的长度和对应的遍历的数组长度一致)

  • filter 过滤的(根据传入条件返回满足条件的内容 返回的是一个新的数组)

  • reduce 计算的 (传入对应的计算方式返回结果(如果传入了初始值那么从下标0开始 没有传入从下标1开始))

  • reduceRight 计算的 (跟reduce一致 计算方向为从右到左 从后面算起)

  • some 判断是否有满足条件的内容 (有返回true 没有返回false)

  • every 判断是否全部都满足条件 (都满足返回true 否则返回false)

注意事项
  • 数组的高阶函数都会忽略对应的空值(empty)
  • forEach常用于要更改原本数组的情况下 map用于无需更改原本数组且需要一个新的数组的时候
  • reduce 方法传入对应的初始值是从下标0开始 未传入是从下标1开始
  • some和every它的执行次和返回的值相关 如果some里面有返回true的值 后面的都不执行 every里面有返回false值 后面的都不执行了
手写源码实现高阶函数
forEach实现
//forEach 和 map
//传入对应的函数及一个数组
function myForEach(callbackFn, arr) {
    //判断callbackFn是否为函数
    if (typeof callbackFn != "function") {
        throw new Error(`${arguments[0]} is not a function`)
    }
    //遍历数组
    for (var i = 0; i < arr.length; i++) {
        //跳过empty   in 关键词 判断属性是否存在
        if (i in arr) {
            //调用callBackFn
            callbackFn(arr[i], i, arr)
        }
    }
}
map实现
//传入及对应的函数及对应的一个数组
function myMap(callbackFn, arr) {
    //判断callbackFn是否为函数
    if (typeof callbackFn != "function") {
        throw new Error(`${arguments[0]} is not a function`)
    }
    //准备一个新的数组来接收结果 返回的数组长度==数组原本的长度
    var result = new Array(arr.length)
    //遍历数组
    for (var i = 0; i < arr.length; i++) {
        //跳过empty   in 关键词 判断属性是否存在
        if (i in arr) {
            //调用callBackFn
            result[i] = callbackFn(arr[i], i, arr)
        }
    }
    return result
}
reduce实现
//手写源码
//传入函数  传入初始值
function myReduce(callbackFn, initValue) {
    //判断callbackFn是否为函数
    if (typeof callbackFn != "function") {
        throw new Error(`${arguments[0]} is not a function`)
    }
    //默认为开始下标为0
    var startIndex = 0
    //判断是否传入了initValue
    if (arguments.length < 2) { //初始值没有被传递
        var values = Object.values(arr) // Object.values 用于获取传入对象的所有值
        // 没有初始值 如果arr里面的内容都empty 报错
        if (values.length == 0) {
            throw new Error("计算空的数组没有传入初始值")
        }
        // 如果没有指定初始值 那么对应的第一个找到的值就是初始值
        initValue = values[0]
        startIndex = arr.indexOf(values[1])
    }
    //遍历
    for (; startIndex < arr.length; startIndex++) {
        if (startIndex in arr) {
            //将上一次的结果作为这一次的初始值
            initValue = callbackFn(initValue, arr[startIndex], startIndex, arr)
        }
    }
    return initValue
}
filter实现
function myFitler(callbackFn){
	//判断callbackFn是否为函数
    if (typeof callbackFn != "function") {
        throw new Error(`${arguments[0]} is not a function`)
    }
    var result = []
    //遍历
    for(var i=0;i<arr.length;i++){
        if(i in arr){
           //如果条件满足
           if(callbackFn(arr[i],i,arr)){
               //将内容添加
               result.push(arr[i])
           }
        }
    }
    return result
}
some实现
function mySome(callbackFn){
	//判断callbackFn是否为函数
    if (typeof callbackFn != "function") {
        throw new Error(`${arguments[0]} is not a function`)
    }
    for(var i=0;i<arr.length;i++){
         if(i in arr){
             if(callbackFn(arr[i],i,arr)){
                  return true
             }
         }
    }
    return false
}
every 实现
function myEvery(callbackFn){
	//判断callbackFn是否为函数
    if (typeof callbackFn != "function") {
        throw new Error(`${arguments[0]} is not a function`)
    }
    for(var i=0;i<arr.length;i++){
         if(i in arr){
            if(!callbackFn(arr[i],i,arr)){
                  return true
             }
         }
    }
    return true
}

字符串的字符串模板

//var str = `${可以解析js代码}`
var str = `${1+2+3}天` //6天

对象的get set方法

  • get是用于获取数据的 里面返回的值就是得到的数据
  • set是用于设置数据的
//对象的新增get set特性 它是用于获取和设置对应的属性的
var obj = {
    _name: '',
    get name() { //当你获取name属性的时候就会调用的这个方法 里面的返回值就是你拿到的值
        console.log('get调用了')
        //里面是不能返回本身的name的 如果访问this.name 那么就是会调用get方法 导致内存溢出
        //要是第三方的属性
        return this._name
    },
    set name(value) { //当你设置name属性的时候就会调用的这个方法 参数为你设置的值
        console.log('set调用了', value)
        this._name = value
    }
}
console.log(obj.name) //调用get方法
obj.name = 'jack' //调用set方法
console.log(obj.name) //调用get方法

利用set get更改数据 驱动视图变化

//改变对应div的宽度
var widthObj = {
    _width:0,
    set width(value){
        this._width = value
        //更改对应的宽度
        document.querySelector('div').style.width = value + 'px'
    },
    get width(){
        return this._width
    }
}
var time = setInterval(function(){
    widthObj.width ++ //不断增大宽度
    if(widthObj.width > 100){ //当宽度大于100 清除定时器
        clearInterval(time)
    }
})
注意事项
  • 不要在get或set方法中使用本身的这个属性,造成内存泄漏。
  • 如果只有get没有set那么对应的属性就是只读属性(无法赋值)

更改函数中this指向的方法

Function的方法
  • bind 返回一个新的函数

    //函数对象的方法
    function fn(){
    console.log(this,arguments)
    }
    fn() //打印window
    //绑定一个this 返回一个新的函数
    //传递参数为this的指向 函数需要传递的参数(传递多个)
    var newFn = fn.bind({name:'jack'},'你好','世界')
    fn() //原本的函数没有发生变化
    newFn() //新的函数的this指向 {name:'jack'}
    
  • call 更改this指向执行当前函数

    //call 传入的对应的this指向  传递函数需要的参数 (传递多个)
    fn.call('call的指向','hello','world')
    
  • apply 更改this指向执行当前函数

    //apply方法  传入的对应的this指向 传入需要的参数数组
    fn.apply('apply的指向',['世界','你好'])
    
区别
  • bind 方法返回一个函数不会自动调用 需要手动调用 而call及apply会自动调用
  • call传递的是一个个的参数 apply传递是一个参数数组
  • call 及apply 不会更改bind返回的函数的this指向

以及部分的方法

  • 字符串的trim
  • 数组的indexOf 及 lastIndexOf等
  • JSON的俩个序列化及反序列化方法 JSON.stringify JSON.parse
  • Objet类中的大部分方法
  • Array.isArray 判断是否类型为数组
  • .....

ES6新增内容

主要在es5的基础,对于对象、数组、变量修饰符、字符串、循环、函数.....进行了增强。

ES3的值类型

string、number、boolean、undefined、null

新增基础值类型

Symbol 独一无二的值
// Symbol 是独一无二的值 底层实现是机器码
var symbol = Symbol('描述信息')
console.log(symbol)
//获取描述
console.log(symbol.description) //描述信息
console.log(Symbol('我是描述') == Symbol('我是描述'))//false
//symbol 常用于对象的key 一般是底层支持
function fn(){
    console.log(arguments)
}
fn()
var obj = {}
obj[Symbol('描述')] = 10
console.log( obj[Symbol('描述')]) //undefined
//获取所有symbol的属性
var s = Object.getOwnPropertySymbols(obj)[0]
console.log(obj[s])
//symbol不能用于计算 无法转为number
// console.log(symbol + 1) 
BigInt 大整型
//BigInt是为了容纳较大的整数值而诞生
var bigInt = BigInt(Number.MAX_VALUE)  //后面显示带个n是BigInt
console.log(bigInt)
console.log(Number.MAX_VALUE)
console.log(BigInt(1) + BigInt(1)) //2n
// console.log(Symbol(1) + Symbol(1)) 报错
// console.log(BigInt(1) + 1) //报错
console.log(BigInt(1) + '1') // 11
console.log(BigInt(1).toString()) //1
console.log(bigInt.toLocaleString())

新增变量声明修饰符

let 块级作用域
let 变量 = 值
  • let 不能在同一块级作用域内重复声明
  • let 不会进行预编译 (变量提升)
  • let 具备块级作用域
const 块级作用域的常量
const 变量 = 值
  • const 声明必须赋值
  • const 修饰的常量地址不可变
  • const 不会进行预编译 (变量提升)
  • const 声明的常量不能二次赋值
  • const 具备块级作用域

面试题 let 、var 、const

数组增强

相关增强方法
静态方法
  • Array.of 将多个内容填入到对应的数组返回一个新的数组

  • Array.from 将对应的伪数组转为一个新的数组 并返回

    //静态方法
    //将传入的多个参数填入一个新的数组 并返回
    let newArray = Array.of(1,2,3,4,5)
    console.log(newArray)
    //将伪数组转为数组
    function fn(){
        console.log(arguments)
        let newArray = Array.from(arguments)
        console.log(newArray)
    }
    fn(1,2,3)
    //快速声明 10000个内容的数组
    let arr = Array.from({length:10000})
    console.log(arr)
    
对象方法
  • find 根据条件查找返回第一个满足条件的元素
  • findIndex 根据条件查找返回第一个满足条件的元素的下标
// find 根据条件查找第一个找到的元素
//高阶函数 以函数作为参数的函数称为高阶函数
var result = [1,2,,3].find(function(v,i,arr){
    console.log(v,i,arr)
    return v > 1
})
console.log(result) //2
// findIndex 根据条件查找第一个找到的元素下标
var index = [1,2,3].findIndex(function(v,i,arr){
    console.log(v,i,arr)
    return v > 1
})
console.log(index) //1
  • fill 填充值的方法
  • flat 扁平化方法
  • includes 是否包含
// 扁平化方法 
//扁平化就是将一个多维数组变成一维数组
var arr = [1,2,3,[4,5,[6,[7]]]]
//扁平化方法 传入deep 默认值为1 (打开的层级) 返回一个新的数组
//打开第几层
var flatArr = arr.flat() 
console.log(flatArr)
var flatArr = arr.flat(3)
console.log(flatArr)
//看不出层级的情况下 传入一个大的值 
var flatArr = arr.flat(Number.MAX_SAFE_INTEGER)
console.log(flatArr)
var flatArr = arr.flat(Infinity) 
console.log(flatArr)
//是否包含
console.log([1,2,3].includes(1))
find的重构
//重构find方法
function myFind(callbackFn){
    if(typeof callbackFn != "function"){
        throw new Error(`${arguments[0]} is not function`)
    }
    //遍历
    for(var i=0;i<arr.length;i++){
        if(i in arr){
            //如果满足条件
            if(callbackFn(arr[i],i,arr)){
                return arr[i]
            }
        }
    }
}
扁平化方法书写
function flatFn(arr){
    //arr这个数组内 如果存在数组
    if(arr.some(function(v){return Array.isArray(v)})){
        //取出对应的元素是数组 进行连接
        var flatArr = arr.reduce(function(prev,v){
            return prev.concat(v)
        },[])
        return flatFn(flatArr)
    }else{//如果没有数组 返回
        return arr
    }
} 
console.log( flatFn([1,[2],[6],[4,5,7]])) // [1,2,6,4,5,7]

了解flat的重构

字符串新增方法

  • startsWith 判断当前字符串是否以传入字符串开头
  • endsWith 判断当前字符串是否以传入字符串结尾
  • includes 是否包含
  • repeat 返回一个新的字符串将原本的字符串进行平铺
var str = "abcdef"
//是否以传入的字符串开头
console.log(str.startsWith('a')) //true
console.log(str.startsWith('abc')) //true
console.log(str.startsWith('abcd')) //true
console.log(str.startsWith('abd')) //false
//是否以传入的字符串结尾
console.log(str.endsWith('f')) //true
console.log(str.endsWith('ef')) //true
console.log(str.endsWith('abcdef')) //true
console.log(str.endsWith('cef')) //false
// 是否包含
console.log(str.includes('a')) //true
console.log(str.includes('ab')) //true
console.log(str.includes('ac')) //false
//repeat 平铺 将原本的字符串平铺成一个新的字符串 返回这个新的字符串 传入的参数为平铺次数
console.log(str.repeat(10))
console.log(str.repeat()) //返回空字符串
//传入number类型的值 进行隐式转换 调用Number方法
console.log(str.repeat(true)) //abcdef
console.log(str.repeat(3.1415926)) //平铺三次
console.log(str.repeat('5a')) //返回空字符串