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')) //返回空字符串