ES的全称是ECMAScript,它是由ECMA国际标准化组织制定的一项脚本语言的标准化规范。
为什么使用ES6?
每年6月份更新,每一次标准的诞生都意味着语言的完善,功能的加强。JavaScript语言本身也有一些令人不满意的地方。
- 变量提升特性增加了程序运行时的不可预测性
- 语法过于松散,实现相同的功能,不同的人可能会写出不同的代码
ES6的新增语法
let
let声明的变量只在所处于的块级(大括号)有效
在一个 { } 中声明的变量,具有块级作用域特性,var没有这个特性。
if (true) {
let a = 10;
console.log(a); // 10
}
console.log(a); //报错
if (true) {
let a = 1;
var b = 2;
console.log(a,b); // 1 2
}
console.log(b); //2
console.log(a); //报错
作用:
- 防止循环变量变成全局变量
for(var i=1;i<3;i++){}
console.log(i); //3
//这里虽然写在()里,但是依然和其对应的{}绑定,拥有了块级作用域
for(let i=1;i<3;i++){}
console.log(i); //报错,未初始化
- 不存在变量提升
必须先声明后使用!
console.log(a); //undefined 获取到变量了
var a = 1;
console.log(b); //报错,未初始化
let b = 1;
- 暂时性死区
外部定义不影响内部定义。例子中报错是未定义。
var a =123;
if(true){
console.log(a); //报错,未初始化
let a="abc";
}
经典面试题:
此题的关键点在于变量i是全局的,函数执行时输出的都是全局作用域下的值。
var arr = [];
for (var i = 0; i < 2; i++) {
arr[i] = function () {
console.log(i);
}
}
arr[0](); // 2
arr[1](); // 2
此题的关键点在于每次循环都会产生一个块级作用域,每个块级作用域中的变量都是不同的,函数执行时输出的是自己上一级(循环产生的块级作用域)作用域下的i值.
var arr = [];
for (let i = 0; i < 2; i++) {
arr[i] = function () {
console.log(i);
}
}
arr[0](); // 0
arr[1](); // 1
const
声明常量,常量就是值(内存地址)不能变化的量。
- 具有块级作用域
if(true){
const a = 11;
console.log(a); // 11
}
console.log(a); //报错,未定义
- 声明常量时必须赋值,否则就会报错
const tmp; //常量声明中缺少初始值设定项
const tmp = 12;
- 常量赋值后,值不能修改
对于基本数据类型,一旦赋值,值不可更改。
const a = 100;
console.log(a); //不输出,只显示下方的报错
const a = 10; //标识符“a”已声明
console.log(a);
const a = 100;
console.log(a); // 100
a = 10; //报错,对常量变量赋值
console.log(a);
对于复杂类型,不能直接赋值,但是可以修改数据结构内部的值,比如数组。
const arr = [100,200];
arr[0] = 'a'; //修改成功
arr[1] = 'b'; //修改成功
console.log(arr); // ["a","b"]
arr = ['c','d']; //报错,对常量变量赋值
let、const、var的区别
- 使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象。
- 使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升。
- 使用const 声明的是常量,在后面出现的代码中不能再修改该常量的值。
解构赋值
ES6中允许从数组中提取值,按照对应位置,对变量赋值。对象也可以实现解构。
1. 数组解构:
数组解构允许我们按照一一对应的关系从数组中提取值然后将值赋值给变量
let arr = [1,2,3];
let [a,b,c] = arr;
console.log(a,b,c); // 1 2 3
let [a,b,c] = [1,2,3]
console.log(a,b,c); // 1 2 3
如果解构不成功,变量的值为undefined
let arr = [1,2];
let [a,b,c] = arr;
console.log(a,b,c); // 1 2 undefined
2. 对象解构:
对象结构实际上是属性匹配,变量名匹配属性名,匹配上就把属性的值赋值给变量。
let person = {name:"xx",age:20}
let {name,age} = person;
console.log(name,age); // xx 20
第二种写法:使用别名,冒号左边属性,右边变量
let person = {name:"xx",age:20}
let {name:a,age:b} = person;
console.log(a,b); // xx 20
箭头函数
ES6中新增的定义函数的方式。
箭头函数是用来简化函数定义语法的。
() => {}
一般我们会将箭头函数赋值给一个变量,通过变量调用箭头函数。
const fn = () => {}
const fn = () =>{
console.log("箭头函数");
}
fn(); //箭头函数
箭头函数的特点:
- 函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号
//常规写法:
function sum(num1,num2){
return sum1+sum2;
}
//箭头函数写法:
const sum = (sum1,sum2) => sum1+sum2;
- 如果形参只有一个,可以省略形参外部的小括号
function sum(num1){
alert("1");
}
const sum = sum1 => { alert("1"); }
sum();
- this相关
传统函数中,谁调用起来的函数,this指向谁。
箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this。
call可以改变this内部指向
function fn(){
console.log(this); //{name: "xx"}
}
const obj = {name : "xx"};
fn.call(obj); //将fn内部的this指向obj
// 箭头函数中没有this,这里用this的话,就会绑定在fn函数上,而下方已经把fn函数指向obj
function fn(){
console.log(this); // {name: "xx"}
return ()=>{
console.log(this); // {name: "xx"}
}
}
const obj = {name : "xx"};
const resfn = fn.call(obj); //将fn内部的this指向obj
resfn(); // resfn就是完整的箭头函数 ()=>{console.log(this);} ,调用箭头函数使用resfn()
箭头函数面试题
//age = 100; 加上这一句,输出的就是100
var obj = {
age: 20,
say: () => {
console.log(this.age);
}
}
obj.say(); // undefined 并不是20
//调用obj下的say,输出this.age
// obj没有this,如果使用,那就会指向其定义区域的this,
//但是obj没有区域性,所以相当于定义在了全局作用域下,this指向window
//window下没有age,所以输出undefined
//在window下定义一个age,就可以输出了
剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
function sum(sum1,...sumn){
console.log(sum1); // 1
console.log(sumn); // [2, 3, 4, 5]
}
sum(1,2,3,4,5);
…sumn 是一个数组,存储了2345。
经典案例:传入不知道数量参数的运算。
forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
item() 方法返回一个节点列表中指定索引的节点。
方法一:
const addn = (...sumn)=>{
let sum=0;
for(let i = 0;i<sumn.length;i++){
sum += sumn[i];
}
return sum;
// console.log(sum);
}
addn(1,2,3,4,5);
方法二:
const add = (...sumn)=>{
let sum = 0;
sumn.forEach(item => sum+=item)
return sum;
}
add(1,2,3,4,5);
剩余参数和解构配合使用
let names = ['张三','李四','王二','赵五'];
let [n1,...n2] = names;
console.log(n1); // 张三1
console.log(n2); // ["李四", "王二", "赵五"]
扩展运算符
扩展运算符可以将数组或者对象转为用逗号分隔的参数序列。
let names = [1,2,3,4];
console.log(...names); // 1 2 3 4
// 注意,原本的console.log(1,2,3); 输出结果就是 1 2 3,没有逗号
// 而...names 就是 1,2,3,4 ,所以输出结果没有逗号
应用:
// 合并数组:
let ary1 = [1,2,3];
let ary2 = ['a','b','c'];
let ary3 = [...ary1,...ary2]; // [1, 2, 3, "a", "b", "c"]
//方法二:
let ary1 = [1,2,3];
let ary2 = ['a','b','c'];
ary1.push(...ary2);
console.log(ary1); // [1, 2, 3, "a", "b", "c"]
将类数组(伪数组)或可遍历对象转换为真正的数组:
let divs = document.getElementsByTagName('div');
console.log(divs); //伪数组 HTMLCollection(6) [div.d1, div.d3, div.d3, div.d2, div.d3, div.d3]
var ary = [...divs];
console.log(ary); // 数组(6) [div.d1, div.d3, div.d3, div.d2, div.d3, div.d3]
转换成数组之后,就能够使用数组中的方法了。
ary.push('a'); // 数组可以追加,伪数组不行
console.log(ary); // (7) [div.d1, div.d3, div.d3, div.d2, div.d3, div.d3, "a"]
构造函数方法
Array.from()
将类数组(伪数组)或可遍历对象转换为真正的数组
let arrlike= {
'0':'a',
'1':'b',
'2':'c',
length:'3' //注意,这一句不能少,不然无法转换
}
var ary = Array.from(arrlike);
console.log(ary);
方法还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
let arrlike= {
'0':'2',
'1':'3',
'2':'4',
length:'4'
}
var ary = Array.from(arrlike,item=>item*2); //省略写法
var ary = Array.from(arrlike,item=>{return item*2}); //不省略写法
console.log(ary); // (4) [4, 6, 8, NaN]
实例方法
find ()
用于找出第一个符合条件的数组成员,如果没有找到返回undefined
let ary = [{
name: 'xx',
id:1
},{
name: 'xx',
id:2
}];
let a = ary.find(item=> item.id == 2);
console.log(a); // {name: "xx", id: 2}
findIndex ()
用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1,找到返回1
let ary = [10,20,30,40];
let a = ary.findIndex(item=>{
return item >15;
})
console.log(a); // 1
includes ()
表示某个数组是否包含给定的值,返回布尔值。
let ary = [10,20,30,40];
let a=ary.includes(20);
let b=ary.includes(22);
console.log(a,b); // true false
模板字符串
ES6新增的创建字符串的方式,使用反引号定义。
let name = `xx`;
特点:
- 模板字符串中可以解析变量:
${变量名}
let name = `xx`;
let hello = `我的名字是 ${name}`;
console.log(hello); // 我的名字是xx
- 模板字符串中可以换行
按照原本的样式输出。
let xx = {
name: 'xxx',
age: 19,
sex: '男'
}
let html = `<div>
<span>${xx.name}</span>
<span>${xx.age}</span>
<span>${xx.sex}</span>
</div>`;
console.log(html);
- 在模板字符串中可以调用函数
let a = function(){return "输出!";}
let b = `无视我+${a()}`;
console.log(b); //无视我+输出!
字符串方法
startsWith ()
:
表示参数字符串是否在原字符串的头部,返回布尔值
endsWith ()
:
表示参数字符串是否在原字符串的尾部,返回布尔值
let hello = "hello world";
console.log(hello.startsWith('hello')); // true
console.log(hello.endsWith('d')); // true
console.log(hello.endsWith('dd')); // false
repeat ()
repeat方法表示将原字符串重复n次,返回一个新字符串。
let a = "123";
console.log(a.repeat(2)); // 123123
let num = 123;
console.log(num.repeat(2)); // 报错,重复次数不是函数
Set 数据结构
ES6提供了新的数据结构Set。
它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成Set 数据结构。
let s = new Set();
Set函数可以接受一个数组作为参数,用来初始化。
const set=new Set([1,2,3,4,4]);
console.log(set); // Set(4) {1, 2, 3, 4} 注意少了一个4
console.log(set.size); // 4 是4不是5,等同length,但是过滤重复
案例1:商场项目中,储存用户搜索记录,下次直接点击搜索,不会储存重复搜搜记录。
案例2:数组去重:
用set结构化原数组,再用扩展运算符接收内容,再加上[],再赋值给一个变量就生成了新的数组,得到去重后的数组。
let search = [1,2,3,4,4];
const set=new Set(search);
let ary = [...set];
console.log(ary); // (4) [1, 2, 3, 4]
Set()
数据结构中的方法:
add(value): 添加某个值,返回Set结构本身
delete(value): 删除某个值,返回一个布尔值,表示删除是否成功
has(value): 返回一个布尔值,表示该值是否为Set的成员
clear(): 清除所有成员,没有返回值
实例:
let search = [1, 2, 3, 4, 4];
const set = new Set(search);
set.add(5).add(6).add(7); // Set(7) {1, 2, 3, 4, 5, 6, 7}
set.delete(1); // Set(6) {2, 3, 4, 5, 6, 7}
set.has(2);
console.log(set.has(2)); // true ,没有的话返回false
set.clear(); // Set(0) {}
console.log(set);
Set ()
遍历
Set结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。
let search = [1, 2, 3, 4, 4];
const set = new Set(search);
set.forEach((value)=>{
console.log(value); // 1 2 3 4 ,四次输出的
})