每一次标准的诞生都意味着语言的完善,功能的加强。JavaScript语言本身也有一些令人不满意的地方。
变量提升特性增加了程序运行时的不可预测性
语法过于松散,实现相同功能,不同的人可能会写出不同的代码
ES6的新增语法
let:ES6中新增的用于变量声明的关键字
let声明的变量只在所处于的块级有效
例:
if (true) {
let a = 10;
}
console.log(a); // a is not defined
在一个大括号中使用let关键字声明的变量才具有块级作用域,var关键字不具备这个特点
例:if (true) {
let num = 100;
var abc = 200;
}
console.log(abc); //输出200
console.log(num); //"abc" is not defined
放置循环变量变成全局变量
例:for (var i = 0; i < 3; i++) {
}
console.log(i); //任然可以输出
for (let i = 0; i<3; i++) {
}
console.log(i); //现在就不可以输出,比较符合逻辑
不存在变量提升
例: console.log(a); //a is not defined (需要先声明再使用)
let a = 20;
暂时性死区
例:var tmp = 123;
if (true) {
tmp = 'abc'; //会报错,报变量没有声明的错误
let tmp;
}
if中的tmp和全局中的tmp互不干扰
经典面试题:
var arr = [];
for (var i = 0; i < 2; i++){
arr[i] = function (){
console.log(i);
}
}
arr[0](); //2俩次输出的结果都是全局变量里面的i
arr[1](); //2
此题的关键点在于全局变量i是全局的,函数执行时输出的都是全局作用域下的值
把其中的var换成let,结果就大不一样
let arr = [];
for ( let i = 0;i < 2; i++) {
arr[i] = function () {
console.log(i);
}
}
arr[0](); //0 此时输出会查找块级作用域里面的i,而不是全局查找
arr[1](); //1
此题的关键点在于每次循环都会产生一个块级作用域,每个块级作用域的变量都是不同的,函数执行时输出的是自己上一级(循环产生的块级作用域)作用域下的i值。
const:声明常量,常量就是值(内存地址)不能发生变化的量
具有块级作用域
例:if (true) {
const a = 10;
}
console.log(a) // a is not defind
声明常量时必须赋值
例: const PI; //Missing initializer in const declaration再声明const常量时丢失了初始值
常量赋值后,值不能修改
例: const PI = 3.14;
PI = 100; //Assignment to constant variable.
特殊情况:
const ary = [100,200];
ary[0] = 'a';
ary[1] = 'b';
console.log(ary); //['a','b']; 可以赋值,因为改变的是值,不是内存地址
ary = ['a','b']; //Assignment to constant variable.这样是不容许的,这样改变了ary在内存中的存储地址
总结let、const、var区别
1、使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象。
2、使用let声明的变量,其作用域为该语句所在代码块内,不存在变量提升现象。
3、使用const声明的常量,在后面出现的代码中不能在修改常量的值。
解构赋值
ES6中允许从数组中提取值,按照对应位置,对变量赋值。对象也可以实现解构。
按照一定模式,从数组或对象中提取,将提取出来的值赋值给另外的变量
数组解构
例:数组与变量一一对应的情况
let arr = [1, 2, 3]
let [a, b, c] = arr; //等号左边中括号中的abc为三个变量,与arr中的值为一一对应的关系,并且用来接收arr中的值
console.log(a); //输出为1
console.log(b); //输出为2
console.log(c); //输出为3
变量与数组中的值不对应
let [foo] = [];
let[bar ,foo] = [1]; //bar对应的值为1 foo对应的值为undefined
对象解构
对象解构允许我们使用变量的名字匹配对象的属性 匹配成功将对象属性的值赋值给变量
例:
let person = {name : 'xijiaxin'; age : 22; sex : '男'};
let { name, age, sex } = person;
console.log(name); //xijiaxin
console.log(age); //22
console.log(sex); //男
对象解构的其他用法
let person = {name : 'xijiaxin'; age : 22; sex : '男'};
let {name : myName, age : myAge} = person; // 以name : myName为例,先用name去匹配person里面的name,再把匹配到的值赋值给myName变量
console.log(myName); // 'xijiaxin'
console.log(myAge); // 22
箭头函数——ES6中新增的定义函数的方式
箭头函数是用来简化定义函数语法
箭头函数基本语法:() => {}
例:const fn = () => {
console.log('123');
}
fn(); //123
函数体中只有一句代码,且代码的执行结果就是返回值,可以省略函数体的大括号
例: function sum(num1, num2) {
return num1 + num2;
} //用原来方法实现俩数相加
const sum = (num1, num2) => num1 + num2; //用箭头函数实现
在箭头函数中,如果形参只有一个,可以省略形参外部的小括号
const fn = (i) => {
alert(i);
};
fn(20); //没有省略括号写法
const fn = i => alert(i); //简化写法
箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this
function fn () {
console.log(this); // {'name':'xijiaxin'}
return () => { //此时,箭头函数被定义在了fn的内部,箭头函数的this指向的是fn中的this
console.log(this); // {'name':'xijiaxin'}
}
}
const obj = {name : 'xijiaxin'}
cosnt res = fn.call(obj); //先用call改变fn的this指向,再用res接收fn的返回值
res();
箭头函数面试题
var obj = {
age : 20,
say : () =>{
alert(this.age)
}
}
obj.say(); //结果为undefined,因为obj是一个对象,他没有形成作用域。此时的箭头函数相当于定义在了全局,就没找到age
剩余参数
剩余参数语法允许我们将一个不定数量的参数参数表示为一个数组。
例:
function sum (first, ...args) {
console.log(first); //10
console.log(args); //[20,30] 再args前面加三个点,就让剩余的实参以数组形式赋给args
}
sum(10,20,30);
数组内所有项的和
const sum = (...args) => {
let total = 0;
args.forEach(item => total +=item); //其中遍历到的item的每一项相加
return total;
};
sum(10, 20);
sum(10, 20, 30);
剩余参数和解构配合使用
let students = ['xian', 'ouya', 'xuanyuan'];
let [s1, ...s2] = students; // 此时,s2接收了除去对应s1的值以外的所有值
console.log(s1); // 'xian'
console.log(s2); // ['ouya', 'xuanyuan']
Array的扩展方法
扩展运算符(展开语法)——扩展运算符可以将数组或者对象转换为用逗号分隔开的参数序列。
let ary = [1, 2, 3];
...ary // 1,2,3 输出结果应该为1,2,3 ,ary是由逗号分隔开的参数
console.log(...ary); // 1 2 3 输出结果为123,原因是这里的逗号被认为是参数分隔符,所有不显示就相当于
console.log(1, 2, 3); //相当于这样的输出结果
例:
let ary1 = ["a", "b", "c"];
console.log(...ary1); // a b c
console.log("a", "b", "c"); // a b c 输出结果相同
扩展运算符可以应于合并数组。
//方法一
let ary1 = [1, 2, 3];
let ary2 = [3, 4, 5];
let ary3 = [...ary1, ...ary2]; //...ary1 = 1,2,3 ary2 = 3,4,5 所以ary3 = [...ary1, ...ary2] = [1, 2, 3, 3, 4, 5]
利用扩展运算符将伪数组转换为真正的数组
<div></div>
<div></div>
<div></div>
<script>
var oDivs = document.getElementsByTagName('div');
console.log(oDivs) //此时获得的是一个类数组
var ary = [...oDivs]; //把类数组转换为可以操作的数组
ary.push('a');
console.log(ary); //输出结果为[ div,div,div,a]
</script>
构造函数方法: Array.from()——将类数组或可遍历的对象转换为真正的数组
let arrayLike = {
'0' : 'a',
'1' : 'b',
'2' : 'c',
length:3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
Array.from()——方法还可以接收第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
例: var arrayLike = {
"0" : "1",
"1" : "2",
"length" : 2
}
var ary = Array.from(arrayarLike,item => item*2); // 给循环出来的每一项值都乘2
console.log(ary); // 输出结果为[2,4]
Array.find()——用于找出第一个符合条件的数组成员,如果没有找到返回undefined
let ary = [{
id : 1,
name : '西安'
},{
id : 2,
name : '欧亚'
}];
let target = ary.find((item, index) => item.id==2); //这个函数需要携带俩个参数,当前循环项,以及当前循环项所携带的索引值
console.log(target) // 输出结果为id:1 name:"西安"
它接收一个函数作为参数,在参数函数体中,要返回一个布尔值,相当于是否满足查找的条件
Array.findIndex()——用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1
let ary = [1, 5, 10, 15];
let index = ary.findIndex((value, index) => value > 9);
console.log(index); // 此时输出为2
用法基本与find()一样,同样是需要传一个函数为参数,在参数函数体中,需要返回一个布尔值,相当于是否满足查找的条件,用于判断。
Array.includes()——表示某个数组是否包含给定的值,返回布尔值
[1, 2, 3].includes(2); //true
[1, 2, 3].includes(4); //false
String的扩展方法
模板字符串——ES6新增的创建字符串的方式,使用反引号定义。
let name = `xijiaxin`; // 模板字符串声明
模板字符串可以解析变量
let name = 'xijiaxin';
let sayHello = `hello,my name is ${name}`; // 输出hello,my name is xijiaxin
模板字符串中可以换行
let result = {
name: "xijiaxin",
age: 22,
};
let html = `
<div>
<span>${result.name}</span>
<span>${result.age}</span>
</div>
`
console.log(html)
模板字符串中可以调用函数
const fn = () => {
return '我还可以调用函数'
}
let html = `我是模板字符串,${fn()}`
console.log(html)
String实例方法:startsWith() 和 endsWith()
startsWith():表示参数字符串是否在源字符串的头部,返回布尔值
endsWith():表示参数字符串是否在原字符串的尾部,返回布尔值
例: let str = 'Hello world!';
let r1 = str.startsWith('H'); // r1输出为 true
let r2 = str.endsWith('!'); // r2输出为true
String实例方法:repeat()——reeat方法表示将原字符串重复n次,返回一个新字符串
例:
"y".repeat(5); // 表示将"y"重复5次显示,想重复几次就在括号里传几
Set数据结构
ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set本身是一个构造函数,用来生成Set数据结构。
const s = new Set();
Set函数可以接收一个数组作为参数,用来初始化。
const set = new Set([1, 2, 3, 4]);
Set函数的值是唯一的
let set = new Set(["a", "b", "a", "b"]);
//console.log(set); // 得到的类数组只有俩个值,重复的就被去除了
// 获得类数组后
let ary = [...set] // 把获得的类数组打散装进数组
console.log(ary)
Set实例方法:
add(value):添加某个值,返回Set结构本身
delete(value):删除某个值,返回一个布尔值,表示删除是否成功
has(value):返回一个布尔值,表示该值是否为Set成员
clear():清除所有成员,没有返回值
Set中取值——Set结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值
s.forEach(value => console.log(value))
例: const s5 = new Set(['a','b','c'])
s5.forEach(value =>{
console.log(value)
})