es6,es7,webpack 和 babel(爱前端)
npm install -g cnpm --registry=https://registry.npm.taobao.org
默认安装位置:
一 ES6, ES7 简介和调试方法
1.1 简介
ECMAScript6 就是ECMAScript2015
ECMAScript7 就是ECMAScript2016
ECMAScript8 就是ECMAScript2017
ECMA组织2015年开始每年都要发布一个ECMAScript的新版本。
ECMAScript现在的语言实现就两个:JavaScript、ActionScript。
1.2 浏览器调试
使用新版本的浏览器,就能调试一些 ES6, 7, 8 的语法
在浏览器调试的时候,要有HTML的壳子,要有 script 标签
1.3 使用 NodeJS 调试
查看 node 版本: 命令行 node -v 回车
运行结果:
1.4 使用 Babel 翻译
-g 安装的,一般叫做 CLI 程序 , commond line interface 命令行接口,这些命令可以在 CMD 窗口中使用
npm install -g cnpm --registry=https://registry.npm.taobao.org
默认安装位置:
运行上述代码后,我们能在 CMD 中运行 cnpm
1, babel 需要用 -g 安装
检查 babel 是否安装成功: babel --version
2, 到这一步,切换到项目目录下,创建一个文件 .babelrc 文件 rc 表示 resource 资源的意思
windows 下不允许文件名以 . (点) 开头,解决:先建立一个文件,然后 rename xx.txt .babelrc
文件内容:
3 完成 .babelrc 之后,还要安装这个 preset 的依赖
cnpm install --sava-dev babel-preset-es2015
--save-dev表示在项目的 package.json 文件中的“devDependencies”字段列出,表示项目的开发依赖。
就是说是在项目开发的时候,用的翻译器、打包工具、构建工具等等
ps: 默认 babel 不认识 ... 语法 ,会报错,要装插件,让 babel 识别更多的语法
babel 的插件在 npm 库中都叫做 babel-plugin-***
淘宝 NPM 镜像: https://npm.taobao.org/
4 装插件 npm install --save-dev @babel/plugin-syntax-object-rest-spread
更改 .babelrc 文件,告诉 babel 我们要求你使用插件:
5 现在可以用 babel 命令进行翻译
babel 02.js -o 0200.js
二 const 和 let
2.1 const 阮一峰的博客
const声明一个只读的常量。一旦声明,常量的值就不能改变。通常用 const 定义函数。
函数的定义一般来说都是不变的,所以今后的函数一律用 const 定义
const sum = function(a,b){
return a + b;
}
console.log(sum(2,3));
const A = 12;
A = 8; // 报错
一般来说所有字母要大写
2.2 let
let 用来定义块级作用域变量。它的用法类似于 var,但是所声明的变量,只在 let 命令所在的代码块内有效。
所谓的块级作用域指的是大括号、所有的语句体。
{
var a = 1;
}
console.log(a); //能够输出1
{
let b = 2;
}
console.log(b); //报错
var定义的变量出了 { } 依然有定义,但是 let 出了 { } 没有定义了
今后,我们的所有的循环变量将用let来定义:
需要注意:
1) 不管是 let 还是 const,都没有了变量声明的提升;
console.log(m); //报错,没有变量声明的提升;
let m = 100;
2) 不管是 let 还是 const,babel 一律翻译为 var。
三 变量的自动解构和剩余参数
3.1 自动解构
只有数组和对象能够自动解构。
ES6中允许从数组中提取值,按照对应位置,对变量赋值。对象也是一样的。
数组的解构 |
对象的解构 |
var [a,b,c] = [1,2,3]; console.log(a); console.log(b); console.log(c); |
这里是 { } |
对象的解构往往用在函数的形参列表中,调用函数的时候,传的对象(实参)就能够自动解构。
1 function People({name,age,sex,yuwen,shuxue,yingyu}){
2 this.name = name;
3 this.age = age;
4 this.sex = sex;
5 this.yuwen = yuwen;
6 this.shuxue = shuxue;
7 this.yingyu = yingyu;
8 }
9 var xiaoming = new People({
10 "name" : "小明",
11 "age" : 12,
12 "sex" : "男",
13 "yuwen" : 34,
14 "shuxue" : 44,
15 "yingyu" : 66
16 });
17
18 console.log(xiaoming);
3.2 剩余参数
在 c 变量之前加上...运算符,表示 c 现在接受所有剩余的参数
需要注意的事情是:... 只能出现在最后一项 ,下面写法是错的
var [a,...b,c] = [1,2,3,4,5,6,7];
let {x, y, ...z} = {x:1, y:2, a:3, b:4};
console.log(x); // 1
console.log(y); // 2
console.log(z); // {a:3, b:4 }
let n = {x,y,...z};
console.log(n); // {x:1, y:2, a:3, b:4}
3.3 强制解构
在数组前面加上 ... 运算符,表示强制解构。这个数组将变为零散量
1 var arr = [1,3,32];
2 console.log(...arr); // 1 3 32
3
4 var str = [...arr];
5 console.log(str); // [ 1 3 32 ]
... 运算符也可以作用于对象,通常用于一个情况:创建 obj1 的副本,仅仅改变 obj1 的某一(些)个属性
1 var obj1 = {
2 "a" : 1,
3 "b" : 2,
4 "c" : 3
5 };
6
7 var obj2 = {
8 ...obj1 ,
9 "b" : 8
10 };
11
12 console.log(obj2);
运行结果:
强制解构还可以用于类数组对象,可以将类数组对象变为真的数组
1 const fun = function(){
2 //下面的语句是一个奇淫技巧,是最快的将类数组对象变为数组的方法
3 var arr = [...arguments];
4 console.log(arr); //[ 1, 2, 3, 4, 5, 6, 7, 8 ]
5 console.log(Array.isArray(arr)); //true
6 }
7 fun(1,2,3,4,5,6,7,8);
如果用 babel 解构对象,需要安装 babel 的插件 babel-plugin-transform-object-rest-spread
四 数组的新方法
4.1 forEach 遍历数组
4.2 map()
map() 返回一个新的数组,新数组的每一项是原数组的映射
例:是创建一个数组,每一项都是原来的数组的两倍
var arr = [12,432,2,25,6];
var newArr = arr.map(function(item){
return item*2;
});
console.log(newArr);
注意:map() 出的数组,一定和原数组长度相同!
函数里面的的return就是新数组中这一项的数值
4.3 filter()
例:从一个数组中,过滤一些项组合成新数组,此时使用 filter() 函数
var arr = [12,432,2,25,6];
var arr2 = arr.filter(function(item){
return item %2 == 0;
});
console.log( arr2); // [ 12, 432, 2, 6 ]
filter() 中有一个函数,这个函数 return 为 true 的项会被加入到新的数组中
例:再比如从一个数组中,提取所有及格组合成为新数组
var arr = [
{"name":"小明" , "fenshu" :66},
{"name":"小红" , "fenshu" :16},
{"name":"小强" , "fenshu" :26},
{"name":"小刚" , "fenshu" :86}
];
var arr2 = arr.filter(function(item){
return item.fenshu >= 60;
});
console.log(arr2);
结果:
4.4 reduce()
reduce 表示迭代遍历,每一项的遍历都可以使用遍历上一项的时候的结果。
reduce可以理解为“降阶”。
reduce里面的函数有两个参数,分别是a、b。
我们来探究 a、b 什么意思。所以我们直接输出a:
var arr = ["白板","幺鸡","二条","三万","四筒"]; arr.reduce(function(a,b){ console.log(a); }); |
var arr = ["白板","幺鸡","二条","三万","四筒"]; arr.reduce(function(a,b){ console.log(b); }); |
少一项 |
reduce的机理:
l a 就表示遍历前一项的时候 return 的值,b 表示这一项的值。
l 系统会自动从下标为1的项开始遍历,遍历下标为1的项的时候,a 的值是第0项。
l 最后的一项的 return,就是总 return。
4.5 综合运用 map() , filter() , reduce() , 解构 (重要)
例:
var xiaoming = { "name" : "小明", "age" : 12, "sex" : "男", "friends" : [ { "name" : "小红", "age" : 13 }, { "name" : "小强", "age" : 14 }, { "name" : "小刚炮", "age" : 18 } ] }
题目1: 不允许更改小明,返回一个新对象,这个对象和小明相同,仅让小明的年龄变为 15岁
题目2:不允许更改小明,让小强的 age 变为 12
var xiaoming1 = {
...xiaoming, // 解构
'friends': xiaoming.friends.map(function(item){
if(item.name =='小强'){
return {
...item, // 解构
'age': 22 // 修改为 22
}
}
return item;
})
}
console.log(xiaoming1);
题目3: 不允许更改小明,让小明只有 15 岁以下的朋友
var xiaoming1 = {
...xiaoming,
'friends': xiaoming.friends.filter(function(item){
return item.age < 15; // 条件 年龄小于15岁
})
}
题目4:不允许更改小明,小明增加一个朋友, 老王,29岁
var xiaoming1 = {
...xiaoming,
'friends': [...xiaoming.friends,{
'name': '老王',
'age' : 29
}]
}
题目5:不允许更改小明,增加一个朋友,并且自动编号
在题目上,给每个 friends 添加 id
var xiaoming1 = {
...xiaoming,
'friends' : [
...xiaoming.friends,
{
'id' : xiaoming.friends.reduce(function(a,b){
return a.id > b.id ? a : b; // 返回 id 大的一个
}).id + 1, // +1
'name' : '老王',
'age' : 29
}
]
}
不更改原来的对象,返回一个新对象,新对象是原来对象的增、删、改某些属性,这叫做函数式编程,也叫作兰姆达式编程
删除用 filter
改变用 map
增加用 ...
作业:
var canting = {
"name" : "全聚德",
"cai" : {
"liangcai" : [
{
"name" : "凉拌西红柿",
"price" : 15
},
{
"name" : "拍黄瓜",
"price" : 18
}
],
"recai" : [
{
"name" : "宫保鸡丁",
"price" : 25
},
{
"name" : "红烧肉",
"price" : 45
},
{
"name" : "辣子鸡",
"price" :15
}
]
}
}
// 宫保鸡丁 不卖了
var c = {
...canting,
'cai' : {
...canting.cai,
'recai' : canting.cai.recai.filter(function(item){
return item.name != '宫保鸡丁';
})
}
}
// 宫保鸡丁 更改价格
var c = {
...canting,
'cai' : {
...canting.cai,
'recai' : canting.cai.recai.map(function(item){
if(item.name == '宫保鸡丁'){
return {
...item,
'price' : 30
}
}
return item;
})
}
}
// 增加一个新菜:红烧茄子,19元
var c = {
...canting,
'cai' : {
...canting.cai,
'recai' : [...canting.cai.recai,{
'name' : '红烧茄子',
'price' : 19
}]
}
}
// 售价 20 以上的热菜都不卖了
var c = {
...canting,
'cai' : {
...canting.cai,
'recai' : canting.cai.recai.filter(function(item){
return item.price <= 20
})
}
}
console.log(JSON.stringify(c)); // console.log(c) 不能全部显示出来
//学习这个很关键,比如react的组件中有state(状态):
this.state = {
a : 1,
b : [5,6,7,8],
c : 3
};
//修改的时候,不能更改原来的state。比如我们要把9加入到b属性中,正确:
this.setState({
b : [...this.state.b , 9]
});
4.6 includes() 方法
Array.prototype.includes 方法返回一个布尔值,表示某个数组是否包含给定的值。
之前我们判断数组中是否存在一项,此时用 indexOf() != -1(IE8开始兼容)。如果要IE6、7兼容,必须一项一项遍历比较。
ES6中,有了更简单的比较方法
注意,includes是全等比较,带着类型比较的 7 ‘7’
4.7 Array.from() 方法
Array.from 方法用于将类数组转为真正的数组
结果:
五 对象的改变
5.1 省略 v
当一个对象的 k、v 相同(k 的名字和 v 的变量名相同),此时可以省略v
比如下面有三个变量a、b、c,要作为一个对象的属性名a、b、c,同时值也是1、2、3。
因为k、v一致,此时就可以省略v
结果:
注意,省略 v 的时候,k 不能有引号!
5.2 对象的方法现在可以简写
5.3 Object.keys() 和 Object.values()
Object.keys() 返回对象的键名数组;
Object.values() 返回对象的值数组;
结果:
5.4 Object.is()
ES5 比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。
它们都有缺点,前者会自动转换数据类型,后者的 NaN 不等于自身,以及+0等于-0。
JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等
5.5 Object.assign()
Object.assign 方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
结果:
注意 Object.assign() 可以有无限个参数,但是只会更改第一个参数对象
5.6 对象中键加方括号 -- 动态键
var sex = '女';
if(sex == '男'){ // 值判断
var k = '身高';
} else {
k = ' 视力';
}
var obj = {
'name': 'rose',
'sex' : sex,
[k] : 'xxx' // 动态键
}
console.log(obj);
六 函数的改变
6.1 箭头函数
下面的sum就是标准的箭头函数,省略掉了function这个关键字:
=>是一个完整的运算符,之间不能有空格
如果函数体内只有一行语句,可以省略 {} 和 return
反过来,如果函数体内有多条语句,此时必须写 {} 和 return 单词
箭头函数的美,最能体现在连续箭头。当外层函数被调用的时候,将返回内层的函数。调用的时候可以加两层圆括号
箭头函数中的 this 是定义时所处的上下文,和如何调用无关!
比如下面有一个 obj 对象,这个对象的 b 方法是用箭头函数写的。这个箭头函数所在的最外层函数体是 window 域。
所以 this 不管 b 函数如何被调用,一律是 window 对象
var a = 9;
var obj = {
a : 1 ,
b : () => { // 箭头
console.log(this.a);
}
}
obj.b(); //9 这里不能用 node 解析, window 对象
甚至call、apply失效:
this 在箭头函数中是固定的,这个性质是我们应该防止的、加以警惕的;而不是利用的
箭头函数有几个使用注意点。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
6.2 bind()
bind表示给一个函数定死上下文,而无论它如何被调用。
比如下面有一个函数 fun,函数体输出 this.a。
我们在后面有一个 .bind() 语句,彻底将 fun 函数的上下文定死了,就是 obj 对象。
无论 fun 函数如何被调用,一律上下文是 obj 对象。
function fun(){
console.log(this.a);
}
//这是一个对象
var obj = {
a : 233 ,
b : 886
}
//这是另一个对象
var another = {
a : 6666666666666
}
//定死上下文为obj对象
fun = fun.bind(obj);
fun(); //233
fun.call(another); //233,call失效了
fun.apply(another); //233,apply失效了
bind 和 call 和 apply 有什么区别?
l bind 不调用函数,call 和 apply 会调用函数。
l bind 能绑死上下文,call 和 apply 是临时的。
6.3 默认参数
在形参列表中可以加等号运算符,表示参数的默认参数,当我们没有传入这个参数的时候,
将自动使用这个默认参数
const mianji = (r , pi = 3.14) => {
return pi * r * r;
}
console.log(mianji(10 , Math.PI)); //传了第二个参数,就是用第二个参数
console.log(mianji(10)); //没有第二个参数,将用默认的3.14
七 字符串, 正则改变
``是新增的定界符,可以和 ${变量} 使用,减少连字符的使用:
八 类的改变
现在可以用 class 关键字来定义一个类,语法:
虽然增加了 class 关键字,但是 JS 中还是没有类!JS 中仍然是简单的“基于对象”原型链的模式来模拟类的。
也就是说,机理没有变化!
ES6 中简化了类的继承:
class People{
constructor(name , age , sex){
this.name = name;
this.age = age;
this.sex = sex;
}
changge(){
console.log("我是一个" + this.name + "今年" + this.age + "岁啦!!");
}
}
class Student extends People{
constructor(name , age , sex , xuehao , banji){
super(name , age , sex); //调用超类的构造器
this.xuehao = xuehao;
this.banji = banji;
}
kaoshi(){
console.log(`${this.name}在考试`);
}
}
var xiaohua = new Student("小花",12,"女",10001,"1班");
xiaohua.changge();
xiaohua.kaoshi();
九 promise 对象 未完。。。