一.什么是ES6?ES5、ES6和ES2015有什么区别?
ES6是新一代的JS语言标准,对部分的JS的语言进行了优化升级,规范了JS的使用标准,使得JS的使用更加的规范,更加优雅,更适合大型应用的开发。
S2015特指在2015年发布的新一代JS语言标准,ES6泛指下一代JS语言标准,包含ES2015、ES2016、ES2017、ES2018等。现阶段在绝大部分场景下,ES2015默认等同ES6。ES5泛指上一代语言标准。ES2015可以理解为ES5和ES6的时间分界线。
二.let和const命令
1.基本用法
ES6新增了let命令,用来声明变量,用法类似于var,但是所声明的变量只在let命令的代码块中有效。
for (let i = 0; i < 10; i++) {
// ...
}
console.log(i);
// ReferenceError: i is not defined
上面循环中,i只在for循环中有效
{
let a = 10;
var b = 1;
}
a // ReferenceError: a is not defined.
b // 1
上面代码a只在它所在的代码块中有效
不存在变量提升
var变量会发生变量提升的现象,即变量可以在声明之前使用,值为undefined
。
而let必须在变量声明之后使用,否则会报错。
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
暂时性死区
只要块级作用域内存在let命令,它所声明的变量就会绑定这个区域,不会受外部影响。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
ES6明确规定,在let声明之前,该变量都是不可用的,称作暂时性死区。
不允许重复声明变量
let不允许在相同作用域内,重复声明同一个变量。
// 报错
function func() {
let a = 10;
var a = 1;
}
//基本用法 报错
function func() {
let a = 10;
let a = 1;
}
2.块级作用域
块级作用域的作用 没有块级作用域,这会带来很多不合理的场景
- 内层变量可能会覆盖外层变量
- 用来计数的循环变量可能会泄露成为全局变量。
3.const命令
基本用法 一旦声明就不能,常量的值就不能被改变,而且声明之后必须立即对其初始化,否则会报错。
const foo;
// SyntaxError: Missing initializer in const declaration
const的作用域和let命令相同,只在声明的所在的块级作用域有效。用来保证声明的变量不会被改动。
##4.ES6声明变量的六种方法 ES5只有var,function,而ES6添加了let,const,import,class。
三.变量的解构赋值。
左右两边结构必须一样;右边合法;声明和赋值不能分开(必须在一句话里完成)
1.数组的解构赋值
基本用法
之前为变量赋值只能直接指定值
let a = 1;
let b = 2;
let c = 3;
而ES6
let [a, b, c] = [1, 2, 3];
let [foo, [[bar], baz]] = [1, [[2,3], 3]];
foo // 1
bar // 2,3
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
如果解析不成功,变量的值为undefined
let [foo] = [];
let [bar, foo] = [1];
这两种方式中foo的值都会为undefined;
默认值
解构赋值允许指定默认值。
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
2.对对象的解构赋值
变量必须与属性同名才能成功赋值
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined
3.函数的扩展
函数参数的默认值(重点)
Es6允许为参数直接设置默认值,直接定义在参数的后面。
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
函数的length属性:可以返回没有指定默认值的参数个数
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
rest参数:(形式...变量名)用于获取函数的多余参数,rest参数搭配的变量是一个数组,将变量多余的参数放入数组中。rest参数后不能再有其他参数。
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
扩展符运算:(形式...) 可以将一个数组拆开成若干参数。
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
箭头函数基本用法(重点)
基本用法
允许使用箭头来定义函数, 如果只有一个参数圆括号省略,若果还有一个return,{}可以省略
var f = v => v;
等同于
var f = function(v) {
return v;
};
如果不需要或需要多个参数,可以用一个函数表示参数部分
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
箭头函数使用时需要注意的点
- 函数体内的this对象,就是定义时所在的对象,不是使用时所在的对象。
- 不可当做构造函数,不可以使用new命令。
- 不可以使用arguments对象,可以用rest参数替换
- 不可以使用yield命令,因此箭头函数不能用作Generator函数。
其中注意在箭头函数中,this的指向固定的,它的内部没有自己的this,这也就导致了this总是指向上一层的this,如果上一层还是箭头函数,则继续向上指,直到指向到有自己this的函数为止,并作为自己的this。
数组的扩展
- map 映射
let arr=[12,5,8];
let result =arr.map((item)=>{
return item *2;
})
let score=[19,85,99,25];
let result=score.map(item=>item>=60?'及格':'不及格');
- reduce 汇总,一堆出来一个,总数,平均数
let arr=[12,46,33,56];
//计算总和,temp表示的是中间结果,item一次遍历数组,index,循环次数
let num=arr.reduce(function(temp,item,index){
return temp+item;
})
- filter 过滤器,保留一部分,去留一部分
//留下3的倍数,留下返回true的部分
let arr=[12,5,6,75,46];
let result=arr.filter(item=>{
if(item%3==0)
return false;
else return true;
})
- forEach 循环迭代
4.对象的扩展
- 可以直接以变量形式声明属性或方法(传统的键值对形式)
let es5Fun = {
method: function(){}
};
let es6Fun = {
method(){}
}
5.Symbol是什么?有什么作用?
Symbol是ES6引入的第七种原始数据类型(说法不准确,应该是第七种数据类型,Object不是原始数据类型之一,已更正),所有Symbol()生成的值都是独一无二的,可以接受一个字符串作为参数,var s1=Symbol(); var s2=Symbol("foo")
,可以作为属性名,而且并不是私有属性
let a={};
let name=Symbol();
a[name]='oll';
6.Promise对象
完成异步请求:多个任务同时进行,代码更复杂 形式:
let p=new Promise(function(resolve,reject){
//resolve成功
//reject失败了
$.ajax({
url:'arr.text',
dataType:'json',
success(arr){
resolve(arr);
}
err0r(err){
reject(err)
}
})
})
//promise 对象掉用then函数开始执行,then的第一个参数是resolve函数,第二个///参数是reject函数
p.then(function(){
alert('成功了')
},function(){
alert('失败了')
})
重点promise.all方法
function createPromise(url){
return new Promise(function(reslove,reject){
$ajax({
url,
dataType:'json',
success(arr){
resolve(arr)
},
error(err){
reject(err)
}
})
})
}
//多个Promise同时执行
Promise.all([p1,p2]).then(function(arr){
console.log(arr);//ajax中传的内容但是内容都会放在arr中
let [res1,res2]=arr;//利用解构赋值可以将结果分解出来
},function(){
//一个失败就会返回失败的结果
})
代码优化
Promise.all([
$ajax({}),
$ajax({})
]).then(function(results){
let[arr1,arr2]=result;
},function(){
//失败
})
7.async和await在干什么
解决异步问题,async返回的是一个Promise对象,await是在等待一个async函数完成,因为async函数返回的是一个Promise对象,await 必须出现在 async 函数内部,不能单独使用如果await函数等到了一个promise对象,await会阻塞后面的代码
举例:
//我们仍然使用 setTimeout 来模拟异步请求
function sleep(second, param) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(param);
}, second);
})
}
async function test() {
let result1 = await sleep(2000, 'req01');
let result2 = await sleep(1000, 'req02' + result1);
let result3 = await sleep(500, 'req03' + result2);
console.log(`
${result3}
${result2}
${result1}
`);
}
test();
//req03req02req01
//req02req01
//req01
8.Proxy
-
什么是Proxy? 是ES6中提供的一个构造函数,更像一种拦截器,在访问赋值时会先用到我们定义好的拦截方法。
-
为什么需要Proxy()?别代理对象不希望直接别访问;被代理的对象能力不足时找个人帮他做,增加新的功能
-
Proxy的用法? Proxy的构造函数中接受两个参数
new Proxy(target,hander)
其中target参数是指目标对象(被代理的的对象),一个对象,属性是各种控制和修改target基本方法的行为。
举例:用户未设置头像返回默认头像
const user={name="cz"};
const userProxy=new Proxy(user,{
get:(obj,prop)=>{
if(prop==='avatar'){
if(!obj.prop){
return 'https://...'
}
}
return obj[prop];
}
})
9.Generator函数
- 什么是Generator()? 执行到中间可以停,配合
yield
函数使用 - 作用:可以实现带逻辑的异步
//注意声明方式比较特殊有个*
function *show(){
alert('a');
yield;//控制在哪里停
alert('b');
}
//使用起来也比较特殊
let genodj=show();
genobj.next();//开始执行,打印a,碰到yield停下来
genobj.next();//打印出b
yield既可以传参,也可以返回。
function *show(){
alert('a');
let a=yield;//控制在哪里停,可以有返回值,此时a的值为5
alert('b');
}
//使用起来也比较特殊
let genodj=show();
genobj.next(12);//
genobj.next(5);//
runner(function*(){
let data1=$.ajax({url:,dataType});
let data2=$.ajax({url:,dataType});
let data3=$.ajax({url:,dataType});
})