一、let和const
在JavaScript中我们之前重要用症结var来定义变量,ES6今后,新增了定义变量的两个症结字,分别是let和const。
关于变量来讲,在ES5中var定义的变量会提拔到作用域中一切的函数与语句前面,而ES6中let定义的变量则不会,let声明的变量会在其响应的代码块中竖立一个暂时性死区,直至变量被声明。
let和const都能够声明块级作用域,用法和var是相似的,let的特点是不会变量提拔,而是被锁在当前块中。
一个异常简朴的例子:
function test() {
if(true) {
console.log(a)//TDZ,俗称暂时死区,用来形貌变量不提拔的征象
let a = 1
}
}
test() // a is not defined
function test() {
if(true) {
let a = 1
}
console.log(a)
}
test() // a is not defined
唯一准确的运用要领:先声明,再接见。
function test() {
if(true) {
let a = 1
console.log(a)
}
}
test() // 1
const
声明常量,一旦声明,不可变动,而且常量必需初始化赋值。
const虽然是常量,不许可修正默许赋值,但假如定义的是对象Object,那末能够修正对象内部的属性值。
const type = {
a: 1
}
type.a = 2 //没有直接修正type的值,而是修正type.a的属性值,这是许可的。
console.log(type) // {a: 2}
const和let的异同点
雷同点:const和let都是在当前块内有效,实行到块外会被烧毁,也不存在变量提拔(TDZ),不能反复声明。
差别点:const不能再赋值,let声明的变量能够反复赋值。
const现实上保证的,并非变量的值不得修改,而是变量指向的谁人内存地点所保留的数据不得修改。关于简朴范例的数据(数值、字符串、布尔值),值就保留在变量指向的谁人内存地点,因而等同于常量。但关于复合范例的数据(主如果对象和数组),变量指向的内存地点,保留的只是一个指向现实数据的指针,const只能保证这个指针是牢固的(即老是指向另一个牢固的地点),至于它指向的数据结构是不是是可变的,就完整不能掌握了。因而,将一个对象声明为常量必需异常警惕。
块级作用域的运用场景
除了上面提到的经常使用声明体式格局,我们还能够在轮回中运用,最着名的一道面试题:轮回中定时器闭包的考题
在for轮回中运用var声明的轮回变量,会跳出轮回体污染当前的函数。
for(var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i) //5, 5, 5, 5, 5
}, 0)
}
console.log(i) //5 i跳出轮回体污染外部函数
//将var改成let今后
for(let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i) // 0,1,2,3,4
}, 0)
}
console.log(i)//i is not defined i没法污染外部函数
在现实开辟中,我们挑选运用var、let照样const,取决于我们的变量是不是是须要更新,一般我们愿望变量保证不被歹意修正,而运用大批的const。运用const声明,声明一个对象的时刻,也引荐运用const,当你须要修正声明的变量值时,运用let,var能用的场景都能够运用let替代。
symbol
ES6 之前,我们晓得5种基础数据范例分别是Undefined,Null,Boolean,Number以及String,然后加上一种援用范例Object构成了JavaScript中一切的数据范例,然则ES6出来今后,新增了一种数据范例,名叫symbol,像它的名字流露的一样,意味着举世无双,意义是每一个 Symbol范例都是举世无双的,不与别的 Symbol 反复。
能够经由过程挪用 Symbol() 要领将建立一个新的 Symbol 范例的值,这个值举世无双,不与任何值相称。
var mySymbol=Symbol();
console.log(typeof mySymbol) //"symbol"
二、字符串
ES6字符串新增的要领
UTF-16码位:ES6强迫运用UTF-16字符串编码。关于UTF-16的诠释请自行百度相识。
codePointAt():该要领支撑UTF-16,吸收编码单位的位置而非字符串位置作为参数,返回与字符串中给定位置对应的码位,即一个整数值。
String.fromCodePoiont():
作用与codePointAt相反,检索字符串中某个字符的码位,也能够依据指定的码位天生一个字符。
normalize():供应Unicode的规范情势,吸收一个可选的字符串参数,指明运用某种Unicode规范情势。
在ES6中,新增了3个新要领。每一个要领都吸收2个参数,须要检测的子字符串,以及最先婚配的索引位置。
模板字符串
字符串是JavaScript中基础范例之一,应当算是除了对象以外是运用最为频仍的范例吧,字符串中包含了比方substr,replace,indexOf,slice等等诸多要领,ES6引入了模板字符串的特征,用反引号来示意,能够示意多行字符串以及做到文本插值(应用模板占位符)。
// 之前的多行字符串我们这么写:
console.log("hello world 1\n\
hello cala");
// "hello world
// hello cala"
//有了模板字符串今后
console.log(`hello world
string text line 2`);
// "hello world
// hello cala"
能够用${}来示意模板占位符,能够将你已定义好的变量传进括弧中,比方:
var name="cala";
var age=22;
console.log(`hello,I'am ${name},my age is ${age}`)
//hello,I'am cala,my age is 22
includes(str, index):假如在字符串中检测到指定文本,返回true,不然false。
let t = 'abcdefg'
if(t.includes('cde')) {
console.log(2)
}
//true
startsWith(str, index):假如在字符串肇端部份检测到指定文本,返回true,不然返回false。
let t = 'abcdefg'
if(t.startsWith('ab')) {
console.log(2)
}
//true
endsWith(str, index):假如在字符串的完毕部份检测到指定文本,返回true,不然返回false。
let t = 'abcdefg'
if(t.endsWith('fg')) {
console.log(2)
}
//true
假如你只是须要婚配字符串中是不是包含某子字符串,那末引荐运用新增的要领,假如须要找到婚配字符串的位置,运用indexOf()。
三、函数
函数的默许参数
在ES5中,我们给函数传参数,然后在函数体内设置默许值,以下面这类体式格局。
function a(num, callback) {
num = num || 6
callback = callback || function (data) {console.log('ES5: ', data)}
callback(num * num)
}
a() //ES5: 36,不传参输出默许值
//你还能够如许运用callback
a(10, function(data) {
console.log(data * 10) // 1000, 传参输出新数值
})
在ES6中,我们运用新的默许值写法
function a(num = 6, callback = function (data) {console.log('ES6: ', data)}) {
callback(num * num)
}
a() //ES6: 36, 不传参输出默许值
a(10, function(data) {
console.log(data * 10) // 1000,传参输出新数值
})
四、箭头函数(=>)
(箭头函数比较重要,如今简朴提一下,迟一点有空特地写一篇箭头函数的文章。)
const arr = [5, 10]
const s = arr.reduce((sum, item) => sum + item)
console.log(s) // 15
箭头函数中this的运用跟一般函数也不一样,在JavaScript的一般函数中,都邑有一个自身的this值,重要分为:
一般函数:
1、函数作为全局函数被挪用时,this指向全局对象
2、函数作为对象中的要领被挪用时,this指向该对象
3、函数作为组织函数的时刻,this指向组织函数new出来的新对象
4、还能够经由过程call,apply,bind转变this的指向
箭头函数:
1、箭头函数没有this,函数内部的this来自于父级近来的非箭头函数,而且不能转变this的指向。
2、箭头函数没有super
3、箭头函数没有arguments
4、箭头函数没有new.target绑定。
5、不能运用new
6、没有原型
7、不支撑反复的定名参数。
箭头函数的简朴明白
1、箭头函数的左侧示意输入的参数,右侧示意输出的效果。
const s = a => a
console.log(s(2)) // 2
2、在箭头函数中,this属于词法作用域,直接由上下文肯定,关于一般函数中指向不定的this,箭头函数中处置惩罚this无疑越发简朴,以下:
//ES5一般函数
function Man(){
this.age=22;
return function(){
this.age+1;
}
}
var cala=new Man();
console.log(cala())//undefined
//ES6箭头函数
function Man(){
this.age=22;
return () => this.age+1;
}
var cala=new Man();
console.log(cala())//23
3、箭头函数中没有arguments(我们能够用rest参数替代),也没有原型,也不能运用new 症结字,比方:
//没有arguments
var foo=(a,b)=>{return arguments[0]*arguments[1]}
console.log(foo(3,5))
//arguments is not defined
//没有原型
var Obj = () => {};
console.log(Obj.prototype);
// undefined
//不能运用new 症结字
var Obj = () => {"hello world"};
var o = new Obj();
// TypeError: Obj is not a constructor
4、箭头函数给数组排序
const arr = [10, 50, 30, 40, 20]
const s = arr.sort((a, b) => a - b)
console.log(s) // [10,20,30,40,50]
尾挪用优化
尾挪用是指在函数return的时刻挪用一个新的函数,由于尾挪用的完成须要存储到内存中,在一个轮回体中,假如存在函数的尾挪用,你的内存能够爆满或溢出。
ES6中,引擎会帮你做好尾挪用的优化事情,你不须要自身优化,但须要满足下面3个请求:
1、函数不是闭包
2、尾挪用是函数末了一条语句
3、尾挪用效果作为函数返回
尾挪用现实用处——递归函数优化
在ES5时期,我们不引荐运用递归,由于递归会影响机能。
然则有了尾挪用优化今后,递归函数的机能有了提拔。
//新型尾优化写法
"use strict";
function a(n, p = 1) {
if(n <= 1) {
return 1 * p
}
let s = n * p
return a(n - 1, s)
}
//求 1 x 2 x 3的阶乘
let sum = a(3)
console.log(sum) // 6
五、ES6对象新增要领
Object.assign()
Object.assign()要领用于将一切可罗列属性的值从一个或多个源对象复制到目的对象。它将返回目的对象。
Object.assign 要领只会拷贝源对象自身的而且可罗列的属性到目的对象。该要领运用源对象的[[Get]]和目的对象的[[Set]],所以它会挪用相干 getter 和 setter。因而,它分派属性,而不仅仅是复制或定义新的属性。假如兼并源包含getter,这能够使其不适合将新属性兼并到原型中。为了将属性定义(包含其可罗列性)复制到原型,应运用Object.getOwnPropertyDescriptor()和Object.defineProperty() 。
String范例和 Symbol 范例的属性都邑被拷贝。
兼并对象
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注重目的对象自身也会转变。
兼并具有雷同属性的对象
var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };
var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
六、Map和Set
Map和Set都叫做鸠合,然则他们也有所差别。Set常被用来搜检对象中是不是存在某个键名,Map鸠合常被用来猎取已存的信息。
Set是有序列表,含有相互自力的非反复值。
Array和Set对照
都是一个存储多值的容器,二者能够相互转换,然则在运用场景上有区分。以下:
Array的indexOf要领比Set的has要领效力低下
Set不含有反复值(能够应用这个特征完成对一个数组的去重)
Set经由过程delete要领删除某个值,而Array只能经由过程splice。二者的运用方便水平前者更优
Array的许多新要领map、filter、some、every等是Set没有的(然则经由过程二者能够相互转换来运用)
Object和Map对照
Object是字符串-值,Map是值-值
Object键为string范例,Map的键是恣意范例
手动盘算Object尺寸,Map.size能够猎取尺寸
Map的排序是插进去递次
Object有原型,所以映照中有一些缺省的键。能够明白为Map=Object.create(null)
Set操纵鸠合
let set = new Set()
// Set转化为数组
let arr = Array.from(set)
let arr = [...set]
// 实例属性(继续自Set)
set.constructor === Set
set.size
// 操纵要领
set.add(1) // 增加一个值
set.delete(1) //删除一个值
set.has(1) //推断是不是有这个值(Array中的indexOf)
set.clear() //消灭一切值
// 猎取用于遍历的成员要领(Set的遍历递次就是插进去递次)
set.keys() // 返回键名的遍历器
set.values() // 返回键值得遍历器
set.entries() // 返回键值对的遍历器
set.forEach() // 轮回遍历每一个值(和Array的要领一致)
for (let key of set.keys()){}
for (let val of set.values()){}
for (let entry of set.entries()){}
// 运用数组要领来处置惩罚set值
set = new Set(arr)
set = new Set([...set].map((x) => x = x * 2))
set = new Set([...set].filter((x) => x > 2))
Map的要领鸠合
let map = new Map()
// 实例属性(继续自Map)
map.constructor === Map
map.size
// 操纵要领
map.set(1,2)
map.get(1)
map.delete(1)
map.has(1)
map.clear()
// 遍历要领
map.keys()
map.values()
map.entries()
map.forEach()
// Map和数组的转换
map = new Map([['key','val'],[2,1]]) // 请求双成员数组
let arr = [...map]
// 值得注重的是Map的键是跟内存绑定的
map.set([1], 's')
map.get([1])
let arr = [1]
let arr1 = [1]
map.set(arr, 's')
map.get(arr)
map.set(arr1, 's')
map.get(arr1)
想要深切明白Set和Map,能够检察《深切明白:ES6中的Set和Map数据结构,Map与别的数据结构的相互转换》
七、迭代器(Iterator)
1、entries() 返回迭代器:返回键值对
//数组
const arr = ['a', 'b', 'c'];
for(let v of arr.entries()) {
console.log(v)
}
// [0, 'a'] [1, 'b'] [2, 'c']
//Set
const arr = new Set(['a', 'b', 'c']);
for(let v of arr.entries()) {
console.log(v)
}
// ['a', 'a'] ['b', 'b'] ['c', 'c']
//Map
const arr = new Map();
arr.set('a', 'a');
arr.set('b', 'b');
for(let v of arr.entries()) {
console.log(v)
}
// ['a', 'a'] ['b', 'b']
2、values() 返回迭代器:返回键值对的value
//数组
const arr = ['a', 'b', 'c'];
for(let v of arr.values()) {
console.log(v)
}
//'a' 'b' 'c'
//Set
const arr = new Set(['a', 'b', 'c']);
for(let v of arr.values()) {
console.log(v)
}
// 'a' 'b' 'c'
//Map
const arr = new Map();
arr.set('a', 'a');
arr.set('b', 'b');
for(let v of arr.values()) {
console.log(v)
}
// 'a' 'b'
3、keys() 返回迭代器:返回键值对的key
//数组
const arr = ['a', 'b', 'c'];
for(let v of arr.keys()) {
console.log(v)
}
// 0 1 2
//Set
const arr = new Set(['a', 'b', 'c']);
for(let v of arr.keys()) {
console.log(v)
}
// 'a' 'b' 'c'
//Map
const arr = new Map();
arr.set('a', 'a');
arr.set('b', 'b');
for(let v of arr.keys()) {
console.log(v)
}
// 'a' 'b'
虽然上面列举了3种内建的迭代器要领,然则差别鸠合的范例另有自身默许的迭代器,在for of中,数组和Set的默许迭代器是values(),Map的默许迭代器是entries()。
for of轮回解构
对象自身不支撑迭代,然则我们能够自身增加一个天生器,返回一个key,value的迭代器,然后运用for of轮回解构key和value。
const obj = {
a: 1,
b: 2,
*[Symbol.iterator]() {
for(let i in obj) {
yield [i, obj[i]]
}
}
}
for(let [key, value] of obj) {
console.log(key, value)
}
// 'a' 1, 'b' 2
字符串迭代器
const str = 'abc';
for(let v of str) {
console.log(v)
}
// 'a' 'b' 'c'
ES6给数组增加了几个新要领:find()、findIndex()、fill()、copyWithin()
1、find():传入一个回调函数,找到数组中相符当前搜刮划定规矩的第一个元素,返回它,而且停止搜刮。
const arr = [1, "2", 3, 3, "2"]
console.log(arr.find(n => typeof n === "number")) // 1
2、findIndex():传入一个回调函数,找到数组中相符当前搜刮划定规矩的第一个元素,返回它的下标,停止搜刮。
const arr = [1, "2", 3, 3, "2"]
console.log(arr.findIndex(n => typeof n === "number")) // 0
3、fill():用新元素替代掉数组内的元素,能够指定替代下标局限。
arr.fill(value, start, end)
4、copyWithin():挑选数组的某个下标,从该位置最先复制数组元素,默许从0最先复制。也能够指定要复制的元素局限。
arr.copyWithin(target, start, end)
const arr = [1, 2, 3, 4, 5]
console.log(arr.copyWithin(3)) // [1,2,3,1,2] 从下标为3的元素最先,复制数组,所以4, 5被替代成1, 2
const arr1 = [1, 2, 3, 4, 5]
console.log(arr1.copyWithin(3, 1)) // [1,2,3,2,3] 从下标为3的元素最先,复制数组,指定复制的第一个元素下标为1,所以4, 5被替代成2, 3
const arr2 = [1, 2, 3, 4, 5]
console.log(arr2.copyWithin(3, 1, 2)) // [1,2,3,2,5] 从下标为3的元素最先,复制数组,指定复制的第一个元素下标为1,完毕位置为2,所以4被替代成2
ES6中类class、Promise与异步编程、代办(Proxy)和反射(Reflection)API,这几块内容比较复杂,今后有时机再细致写。
PS: 写的太急忙了,不免有讹夺的处所。