ES6中对象的简化写法
ES6允许大括号里面直接写入变量和函数,作为对象的属性和方法。
例:
let nickname = '果粒陈';
let myNickName = function(){
console.log("我的昵称是果粒陈");
}
const person = {
nickname,
myNickName,
}
console.log(person.nickname);//果粒陈
console.log(person.myNickName());//我的昵称是果粒陈
还有方法声明的简化:
const person = {
nickname,
myNickName,
/*之前:
improve: function(){
console.log("提高能力");
},
*/
//简化后
improve(){
console.log("提高能力");
},
}
ES6箭头函数以及声明特点
ES6允许使用=>
定义函数
声明和调用
//声明一个函数
//()里写参数
let fn = (a,b) => {
return a + b;
}
//调用函数
let result = fn(1,2);
console.log(result);//3
声明特性
this是静态的,this始终指向函数声明时所在作用域下的this值
function getName(){
console.log(this.name);
};
let getName2 = () => {
console.log(this.name);
};
window.name = '果粒陈';
const person = {
name : "guolchen",
}
//直接调用
getName();//果粒陈
getName2();//果粒陈
//call方法调用
getName.call(person);//guolichen
getName2.call(person);//果粒陈
不能作为构造函数实例化对象
不能使用arguments变量
箭头函数的简写
1)省略小括号。【当形参有且只有一个的时候】
/*let add = (n) => {
return n+n;
} 可以省略为如下
*/
let add = n => {
return n+n;
}
console.log(add(9));//18
2)省略大括号【当代码体只有一条语句的时候】此时return必须省略,而且语句的执行结果就是函数的返回值
/*let pow = (n) => {
return n*n;
}; 可以省略为如下
*/
let pow = (n) => n*n;
//let pow = n => n*n;
console.log(pow(9));//81
箭头函数的实践与应用场景
需求1:点击div 2s后颜色变成粉色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>箭头函数实践</title>
<style>
div{
width: 200px;
height: 200px;
background-color: #58a;
}
</style>
</head>
<body>
<div id="ad"></div>
<script>
let ad = document.getElementById('ad');
ad.addEventListener("click",function(){
setTimeout(() => {
this.style.background = 'pink';
},2000);
})
</script>
</body>
</html>
需求2:从数组中返回偶数的元素
const arr = [1,6,9,10,100,25];
//以前:
// const result = arr.filter(function(item){
// if(item % 2 ===0){
// return true;
// }else{
// return false;
// }
// });
const result = arr.filter(item => {
if(item % 2 ===0){
return true;
}else{
return false;
}
})
//还可以简写为 const result = arr.filter(item => item % 2 === 0);
console.log(result);//[6,10,100]
综上,箭头函数适合与this无关的回调,比如定时器、数组的方法回调。
箭头函数不适合与this有关的回调,比如dom元素的事件回调、对象的方法【不适合,不是不能】。
函数参数的默认值设置
ES6允许给函数参数赋初始值
1、形参的初始值。具有默认值的参数,一般位置要靠后
function add(a, b, c = 10){
return a+b+c;
}
let result = add(1,2,);
console.log(result);//13
2、与解构赋值结合
//可以给属性赋初始值
//function connect({host="127.0.0.1",username,password,port}){
function connect({host,username,password,port}){
console.log(host);
console.log(username);
console.log(password);
console.log(port);
}
connect({
host:'localhost',
username:'root',
password:'root',
port:3306
})
rest参数
ES6中引入rest参数,用于获取函数的实参,用来代替arguments
//ES5获取实参的方式
function date(){
console.log(arguments);
}
date('白芷','阿娇','思慧');//对象.....
//rest参数
function date(...args){
console.log(args);
}
date('白芷','阿娇','思慧');//数组["白芷","阿娇","思慧"]
rest参数必须要放到参数最后。比如:
function fn(a,b,...args){
console.log(a);
console.log(b);
console.log(args);
}
fn(1,2,3,4,5,6);
扩展运算符
扩展运算符的介绍
扩展运算符(...
)能将数组转换为逗号分隔的参数序列。
//声明一个数组。。。
const tfboys = ['易烊千玺','王源','王俊凯'];
//声明一个函数
function chunwan(){
console.log(arguments);
}
chunwan(...tfboys);//等同于:chunwan('易烊千玺','王源','王俊凯')
扩展运算符的应用
1、数组的合并
const kuaizi = ['王太丽','肖央'];
const fenghuang = ['曾毅','玲花'];
//const zuixuan = kuaizi.concat(fenghuang);
const zuixuan = [...kuaizi,...fenghuang];
console.log(zuixuan);//['王太丽', '肖央', '曾毅', '玲花']
2、数组的克隆
const sanzhihua = ['E','G','M'];
const sanyecao = [...sanzhihua];
console.log(sanyecao);// ['E', 'G', 'M']
3、将伪数组转为真正的数组
<div></div>
<div></div>
<div></div>
<script>
const divs = document.querySelectorAll('div');
const divArr = [...divs];
console.log(divArr);//[div, div, div]
</script>
for…of循环
//声明一个数组
const xiyou =['唐僧','孙悟空','猪八戒','沙僧'];
// 使用for...of遍历数组
for(let v of xiyou){
console.log(v);
}
for...of
与for-in的区别:
for...of
保存的是数组的键值
for...in
保存的是数组的键名
以上例子用for…in遍历:
//声明一个数组
const xiyou =['唐僧','孙悟空','猪八戒','沙僧'];
// 使用for...of遍历数组
for(let v in xiyou){
console.log(v);
}
迭代器应用-自定义遍历对象
遍历对象属性【输出属性里的东西】
//需求,遍历这个对象,每次返回banji.stus中的一个/
const banji = {
name: "火箭班",
stus: [
'xiaoming',
'xiaohua',
'xiaohuang',
'xiaolv',
'xiaolan'
],
[Symbol.iterator]() {
//索引变量
let index = 0;
let _this = this;
return {
next: function () {
if (index < _this.stus.length) {
const result = {
value: _this.stus[index],
done: false
}
index++;
return result;
}else{
return{value:undefined,done:true}
}
}
};
}
}
for (let v of banji) {
console.log(v);
}
用箭头函数的方式
【区别在next那里,输出结果同上】
<script>
const friend = {
name:"good",
stus:[
'xiaoli',
'xiaochen',
'xiaoluo',
'xiaosu',
'xiaoshi'
],
[Symbol.iterator] () {
let index = 0;
return {
next : () => {
if(index < this.stus.length){
const result = {
value:this.stus[index],
doce:false
}
index++;
return result;
}else{
return {value:undefined,done:true};
}
}
}
}
}
for(let v of friend){
console.log(v);
}
</script>
遍历对象【输出对象中的属性】
const friend = {
name:"good",
stus:[
'xiaoli',
'xiaochen',
'xiaoluo',
'xiaosu',
'xiaoshi'
],
[Symbol.iterator] () {
let index = 0;
const keys = Object.getOwnPropertyNames(this);
return {
next () {
const _this = Object.assign(friend);
return index < _this.stus.length?{value:_this[keys[index++]],
done:false}:{value:undefined,done:true};
}
}
}
}
for(const v of friend){
console.log(v);
}
生成器
生成器函数声明与调用
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。
异步编程以前用的是纯回调函数
<script>
//声明
function * gen(){
console.log("hello generator");
}
let iterator = gen();
//console.log(iterator);
//调用。需要用next来调用
iterator.next();
</script>
在生成器函数可以出现yield语句,yield算是函数代码的分隔符,把函数代码切分成几块。比如这里三个分隔符,产生四块代码
function *gen(){
console.log(111);
yield '吧啦啦啦啦~';
console.log(222);
yield '小魔仙~';
console.log(333);
yield '呜啦啦啦啦';
console.log(444);
}
let iterator = gen();
iterator.next();//111
iterator.next();//222
iterator.next();//333
iterator.next();//444
function *gen(){
yield '吧啦啦啦啦~';
yield '小魔仙~';
yield '呜啦啦啦啦';
}
//遍历
for(let v of gen()){
console.log(v);
}
以上遍历输出如下:
生成器函数参数
生成器函数可以传入参数
function * gen(arg){
console.log(arg);
yield 111;
yield 222;
yield 333;
}
let iterator = gen('AAA');
console.log(iterator.next());
next方法可以传入实参,这个实参就是yield语句整个的返回结果
生成器函数可以传入参数
function * gen(arg){
console.log(arg);
let one = yield 111;
console.log(one);
let two = yield 222;
console.log(two);
let three = yield 333;
console.log(three);
}
let iterator = gen('AAA');
console.log(iterator.next());
console.log(iterator.next('bbb'));//第一次调用next将作为第一个yield语句整体的返回结果
console.log(iterator.next('ccc'));
console.log(iterator.next('ddd'));
生成器函数实例
生成器函数是专门针对于异步编程的新的解决方案
JS本身是单线程的,异步是单线程的。
异步编程:文件操作、网络操作(Ajax、request)、数据库操作
案例1:
【以定时器的案例演示生成器函数在异步编程中的表现】
1s后控制台输出111 2s后输出222 3s后输出333
定时器嵌套实现【回调地狱】
setTimeout(() => {
console.log(111);
setTimeout(() => {
console.log(222);
setTimeout(()=>{
console.log(333);
})
}, 2000);
}, 1000);
用生成器
function one(){
setTimeout(()=>{
console.log(111);
iterator.next();
},1000)
}
function two(){
setTimeout(()=>{
console.log(222);
iterator.next();
},2000)
}
function three(){
setTimeout(()=>{
console.log(333);
iterator.next();
},3000)
}
function * gen(){
yield one();
yield two();
yield three();
}
//调用生成器函数
let iterator = gen();
iterator.next();
案例二
【模拟获取】
获取用户数据、订单数据、商品数据(有先后顺序)
function getUsers(){
setTimeout(() => {
let data = '用户数据';
//调用next方法并且将数据传入
iterator.next(data)
}, 1000);
}
function getOrders(){
setTimeout(() => {
let data ='订单数据';
iterator.next(data);
}, 1000);
}
function getGoods(){
setTimeout(() => {
let data ='商品数据';
iterator.next(data);
}, 1000);
}
function * gen(){
let users = yield getUsers();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}
let iterator = gen ();
iterator.next();
Promise实践
【Promise解决回调地狱的演示】
需求:读取三个文件,先读取为学再读取插秧诗再读取观书有感最后把三个内容合在一起进行输出
const fs = require("fs");
const { resolve } = require("path");
const p = new Promise((resolve, reject) => {
fs.readFile("./resources/为学.md", (err, data) => {
resolve(data);
});
});
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/插秧诗.md", (err, data) => {
resolve([value, data]);
});
});
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile("./resources/观书有感.md", (err, data) => {
//压入
value.push(data);
resolve(value);
});
})
}).then(value=>{
console.log(value.join('\r\n'));
});
class类
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法。
class声明类
ES5
class Phone{ //构造方法【名字不能修改,自动执行】 constructor(brand,price){ this.brand = brand; this.price = price; } //方法必须使用该语法,不能使用ES5的对象完整形式 call(){ console.log("我可以打电话!!"); } say(){ console.log("我可以说话!"); } } ```
类的静态成员
function Phone(){ } Phone.name = '手机';//属于函数对象,并不属于实例对象,这种称为静态成员 //属于函数对象,并不属于实例对象.这种称为静态成员 Phone.change = function(){ console.log("我可以改变世界"); } let nokia = new Phone(); console.log(nokia.name);//undefined //nokia.change();//Uncaught TypeError: nokia.change is not a function //实例对象是实例对象,函数对象是函数对象,他们的属性是不同的。实例对象和构造函数原型对象相同。如下 Phone.prototype.size = '5.5inch'; console.log(nokia.size); ```
以上是ES5中,以下是ES6
//在面向对象中,静态成员属于类,不属于实例对象 class Phone{ static name = '手机'; static change(){ console.log("我可以改变世界"); } } let nokia = new Phone(); console.log(nokia.name);//undefined console.log(Phone.name);//手机 ```
类继承
构造函数继承
//手机
function Phone(brand,price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call =function(){
console.log("我可以打电话!");
}
//智能手机
function SmartPhone(brand,price,color,size){
//this指向SmartPhone
Phone.call(this,brand,price);
this.color = color;
this.size = size;
}
//设置子级构造函数的原型
SmartPhone.prototype = new Phone;
SmartPhone.prototype.constructor = SmartPhone;
//声明子类的方法
SmartPhone.prototype.photo = function(){
console.log("我可以拍照");
}
SmartPhone.prototype.playGame =function(){
console.log("我可以玩游戏");
}
const chuizi = new SmartPhone('锤子',2499,'黑色','5.5inch');
console.log(chuizi);
类继承
class Phone {
//构造方法
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
//父类的成员属性
call() {
console.log("我可以打电话!!");
}
photo() {
console.log("我可以拍照");
}
}
class SmartPhone extends Phone {
//构造方法
constructor(brand, price, color, size) {
super(brand, price);//Phone.call(this,brand,price)
this.color = color;
this.size = size;
}
playGame() {
console.log("玩游戏");
}
wechat() {
console.log("玩微信");
}
}
const huawei = new SmartPhone('huawei', 2499, '黑色', '5inch');
console.log(huawei);//SmartPhone {brand: 'huawei', price: 2499, color: '黑色', size: '5inch'}
huawei.call();
huawei.photo();
huawei.playGame();
huawei.wechat();
子类对父类方法的重写
例如以上例子中重写父类的call方法:
class Phone {
//构造方法
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
//父类的成员属性
call() {
console.log("我可以打电话!!");
}
photo() {
console.log("我可以拍照");
}
}
class SmartPhone extends Phone {
//构造方法
constructor(brand, price, color, size) {
super(brand, price);//Phone.call(this,brand,price)
this.color = color;
this.size = size;
}
playGame() {
console.log("玩游戏");
}
wechat() {
console.log("玩微信");
}
//重写父类的call方法
call(){
console.log("我可以视频通话");
}
}
const huawei = new SmartPhone('huawei', 2499, '黑色', '5inch');
huawei.call();//我可以视频通话
class中的set、get
set
和get
在ES5
中也用过,可以对对象的属性进行方法的绑定。比如:添加一个get方法,当对某一个属性进行获取时,执行get对应的函数;当对某一属性进行设置时,执行set对应的函数。在class中也有这样的特性。
class中set、get使用场景:
get
通常来对对象的动态的属性进行一个封装;
set
可以添加更多的控制、判断
class Phone{
set price(newVal){
console.log("价格属性被修改了");
}
get price(){
console.log("价格属性被读取");
return 'aaa';
}
}
//实例化对象
let s = new Phone();
console.log(s.price);
s.price = 'free';//价格属性被修改了
ES6中的数值扩展
Number.EPSILON
Number.EPSILON 是 JavaScript 表示的最小精度
EPSILON 属性的值接近于2.2204460492503130808472633361816E-16
该数常用来浮点数的运算上,对精度做一个设置
console.log(0.1+0.2);//0.30000000000000004
//解决
function equal(a, b) {
if (Math.abs(a - b) < Number.EPSILON) {
return true;
} else {
return false;
}
}
console.log(0.1+0.2 === 0.3);//false
console.log(equal(0.1 + 0.2, 0.3));//true
二进制和八进制
//二进制
let b = 0b1010;
//八进制
let o = 0o777;
//十进制
let d = 100;
//十六进制
let x = 0xff;
Number.isFinite
Number.isFinite 检测一个数值是否为有限数
console.log(Number.isFinite(100));//true
console.log(Number.isFinite(100/0));//false
console.log(Number.isFinite(Infinity));//false
Number.isNaN
Number.isNaN 检测一个数值是否为 NaN
【ES5中isNaN是一个单独的函数,在ES6中把它作为了Number的方法。】
console.log(Number.isNaN(123)); //false
Number.parseInt Number.parseFloat字符串转整数
console.log(Number.parseInt('5211314love'));//5211314
console.log(Number.parseFloat('3.1415926神奇'));//3.1415926
Number.isInteger 判断一个数是否为整数
console.log(Number.isInteger(5));//true
console.log(Number.isInteger(2.5));//false
Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(3.5));//3
Math.sign 判断一个数到底为正数 负数 还是零
console.log(Math.sign(100));//1【代表为正数】
console.log(Math.sign(0));//0【代表为0】
console.log(Math.sign(-1000));//-1【代表为负数】
对象方法的扩展
Object.is
Object.js
比较两个值是否严格相等,与===
行为基本一致。Object.js
与===
的不同之处:NaN
、
console.log(Object.is(120,120));//true
console.log(Object.is(120,110));//false
console.log(Object.is(NaN,NaN));//true
console.log(NaN === NaN);//fasle
Object.assign
Object.assign
对象的合并,将源对象的所有可枚举属性,复制到目标对象
它用来做配置的合并,非常合适
const config1 = {
host:'localhost',
port:3306,
name:'root',
pass:'root',
test:'test'
};
const config2 = {
host:'http://www.cxj.com',
port:33060,
name:'cxj.com',
pass:'abc',
test2:'test2'
}
//config2会覆盖config1重名的属性
console.log(Object.assign(config1,config2));
proto、setPrototypeOf、getPrototypeof
_proto_、setPrototypeOf、getPrototypeof
可以直接设置对象的原型
const school = {
name: '果粒陈'
}
const cities = {
xiaoqu: ['北京', '上海', '广州', '深圳']
}
Object.setPrototypeOf(school, cities);
console.log(school);
console.log(Object.getPrototypeOf(school));
模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
模块化的好处
模块化的优势有几下几点:
- 防止命名冲突
- 代码复用
- 高维护性
模块化规范产品
ES6之前的模块化规范有:
- CommonJS => NodeJS、Browserify
- AMD => requireJS
- CMD => seaJS
ES6模块化语法
模块功能主要由两个命令构成:export和import
export
命令用于规定模块的外接口import
命令用于输入其他模块提供的功能
浏览器使用ES6模块化引入模块方式一
1、以下就是一个模块
2、想对外暴露一些数据,让外部模块可以使用这个模块的一些变量或者函数。【可以使用export命令来暴露】
【分别暴露】
3、引入模块
【通用方式引入】
<script type = "module">
//引入 39-m1.js 模块内容
import * as m1 from "./39-m1.js";
console.log(m1);
</script>
ES6模块暴露数据语法汇总
【统一暴露】
//统一暴露
let school = '果粒陈';
function good(){
console.log("我们可以让你变得优秀");
}
export{school,good}
【默认暴露】
//默认暴露
export default{
school:'CXJCXJ',
change:function(){
console.log("我们可以改变你");
}
}
ES6引入模块数据语法汇总
【解构赋值形式】
//导入分别暴露
import {school,teach} from "./39-m1.js";//这时候可以直接使用school、teach
//导入统一暴露
import {school as cxj,good} from "./39-m2.js";//这里school重名了,可以起别名
//导入默认暴露
import {default as m3} from "./39-m3.js";
console.log(school);
console.log(teach);
console.log(cxj);
console.log(good);
console.log(m3);
【简便形式】只能针对默认暴露
import m3 from "./39-m3.js";
console.log(m3);//输出结果同上输出m3的结果
浏览器使用ES6模块化方式二
前面都是使用script标签写import语句。这样会使文件的体积变大。所以可以把import单独写入到一个文件中。这个文件可以当做整个JS代码的入口
step1:在html文件中引入入口文件
<script src="./39-app.js" type="module"></script>
step2:在入口文件中引入模块
babel对ES6模块化代码转换【项目中的应用】
Babel中文网
step1:
1、安装工具:
- babel-cli【babel命令行工具】
- babel-preset-env【预设包:能够把最新的ECMAScript的特性做一个转换,转化为ES5的语法】
- broeserify【打包工具】打包工具还有webpack,项目中其实用webpack
2、对文件进行转换
3、打包
4、引入打包好的js,就完成了