ES6系列---【ES6新语法】
1、ES6与JavaScript的区别
ES6仅仅是一种语法规范。JavaScript只是ES6的一种实现,具体实现到多少看浏览器厂家执行规范的程度。javascirpt 还包括DOM、BOM,另外JavaScript还可以应用与后台开发环境例如node。
2、let 与 const
ES6新增用于声明变量的语法。
2.1 let与var的区别
a) var 是函数作用域,let是块作用域
-
let与var 用法是一样的
-
let在 if、for循环等语句中声明的变量也是局部变量
-
优点:et声明的变量可以防止全局污染。容易产生bug
b) var 有变量提升,let不存在变量提升
-
let变量声明必须先声明,再使用,否则报错;
-
优点:对于开发者来说,代码更严谨,报错更加一目了然,容易排除。
c) var 可以重复声明的,let在同一作用域下不能重复声明
-
函数的形参let 也不允许重复声明。
-
优点:在复杂的项目开发中,程序员重复声明变量在所难免,var的情况不报错,不易觉察,容易产生bug。let直接报错,比较直观容易排除
2.2 let变量在for循环中的应用
let变量在for循环中,分为父作用域和子作用域。for循环的圆括号中的变量是父作用域中,for循环的大括号实际为子作用域。
var btns = document.getElementsByTagName("button");
for (let i = 0; i < btns.length; i++) {
btns[i].onclick = function () {
alert(i + 1);
}
}
3、const 常量
const常量用于项目中不经常会改变的内容。例如:地址,数据库账号,密码、圆周率PI
-
const特征:
-
一旦被声明并赋值后不可再改动
-
声明和赋值必须同时进行
-
其他特征和let一样
-
约定俗称:常量名称大写
-
特殊说明:
const常量对于复杂类型来说,只能保证保存地址的不能被更改,至于地址指向的内容是可以修改的。
4、et变量与顶级对象(window)解绑
- var 声明的全局变量,实际上是window对象的属性,这是JavaScript遗留的设计败笔
- 从ES6开始,let 声明的变量与window对象不再绑定
let a = "ok";
console.log( window.a ); //undefined
4、解构赋值
解构赋值: ES6按照一定的模式,将结构化的数据(数组、对象)中的数据提取出来,赋值给变量
-
总结特征:
- 必须有赋值运算符(等号)
- 等号的前面是模式和变量
- 等号的后面是数组或对象
-
数组解构赋值的几种情况
-
要解构的数据和变量一一对应
-
要解构的数据比变量多,没有影响
-
要解构的数据比变量少,解构失败变量的值为undefined
-
解构赋值允许使用 空的逗号实现缺省
-
解构赋值的默认值(当解构赋值失败时或者严格等于undefined时默认值生效)
let [x=1,y=x] = []; // x=1 y=1
let [x=1,y=x] = [2]; //x=2, y=2
let [x=1,y=x] = [1,2]; //x=1 y=2
let [x=y,y=1] = []; //报错,变量y未声明即使用了
-
对象解构赋值的情况
-
对象的解构赋值,因为对象中的属性没有次序,因此对象必须依靠键的匹配实现解构赋值。
-
对象解构赋值的默认值(当解构赋值失败时或者严格等于undefined时默认值生效)
// let {name:xxx,sex:yyy,age:zzz} = {name:"张三",age:20,sex:"男"}
// console.log( xxx, yyy,zzz);
// 实际可能写为:
// let {name:name,sex:sex,age:age} = {name:"张三",age:20,sex:"男"}
// console.log( name,sex,age);
// ES6允许简化为:
let {name,sex,age} = {name:"张三",age:20,sex:"男"}
console.log( name,sex,age);
-
函数形参的解构赋值
- 可利用数组实现解构赋值。注意声明函数时的形参此时不是数组,是模式和变量
function fn([a,b,c]){ console.log( a+b+c ); } fn([2,3,4]); */ // 相当于 // let [a,b,c] = [2,3,4]
- 利用对象实现函数解构赋值。注意,声明函数时的形参不是对象,是模式和变量\
function demo({x,y}){ return x*y } console.log( demo({x:2,y:2}) ); */ // 相当于 // let {x,y} = {x:2,y:2}
- 函数形参解构赋值时的默认值
function fn({x=0,y=0}){ return x*y } */ // console.log( fn({x:1}) )
5、解构赋值应用场景
1) 交换变量的值
2) 获取函数的多个返回值
3)利用解构赋值实现ajax封装函数
// 利用解构赋值实现ajax封装函数。可灵活使用解构赋值的默认值,这样调用函数时只需要传递必要的参数即可
function sendAjax({type="get",url,data=null,dataType="json",timeout="5000"}) {
$.ajax({
type: type, //请求的方法 get post
url: url, //请求的地址
data: data, // 请求时发送的数据
dataType: dataType, //期望返回的数据类型
// ajax成功后的回调函数
success: function (response) {
console.log(respnse);
},
// 失败时的回调函数
error: function (err) {
console.log(err);
}
});
}
// 函数调用时传递实参为一个对象
sendAjax({url:"http://baidu.com/01.json"});
sendAjax({url:"http://baidu.com/02.json"});
以上代码进一步优化为:
将封装函数保存为外部js, 需要时引用:
// 利用解构赋值实现ajax封装函数。可灵活使用解构赋值的默认值,这样调用函数时只需要传递必要的参数即可
function sendAjax({type="get",url,data=null,dataType="json",timeOut="5000"},callback) {
$.ajax({
type: type, //请求的方法 get post
url: url, //请求的地址
data: data, // 请求时发送的数据
dataType: dataType, //期望返回的数据类型
// ajax成功后的回调函数
success: function (response) {
// console.log(respnse);
callback(response)
},
// 失败时的回调函数
error: function (err) {
console.log(err);
}
});
}
<script src="./sendAjax.js"></script>
<script>
sendAjax({type:"post",url:"http://api.shenzhou888.com.cn/v2/ecapi.banner.list"},function(data){
// 渲染页面代码
console.log( data );
});
</script>
6、字符串扩展--模板字符串
ES6可以使用模板字符串(``) 代替原来的繁琐的拼字符串渲染页面的方式。可以使用 ${ } 来嵌套变量或js表达式。
let str = `<ul>
<li><span class="name">姓名:</span><span class="uname">${student.name}</span></li>
<ul>
<li>${ "语文:"+ student.score[0]}</li>
<li>${ "数学:"+ student.score[1]}</li>
<li>${ student.score[2]}</li>
</ul>
<li>性别:${ student.sex }</li>
</ul>`;
let box = document.getElementById("box");
box.innerHTML = str;
7、ES6对象扩展
- 允许属性名简写
let name = "jack";
let sex = "男"
let obj = {
name,
sex,
say(){
console.log( name );
}
}
- ES6支持对象的键为表达式
let city = {};
for(let i=0;i<26;i++){
console.log( String.fromCharCode(i+65) );
let key = String.fromCharCode(i+65);
city[key] = [];
}
- 几个静态方法
- Object.assign() 对象的合并
- Object.keys() 获取对象上所有的键,以数组的形式返回
- Object.values() 获取对象上所有的值,以数组的形式返回
// 对象的合并,第一个参数为合并的目标对象
let obj1 ={ name:"jack"};
let obj2 = { sex:"男"};
Object.assign(obj1, obj2);
console.log( obj1 );
8、数组扩展
- Array.from() 将类数组对象转换为真正的数组
// nodelist, htmlCollection, argument 类数组对象
// 典型的类数组对象的形式:
let obj = {
"0":"hello",
"1":"world",
"length":2
}
console.log( obj );
console.log( Array.from(obj) );
- includes()
用来查找数组中是否存在指定的值,有就返回true, 没有返回false。与indexOf的功能类似。
// includes() 用来查找数组中是否存在指定的值,有就返回true, 没有返回false。解决了indexOf()对NaN无效的bug
let arr = [2,3,4,5,NaN];
/* if( arr.indexOf(NaN) != -1 ){
console.log("找到了");
}else{
console.log("没找到");
} */
if( arr.includes(NaN) ){
console.log("找到了");
}else{
console.log("没找到");
}
9、函数扩展
ES6可以使用箭头(=>)来简化函数的声明。
-
特征: 用 => 替换了 function
-
=>的后面:
- 如果函数体内只有一行代码,大括号可省略
- 如果只有一行代码而且是return语句,return 也可省略
- 如果只有一行代码而且是retrun一个对象,为了避免歧义,要使用圆括号包起来
-
=>的前面:
- 如果只有一个形参,圆括号也可以省略
- 如果有多个或者没有形参,圆括号不能省略
-
箭头函数中的this指向规律
-
ES6之前的普通函数中this指向规律:
1)在全局函数或定时器的回调函数中this指向 window
2)在事件处理函数中this指向事件源
3)在对象的方法中this指向对象本身
4)可使用call/apply/bind 改变this指向
-
ES6中箭头函数的this指向规律:
1)定义好箭头函数后,this的指向就确定了,与call/apply等没有关系
2)永远指向其上层环境(环境指的的是函数内或全局下,只有这两种情况,其他的大括号不能称为环境)
function Person(){
let fn1 = ()=>{
console.log( this );
}
fn1();
}
// 1、Person当普通函数调用时
// Person();
// 2、Person当构造函数使用时,构造函数中的this发生了改变,指向创建的新对象。那么箭头函数中的this也指向新创建的对象。
new Person();
- 箭头函数的不适应用的情况:
1)事件处理函数中;
2)对象的方法中;
3)构造函数中
函数形参的默认值
// 函数形参的默认值
function fn(name="杨营"){
// if(!name){
// name = "杨营";
// }
// name = name || "杨颖"; //短路语法
console.log(`我是:${name}` );
}
fn("刘子琪")
rest剩余参数运算符 和 spread 扩展运算符
rest 剩余参数,用于获取多余(全部)的实参并放入一个数组中。
// rest剩余参数运算符(...),只出现在函数形参声明处,作用可代替arguments,实现将实参转换为数组
function fn(...c){
console.log( Array.from(arguments) );
console.log( c );
}
fn(1,2,3,4,5,6)
spread扩展运算符(...),作用是将结构化的参数(数组,对象)转换为逗号分隔的参数序列。类似rest的逆运算。
/* let arr = [2,3,4,5]
console.log( ...arr );
*/
// 应用场景1 -- 函数传参
/* let arr = [2,5,0,9];
console.log( Math.min(...arr) ); */
// 应用场景2--数组合并
let arr1 = [2,3,4,5];
let arr2 = ["hello","ok"];
let arr3 = [...arr1,...arr2];
// 对象合并
let obj1 = {
name:"jack"
}
let obj2 = {
age:20
}
let obj3 = {
...obj1,
...obj2
}
console.log( obj3 );
10、symbol 类型
symbol是ES6新增的数据类型,string、number、boolean、null、undefined、object、symbol。
// symbol类型,作用是产生一个永不和其他symbol相同的独一无二的值。
// 创建symbol时可添加一个参数,起到在控制台输出时的区分作用,类似于程序中的注释,对程序的执行没有任何影响
let s1 = Symbol("老大");
let s2 = Symbol("老二");
console.log(typeof s1);
console.log( s1 == s2 ); //永远false
console.log(s1,s2);
11、set数据类型
set 是ES6新增的类似数组的数据结构。特点:set中的成员永远是唯一,允许重复。set的主要作用是过滤数组中重复的项。
// set 数据类型,类似数组的数据结构,作用:可以过滤到数组中重复的项
let arr = [2,3,2,4,3,0,1,4];
let s1 = new Set(arr);
console.log( s1 );
console.log( Array.from(s1) );
set 自有的属性和方法:
size set中成员的个数
add() 添加某个值
delete() 删除某个值
has() 返回一个布尔值,表明是否包含有某个值
clear() 清除set中所有成员
12、Map数据类型
Map是ES6新增的类似对象的数据结构,也是键值对的集合。
-
特点:键的范围不限于字符串,可以是各种类型的值都可以当做键,比object提供的‘字符串一值’的对应更加完善
-
set 自有的属性和方法:
- size 类似数组的length属性:size用于返回Map集合的内容长度
- set(key,value):添加一个键值数据
- get(key):根据key获取value
- has(key):返回布尔值,表明是否包含有某个值
- delete(key):根据指定的key删除数据
- clear():清除Map中所有成员,没有返回值
//Map基本使用 let m = new Map(); m.set('c', 'content') m.get('c')//content m.size//1 m.has('c') // true m.delete('c') m.has('c') m.clear()
//Map结构和数组结构之间的转换 let map = new Map([ [1, 'one'], [2, 'two'], [3, 'three'], ]); [...map.keys()]// [1, 2, 3] [...map.values()]// ['one', 'two', 'three'] [...map.entries()]// [[1,'one'], [2, 'two'], [3, 'three']] [...map]// [[1,'one'], [2, 'two'], [3, 'three']]
-
Map 循环遍历
Map 原生提供三个遍历器:
- keys():返回键名的遍历器。
- values():返回键值的遍历器。
- entries():返回所有成员的遍历器
let map = new Map([
['F', 'no'],
['T', 'yes'],
]);
for (let key of map.keys()) {
console.log(key);
}
// "F"
// "T"
for (let value of map.values()) {
console.log(value);
}
// "no"
// "yes"
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"
// 或者
for (let [key, value] of map.entries()) {
console.log(key, value);
}
// 等同于使用map.entries()
for (let [key, value] of map) {
console.log(key, value);
}
上面代码最后的那个例子,表示 Map 结构的默认遍历器接口(Symbol.iterator 属性),就是 entries 方法。
map[Symbol.iterator] === map.entries // true