1 let和const关键字
1. 1 let
ES5中只有var能够定义变量,作用域是在function中。
ES6中可以用let来定义变量,定义是块级作用域变量。
- 如果用let来引导循环,出了循环体就真的没有定义了。
for(let i = 0; i < 10 ; i++) {
//相当于在这里定义了i
}
console.log(i); //报错
- 使用let,不再有变量声明的提升。
console.log(a); //报错
let a = 10;
- let会引发暂时性死区。
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
var m = 10;
function fun(){
m = 20; //报错。函数在预解析阶段会预读所有的语句,发现了let语句,所以就将这个函数变为了一个m的暂时性死区,此时m不允许在let前被赋值。
let m;
console.log(m);
}
fun();
1.2 const
const命令表示定义一个常量,不能被更改的量:
const pi = 3.14;
console.log(pi);
pi = 3.1415; //报错
但是可以指向一个引用类型值,对这个引用类型值的操作是允许的,但是不能允许指向别的值:
const arr = ["白板","幺鸡","二条"];
arr.push("三筒");
console.log(arr); // 合法,["白板","幺鸡","二条","三筒"];
arr = ["王","王","2","2","2","2"]; //报错,因为arr是常量。
如果要冻结对象,用Object.freeze()
const arr = Object.freeze(["路飞", "索隆","布鲁克"]);
console.log(arr); //合法
arr.push("埼玉"); //报错!因为对象已经被冻结!
Object.freeze()只能冻结一层:
var obj = Object.freeze({"a" : 1 , "b" : 2 , "c" : ["J","Q","K"]});
obj.a = 44; //没有修改成功
obj.c.push("A"); //A成功推入了数组,因为freeze只能冻结1层
console.log(obj); //{"a" : 1 , "b" : 2 , "c" : ["J","Q","K","A"]};
1.3 其它
let和const定义的变量不会成为window对象的属性,
let a = 100;
var b = 200;
const c = 300;
alert(window.a); //undefined
alert(window.b); //200
alert(window.c); //undefined
2 ES6中的解构
2.1 数组的解构
数组的解构,用[ ]。
var [a,b,c] = ["汤姆猫", "杰瑞鼠", "老板娘"];
console.log(a); // 汤姆猫
console.log(b); // 杰瑞鼠
console.log(c); // 老板娘
2.2 对象的解构
对象的解构,用{ }。
var {name,age} = {name :"老王" , age : 12};
console.log(name); // 老王
console.log(age); // 12
2.3 …运算符
spread运算符和rest运算符其实都是三个点**…**。
2.3.1 spread运算符
spread运算符又叫扩展运算符。
功能是把数组或类数组对象展开成一系列用逗号隔开的值。
var [a, b, ...c] = ["Google", "Facebook", "Alibaba", "Tencent", "163"];
console.log(a); // Google
console.log(b); // Facebook
console.log(c); // ["Alibaba", "Tencent", "163"]
几个常用用法。
//数组深拷贝
var arr1 = arr;
var arr2 = [...arr];
console.log(arr === arr1); //true, 说明arr和arr2指向同一个数组
console.log(arr === arr2); //false, 说明arr3和arr指向不同数组
//把一个数组插入另一个数组字面量
var arr3 = [...arr, 4, 5, 6];
console.log(arr3); // [1, 2, 3, 4, 5, 6]
//字符串转数组
var str = 'love';
var arr4 = [...str];
console.log(arr4); //[ 'l', 'o', 'v', 'e' ]
2.3.2 rest运算符
功能是把逗号隔开的值序列组合成一个数组。
// 1.主要用于不定参数,所以ES6开始可以不再使用arguments对象
var bar = function(...args) {
for (let el of args) {
console.log(el);
}
}
bar(1, 2, 3, 4); // 将别打印 1 2 3 4,即args=[1, 2, 3, 4]
bar = function(a, ...args) {
console.log(a); // 1
console.log(args); // [2, 3, 4]
}
bar(1, 2, 3, 4);
// 2.rest运算符配合解构使用:
var [a, ...rest] = [1, 2, 3, 4];
console.log(a); // 1
console.log(rest); // [2, 3, 4]
2.3.3 小结
总之,ES6中三个点“…”既可以用来把数组或类数组对象展开,也可以把逗号隔开的值序列组合成一个数组。具体是展开还是组合,看是赋值还是被赋值。
2.4 实际应用
- 函数参数自动解构
function fun([a,b]){
console.log(a + b);
}
fun([4,7]);
- 形参列表使用…
…将形参列表组合成数组(此时…表示rest运算符)。
function fun(...arr){
let sum = 0;
for(let i = 0 ; i < arr.length ; i++){
sum += arr[i];
}
console.log(sum);
}
fun(1,2,3,4);
- 形参列表中对象的自动解构
function fun({shuxue, yuwen, yingyu}){
console.log(shuxue + yuwen + yingyu);
}
var xiaoming = {"name" : "小明" , "age" : 12 , "shuxue" : 10 , "yuwen" :20 , "yingyu" :30};
fun(xiaoming); //60,在计算各个科目的总分。
- 更改变量名
对于对象来说,还有一个k:v的解构模式,特别重要。
冒号右边的变量才真正的被赋值,冒号左边的变量表示对象的属性。
let obj = {"a" : 1 , "b" : 2};
let { a : n , b : m} = obj;
console.log(n); //1
console.log(m); //2
console.log(a); //报错
console.log(b); //报错
- …传形参
这里…充当的是spread运算符或扩展运算符(就是把数组或对象拆开成一系列用逗号隔开的值)。
function fun(a,b,c){
console.log(a);
console.log(b);
console.log(c);
}
var arr = [1,2,3];
fun(...arr); // 将依次输出1, 2, 3
3 ES6中的字符串、数组的增强
3.1 字符串增强
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
repeat():重复多少次
`:新增加的运算符,表示模板字符串,其中的字符串可以换行。
let str = "我爱北京天安门";
console.log(str.includes("北京")); //true
console.log(str.startsWith("北京")); //false
console.log(str.endsWith("天安门")); //true
var str2 = "★".repeat(5);
console.log(str2); // ★★★★★
// 模板字符串
var a = 10;
var b = "高兴";
var c = "手机";
var str = `好高兴啊,我买了一个${c},花了${a}元,我很${b}啊!`;
console.log(str);
3.2 数组增强
- Array.from()可以将类数组对象变为数组:
let obj = {
"0" : "汤姆猫",
"1" : "杰瑞鼠",
"2" : "老板娘",
length : 3
};
let arr = Array.from(obj);
console.log(arr); // [ "汤姆猫", "杰瑞鼠", “老板娘”]
- Array.of方法用于将一组值,转换为数组。
var arr = Array.of(1,2,3);
console.log(arr); // [1, 2, 3]
- ind()、findIndex()
寻找数组中是否有某项find()、findIndex(),里面要放置回调函数。
需要注意的是,里面的回调函数的三个参数分别是项、编号、数组本身。
机理是JS会测试每一个项目,返回第一个返回true的项。
var arr = [3,4,5,34,34,324,342,43,23,30,60,45,34,53];
var item = arr.find(function(value,index,arr){
if(value % 5 == 0 && value % 6 == 0){
return true;
}
});
console.log(item); //30
返回第一个返回true的下标项,用findIndex,如果没有一个项目返回true的函数,此时就会显示-1。
var arr = [3,4,5,34,34,324,342,43,23,30,60,45,34,53];
var item = arr.findIndex(function(value,index,arr){
if(value % 5 == 0 && value % 6 == 0){
return true;
}
});
console.log(item); //9
- for of 遍历
增加了一种数组的遍历方法,叫做for of遍历。通常配合arr.entries()和arr.key()来使用。
let arr = [ "汤姆猫", "杰瑞鼠", "老板娘" ];
for(let v of arr){
console.log(v); // 输出 "汤姆猫" "杰瑞鼠" "老板娘"
}
let arr = [ "汤姆猫", "杰瑞鼠", "老板娘" ];
for(let [k,v] of arr.entries()){
console.log(k,v);
}
// 0, "汤姆猫"
// 1, "杰瑞鼠"
// 2, "老板娘"
- includes()
返回一个布尔值,判断数组中是否有某个项。现在终于不用遍历整个数组来验证某一个项目是否存在了。
4 ES6中的对象的增强
- 如果kv一致,此时可以省略v
let a = 100;
let obj = {
a ,
b : 200,
c : 300
};
console.log(obj);
- 合并对象
var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target) // {a:1, b:2, c:3}
- 得到对象的所有键
var obj = {"a" : 1 , "b" : 2 , "c" : 3};
console.log(Object.keys(obj));
5 ES6中的Symbol类型
S6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
6 ES6中的Set和Map数据结构
Set是不能有重复项的集合,Map是可以用引用类型值当做key的对象。
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
实例化的时候就可以直接传入数组,此时类似数组的去重。
let s = new Set([1,1,1,1,1,2,2,2,2]);
console.log(s); // Set{1,2}
for(let v of s){
console.log(v); //1,2
}
console.log([...s]); //[1,2]
这是数组去重的最快的方法。
let arr = [1,23,34,3,3,3,324,23,3,34,34,324];
arr = [...new Set(arr)]
console.log(arr);
size属性表示集合的长度。
new Map()的时候用数组表示映射关系,语法如下:
var xiaoming = {"name" : "小明" , "age" : 12 , "sex" : "男"};
var xiaohong = {"name" : "小红" , "age" : 13 , "sex" : "女"};
var xiaoqiang = {"name" : "小强" , "age" : 14 , "sex" : "男"};
var m = new Map([
[xiaoming , "好人"],
[xiaohong , "坏人"],
[xiaoqiang , "好人"]
]);
m.set(xiaoqiang,"坏人"); //设置xiaoqiang对象映射到"坏人"
console.log(m.get(xiaoming)); // 好人
7 ES6中的Promise对象
8 ES6中的类的定义
直接看例子。
class People{
constructor(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
} // 注意这里没有分号哟!
sayHello(){
console.log(`你好,我是${this.name},今年${this.age}岁了`);
}
}
class Student extends People{
constructor(name,age,sex,xuehao,banji){
super(name,age,sex); // super关键字,和java一样
this.xuehao = xuehao;
this.banji = banji;
}
xuexi(){
console.log(`我是${this.name},我正在学习,我是${this.xuehao}啊`);
}
}
var xiaoming = new Student("小明",12,"男",1000,"一年级1班");
xiaoming.xuexi();
xiaoming.sayHello();
ES6并没有深化“继承”的概念,还是用我们的“prototype”来实现继承(原型链)。类其实是一个语法糖。
console.log(xiaoming.__proto__.__proto__ === People.prototype); //true
9 ES6中的箭头函数
lambda表达式。和C#类似。
特别注意的是箭头函数中的this是在定义时就已经确定好了,以后都不会再改变。即使你使用call,apply,箭头函数中的this依然不变。
注意:
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
var fun = () => {
console.log(this.a);
}
var obj = {
a : 100,
f : fun
}
obj.f(); //undefined
obj.f.call(obj); //undefined
obj.f.apply(obj); //undefined
也就是说fun()在运行的时候,里面的this永远不等于obj。而是永远等于window对象(在浏览器环境中),或者是空对象(在NodeJS环境中)。