本人小白,欢迎指正
一、变量let和const
var:
- 可以重复声明
- 可以进行变量提升(即将声明提升到最前面)
let:
- 不可以重复声明
- 块级作用域
- 不可以变量提升
const:
- 不可以重复声明
- 块级作用域
- 声明后不可以进行修改
- 声明时必须初始化
- const声明的数组内容可以被修改,所以常规使用const进行数组变量的声明
二、解构赋值
1.什么是解构?:es6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
2.数组解构赋值:
语法:
let [a,b,c] = [1,2,3];
console.log(a,b,c);
3.对象解构赋值:
语法:
let{a,b} = {
a:'aa',
b:'bb'
};
console.log(a,b);
顺序:数据解构按照对应位置关系,但是对象解构变量没有顺序,变量必须与属性同名,才能解构成功。
注意:let和const声明的变量不可以进行解构赋值!
4.字符串的解构赋值:
语法:
let[a,b,c,d] = 'hello';
console.log(a,b,c,d);//h e l l
5.数值和布尔值的解构赋值:
6.函数的解构赋值:
语法:
function fun([x,y]){
console.log(x+y);
}
fun([1,2]);//实参
7.解构的用途:
- 交换变量的值
- 从函数返回多个值(这样就可以快速调用一些数据)
- 函数传参
- 提取json数据(解构对提取json尤其有用)
- 函数参数默认值(es6允许函数的参数设置默认值)
8.函数默认初始值:
一般用法:(直接将默认值写在形参之后)
function fun(x,y ='world'){
console.log(x,y);
}
与解构配合使用:
function fun({x,y=5}={}){
console.log(x,y);
}
注意:
1. 函数的length属性是函数的形参个数!
2. 一般带有默认值得参数要放在最后!(潜规则)
三、模板字符串
1.JavaScript写法:
'He is <b>'+person.name+'</b>'+'and we wish to know his'+person.age+' . That is all.'
2.模板字符串写法:
`He is <b>${person.name}</b> and we wish know his ${person.age} . That is all.`
这种写法减免了很多的繁杂的工作!
如果需要使用' ` ',则可以进行转义!
当然,模板字符串也可以不引入变量,可以简单的使用!
四、对象的简化写法
1.ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法在Vue中经常使用,这样写会使得编写更加的简洁!
五、箭头函数
1.ES6允许使用「箭头」(=>)定义函数
声明函数的两种方法:
let fn = function(){
}
let fn = (a,b) => {
return a+b;
}
2.this是静态的,this始终指向函数声明时所在作用域下的this的值
3.箭头函数的this值是静态的,始终指向函数声明时所在作用域下的this的值
例如:
//常规声明
function getName() {
console.log(this.name);
}
//箭头函数
let getName2 = () => {
console.log(this.name);
}
window.name = '周师扬';
const school = {
name: 'zsy'
}
getName();//周师扬
getName2();//周师扬
getName.call(school);//zsy
getName2.call(school);//周师扬
4.箭头函数不能作为一个构造函数实例化对象!
5.箭头函数不能使用arguments变量:
典型错误用法:
let fn = () =>{
console.log(arguments)
}
fn(1,2,3);//将会报错,箭头函数不支持arguments参数
6.箭头函数的简写:
- 省略小括号: 当形参有且只有一个的时候
- 省略花括号: 当代码体只有一条语句的时候
7.箭头函数适合于与函数的this无关的的回调,例如:定时器,数组等的方法回调不适合于与函数的this有关的的方法的回调,建议使用function( );不适合对象内方法的定义,否则作用域可能会出现问题
六、ES6的rest参数
1.ES5中使用arguments参数进行获取函数的实参
例如:
function fn(){
console.log(arguments);//返回的是Object对象
}
2.ES5中使用rest参数进行获取函数的实参
例如:
function fn(…args){
console.log(args);//返回的是Array对象,更加便于对函数实参的处理
}
更加高级的用例:
function fn(a,b,…args){//args要放到后面
console.log(a);//1
console.log(b);//2
console.log(args);//3 4 5 6
}
fn(1,2,3,4,5,6);
七、扩展运算符
1.「 … 」能将数组转化为用逗号分隔的「参数序列」
基本用法:
const TFboys = ['王源','易烊千玺','王俊凯'];
function show(){
console.log(arguments);
}
show(…TFboys);//返回的是=>‘王源’,’易烊千玺’,’王俊凯’的字符序列
2.扩展运算符用于数组的合并
ES5用法:
const kuaizi = ['肖央','王太利'];
const fenghuang = ['曾毅','玲花'];
const zuixuan = kuaizi.concat(fenghuang);
ES6用法:
const zuixuan = […fenghuang,…kuaizi];//使用扩展运算符
3.扩展运算符用于数组的克隆
const arr1 = ['z','s','y'];
const arr2 = […arr1];//使用...进行clone
4.将伪数组转化成为真正的数组
const divs = document.querySelectorAll('div');
const divarr = [..divs];//已经转化为了真正的数组
八、Symbol
Symbol是一种标识符,是一种类型,表示独一无二的值
1.Symbol简介:
- Symbol的值是唯一的,用来解决命名冲突的问题
- Symbol的值不能与其他数据进行运算
- Symbol定义的对象属性不能使用for…in...进行循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
2.创建Symbol的两种方式:
- 直接使用Symbol进行创建:
let s1 = Symbol('zsy');
let s2 = Symbol('zsy');
console.log(s1 === s2);//false,注意这里是不相等的!
- 使用Symbol.for进行创建
let s1 = Symbol.for('zsy');
let s2 = Symbol.for('zsy');
console.log(s1 === s2);//true,这样就是相等的了!
3. Symbol的使用
使用Symbol安全的添加methods(function):
let game = {}
let methods = {
up:Symbol(),
down:Symbol()
}
game[method.up] = function(){
console.log('1');
}
game[method.down] = function(){
console.log('1');
}
在另一种情况下添加methods(内部):
let youxi = {
name:'狼人杀',
[Symbol('say')]:function(){
console.log('I can say!');
}
}
4. Symbol的内置方法,可以自己查看文档
九、迭代器
1.for…in…:遍历返回的是键名
for…of…:遍历返回的是键值
2.迭代器的工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
- 接下来不断使用next方法,指针不断向后移动直到指向最后一个数据成员
- 每调用一次方法返回一个包含value和done属性的对象(done代表是否完,为一个布尔值,如果遍历完成则为ture,否则为false)
3.注意:要自定义遍历数据的时候,要想到迭代器!
自定义遍历数据代码实例:
const stu = {
name: "zsy",
stus: [
'xiaoming',
'xiaoning',
'xiaotian',
'knight'
],
[Symbol.iterator]() {//必须要有iterator对象
let index = 0;
let _this = 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 stu) {
console.log(v);
}
十、生成器
1.生成器是一个特殊的函数,常用于异步编程
初识生成器函数:
function * gen() {//生成器函数的特殊写法,注意拥有*
console.log('hello zsy!');
}
let ite = gen();
// console.log(ite);//这是一个错误的写法,这样并不能运行生成器函数
ite.next();//这是一个正确的写法,执行语句
2.生成器函数中允许出现yield关键字(yield关键字:用于分隔代码块,每次执行两个yield中的代码)
示例:
function * gen() {
console.log('1');
yield 'I am 1';
console.log('2');
yield 'I am 2';
console.log('3');
yield 'I am 3';
console.log('4');
}
let ite = gen();
ite.next();//1
ite.next();//2
ite.next();//3
ite.next();//4
3.生成器函数可以使用for…of…进行遍历
function * gen() {
yield 'I am 1';
yield 'I am 2';
yield 'I am 3';
}
for(let v of gen()){
console.log(v);
}
//输出的结果为yield后面的语句运行的结果
//I’m 1
//I’m 2
//I’m 3
4.next函数可以传参,传的参数作为下一个yield后面的值,可以打印查看。
5.生成器函数的实例:(异步编程:有助于避免回调地狱(缩进向前延伸导致超出编辑区域不利于阅读和维护))
(使用定时器实现)
function one(){
setTimeout(()=>{
console.log(111);
ite.next();
},1000}
}
function two(){
setTimeout(()=>{
console.log(222);
ite.next();
},2000}
}
function three(){
setTimeout(()=>{
console.log(333);
ite.next();
},3000}
}
function *gen(){
yield one();
yield two();
yield three();
}
let ite = gen();
ite.next();//这样就实现了异步输出
(实现获取数据的模拟过程)
(异步符合现实生活)
function getUsers(){
setTimeout(()=>{
let data = '用户数据';
ite.next(data);
},1000)
}
function getOrders(){
setTimeout(()=>{
let data = '订单数据';
ite.next(data);
},1000)
}
function getGoods(){
setTimeout(()=>{
let data = '商品数据';
ite.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 ite = gen();
ite.next();
十一、ES6中的promise
1.promise是ES6引出的新的异步编程的解决方案,语法上promise是一个构造函数,用来封装异步操作并且可以获取其成功或失败的结果
2.简单的promise用例
const p = new Promise(function(resolve,reject){//常用resolve和reject
setTimeout(function(){
let data = '数据库中的数据';
resolve(data);//成功时的用例,返回data作为value
let err = '数据读取失败';
reject(data);//失败时的用例,返回data作为reason
},1000)
});
p.then(function(value){//常用value和reason
console.log(value);
},function(reason){
console.error(reason);
})
3.使用promise封装读取文件
实例:
const fs = require('fs');//使用node.js的require方法来引入require模块
const p = new Promise(function(resolve,reject){
fs.readFile('./demo,md',(err,data)=>{
if(err)
reject(err);//失败情况
resolve(data);//成功情况
});
});
p.then(function(value){
console.log(value.toString());
},function(reason){
console.log('读取失败!');
});
4.使用promise封装ajax
实例:
const p = new Promise((resolve,reject)=\>{//创建一个promise对象
const xhr = new XMLHttpRequest();//新建一个XMLHttpRequest对象
xhr.open(‘GET’,’https://……’);//使用GET方法
xhr.send();//发送请求
xhr.onreadystatechange = function(){//当状态改变的时候触发onchange事件
if(xhr.readyState === 4){//如果状态为4,代表请求已响应,到达了最后一个阶段
if(xhr.status >= 200 && xhr.status < 300){//200~300之间为有效区间
resolve(xhr.response);//调用response方法
}
else{
reject(xhr.status);//调用reject方法
}
}
}
});
p.then(function(value){//使用then方法进行对promise对象的状态
console.log(value);
},function(reason){
console.error(reason);//使用error在控制台进行警告
})
5.promise中的then方法详解:(promise的prototype)
- then方法的返回结果是一个promise对象
- 如果返回是一个非promise属性的(return ’zsy’),则值为zsy
- 如果返回是一个promise属性的(return new promise()),则值为下一个的resolve或者reject值
- 如果抛出错误(throw new Error(’error!’)),则值为error,自动调用reject
6.使用promise方法异步读取多个文件的内容
实例:
const fs = require('fs');//引入node.js中的fs模块
const p = new Promise((resolve, reject) => {
fs.readFile('./demo.md', (err, data) => {
resolve(data);
});
});
p.then(value => {
return new Promise((resolve, reject) => {//返回新的promise对象
fs.readFile('./demo2.md', (err, data) => {
resolve([value, data]);//合并返回结果
})
})
}).then(value => {
return new Promise((resolve, reject) => {//返回新的promise对象
fs.readFile('./demo3.md', (err, data) => {
value.push(data);
resolve(value);
})
})
}).then((value => {
console.log(value.join('\r\n'));//打印查看
}))
7.promise中的catch方法(其实就是一个语法糖)(只使用then也可以完成,只是catch可以提高代码的可读性)
用法:
p.catch(function(reason){
console.error(reason);
})
十二、集合
1.集合Set类似于数组,不过元素都是唯一的(成员元素不允许重复),内置了iterator方法,可以使用「扩展运算符」
进行遍历,也内置了一些API,可以查看文档进行学习
2.Set可以用于数组去重
let arr = [1,2,3,2,1,2,3];
let result = […new Set(arr)];
3.Set可以用于求交集、并集、差集
//交集
let arr = [1,2,3,2,1,2,3];
let arr2 = [1,2,1,1];
let result = […new Set(arr)].filter(item=\>{//filter方法的作用:使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组。
let s2 = new Set(arr2);
if(s2.has(item)){
return true;
}
else{
return false;
}
});
//并集
let union = […new Set([arr1,arr2])];
//差集
let diff = [..new Set(arr)].filter(item=>!new Set(arr2),has(item));
十三、Map
1.Map是键值对的集合,但是键不仅限于字符串,可以是各种类型的值,并且内置了iterator方法,可以使用for…of…进行遍历
简单的Map的使用方法
let m = new Map();
m.set('change',function(){
console.log(‘I am zsy.’);
});
let key = {
school:'XDU',
};
m.set(key,['南校区','北校区');
console.log(m.size);
console.log(m.get('change'));
console.log(m.get(key));
m.delete('change');
十四、class类
1.class可以声明类,作为对象的模板(其实也是一个语法糖)
简单的使用
//使用ES5的方法通过构造函数进行对象的实例化
function Phone(brand,price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function()
console.log('我可以打电话!');
}
let HuaWei = new Phone('华为',5999)
HuaWei.call();
console.log(HuaWei);
//使用ES6的class来实现对象的实例化
class Phone{
//constructor名字不能修改
constructor(brand,price){
this.brand = brand;
this.price = price
}
call(){
//方法必须使用call方法,不可以使用call:function()的用法
console.log('我可以打电话!');
}
}
let onePlue = new Phone('一加',5999);
console.log(onePlus);
2.class拥有static静态成员
用法
class Phone{
static name = '手机';
static change(){
console.log('I can change the world!');
}
}
let nokia = new Phone();
console.log(nokia.name);//Undefined
console.log(Phone.name);//手机
//说明了静态成员只属于这个类而不属于实例化对象
3.类继承
//ES5中构造函数的继承
function Phone(brand,price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function(){
console.log('我可以打电话');
}
function SmartPhone(brand,price,color,size){
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('锤子',3999);//实例化对象
console.log(chuizi);
//ES6中的类继承
class Phone{
constructor(brand,price){
this.brand = brand;
this.price = price;
}
call(){
console.log('我可以打电话!');
}
}
class SmartPhone extends Phone{//使用extends进行继承
constructor(brand,price,color,size){
super(brand,price);//使用super
}
photo(){
console.log('拍照');
}
play(){
console.log('玩游戏')
}
}
const xiaomi = new SmartPhone('小米',799,'black','4.7inch');
console.log(xiaomi);
4.子类对父类的重写
//直接在子类中写重名的父类方法即可
5.ES6中的get和set
简单用例
class Phone{
get price(){//每次调用price成员都会自定调用get方法
console.log(‘价格属性被读取!’);
return '11';//返回值就是price成员的
}
set price(newVal){//注意get方法必须有一个参数,每次更改price成员的值都会调用set方法
console.log('价格属性被修改!');
}
}
let s = new Phone();//实例化对象
console.log(s.price);//价格属性被读取!
//undefined
十五、ES6中的数值扩展
1.Number.EPSILON表示JavaScript中的最小精度(小数点后16位)
用例:
function equal(a,b){
if(Math.abs(a-b) < Number.EPSILON){
return true
}else{
return false;
}
}
console.log(0.1+0.1 === 0.3);//false
console.log(equal(0.1+0.2,0.3));//true
2.二进制和八进制
用例:
let a = 0b0101;//二进制
let b = 0o777;//八进制
let c = 100;//十进制
let d = 0xff;//十六进制
3.Number.isFinite判断是不是一个有限数
4.Number.isNaN检测一个数是否为NaN
5.Number.parseInt
Number.parseFloat 字符串转整数
6.Number.isInteger检测一个数是否为整数
7.Math.trunc将数字的小数部分抹掉
8.Math.sign判断数字是正数负数还是零
十六、ES6的对象方法扩展
1.Object.is 判断两个值是否完全相等
简单用例
console.log(Object.is(NaN,NaN));//使用对象的方法两个NaN是相等的
console.log(NaN,NaN);//使用等号判断,两个NaN是不相等的
2.Object.assign对象的合并
const config1 = {
host:'localhost',
port:3306,
name:'zsy',
pass:'zsy'
}
const config2 = {
host:'localhost2',
port:3306,
name:'root',
pass:'root'
}
console.log(Object.assign(config1,config2));//config1会被config2覆盖掉,如果有一种元素1中有但是2中没有那么会直接添加到2中
3.Object.setPrototypeof
Object.getPrototypeof进行设定原型对象和获取原型对象
十七、ES6模块化
1.有助于处理各个模块之间的冲突,易于维护,易于修改
2.ES6之前的模块化规范主要有:
1. CommonJS => NodeJS、Broeserify
2. AMD => requireJ
3. CMD => seaJS
3.模块化功能主要由两个命令构成:export和import
1)export命令用于规定模块的对外接口
2)import命令用于输入其他模块提供的功能
4.模块化的简单用例:
//三种暴露的方法
//index.html
<script type='module'>
import * as m1 from './src/js/m1.js';//使用import引入接口
import * as m2 from './src/js/m2.js';
import * as m3 from './src/js/m3.js';
console.log(m1);
console.log(m2);
</script>
//m1.js
export let school = 'XDU';//使用export暴露数据,分别暴露
export function teach(){
console.log('我是zsy!');
}
//m2.js
let school = 'zsy';
function findJob(){
console.log('hahaha');
}
export{school,findJob};//统一暴露
//m3.js
export default{//默认暴露
let school = 'XDU';
}
5.导入模块的方式
//通用的导入方式
import * as m1 from './src/js/m1.js';//使用import引入接口
import * as m2 from './src/js/m2.js';
import * as m3 from './src/js/m3.js';
//解构赋值形式
import {school,teach} from './src/js/m1.js';
import {school as guigu,findJob} from './src/js/m2.js';//as后面的作为别名,可以不引起重名的冲突
//应对默认暴露的方式,不经常使用
import {default as m3} from './src/js/m3.js';//对default进行一个别名设置,不能直接使用default
//只能针对默认暴露的简单写法,很常用
import m3 from './src/js/m3.js'
6.浏览器使用模块化的两种方式
- 使用import引入
- 建立一个入口文件然后仅直接引入入口文件
十八、ES6使用babel对模块化代码进行转换
1.安装babel,具体内容可以详细学习
简单步骤:
- 安装工具:babel-cli babel-preset-env browserify(或webpack)
- 转换:npx babel src/js -d dist/js
- 打包:npx browserify dist/js/app.js(源路径) -o dist/bundle.js(目标路径)
- 每次更新都要重新转换和打包