1.变量let
01.变量不能重复声明,会报错
02.块级作用域 在{}内执行,代码块外部无法访问
03.不存在变量提升
04.不影响作用域链(函数执行,变量寻找从内到外)
避免变量污染:
- 立即执行函数
- 创建对象
// 匿名函数,立即执行,可以避免变量污染
(function(){
var str='坚持到底';
console.log(str);
})();
// 创建对象,可以避免变量污染
var obj = {
aa:'碧血剑',
bb:'亮剑',
cc:function(){
console.log(this.bb);
}
};
obj.cc();
2.常量 const
- 一定要赋初始值
- 一般常量使用大写
- 常量的值不能修改
- 属于块级作用域
- 对于数组和对象的修改不算对常量的修改,不会报错
3.解构赋值
ES6允许一定模式对数组和对象进行解构赋值
-
数组解构
-
对象解构赋值
let { name, age, sex } = { name: '钟馗', sex: '男', ①
age: 234 };
console.log(name, age, sex);
对象的解构赋值,实质是给对象的属性值赋值,即先找到对应的同名属性,然后再赋值给对应的变量,真正赋值是属性对应的值所表示的字符串,而非属性名
let { abc: an, abd: anage, abe: ansex } = {
abc: '锴',
abd: 123,
abe: '男'
};
console.log(an, anage, ansex);
平常简写为①,即直接写对象的属性参数,不能直接写属性值,顺序无关
- 也可以单独写数组或对象中的某一项
对象解构赋值实质是给对象属性的值赋值(即)
对象的解构赋值,只和对象的属性有关,和次序无关
let {name,age,sex} = {name:'钟馗',sex:'男',age:234};
console.log(name,age,sex);
4.模板字符串 ``
- 可以直接出现换行符(单双引号中的换行会报错)
- 可以在反引号内部添加${}直接进行变量拼接,{}内可以是变量,可以是函数或者运算
ex:
5.简化对象写法
允许在花括号里边直接写入变量和函数,作为对象的属性和方法
对象内部的方法可以直接用()+{}来简写(省去:function)
6.函数参数赋值初始值
function add(a,b,c=10){ return a+b+c;}
- 赋值后,c不写实参的情况下,默认为10,
- 具有默认值的参数尽量写后边
7.rest参数
rest用于获取函数的实参,用来代替arguments,与前者不同的是获取的实参是一个数组ex:function(…aa==){}
注意:如果需要写rest参数,rest参数必须写在形参的最后
8.扩展运算符…
- 01对象中的扩展运算符(…),用来获取到参数对象中所有的能遍历的属性,复制到当前对象中,只能深copy值为基本数据类型的对象,值是引用数据类型的话为深copy;
var obj1 = {
name:'唐家三少',
age:45,
sex:'男'
};
var obj2 = {...obj1};
console.log(obj2);
8.1扩展运算符数组复制,合并,字符串转化为数组
- 01可以将数组分割成逗号分割的参数序列…arr
var arr1 = ['科比','姚明','易建联','周琦'];
//将数组转换为用到逗号分割的参数序列
console.log(...arr1); // '科比','姚明','易建联','周琦'
-02复制数组 arr2=[...arr1]
var arr2 = [...arr1];
console.log(arr2);
-03与解构赋值结合使用,如果有其他的元素,则扩展运算符须放在最后
let [kb,ym,yjl,zq] = [...arr1];
console.log('篮球明星:',kb,ym,yjl,zq);
-04 将字符串转化为数组
console.log(...'少壮不努力');//返回空格隔开的字符串
console.log([...'少壮不努力']);//返回数组["少", "壮", "不", "努", "力"]
- 数组合并
ex:
var arr1=[],arr2=[];
var arr3=[…arr1,…arr2]; - 数组克隆
var arr1=[];
var arr2=[…arr1];
9.对象操作
assign,is
- Object.assign(参数1,参数2) 合并对象,返回合并后的对象,原对象改变,把参数2复制到参数1中,如果有相同的属性,则覆盖
- Object.is() 比较两个值是否相等
console.log( Object.is('a','a')); //TRUE
console.log( Object.is({},{}) ); //false
console.log( Object.is(+0,-0) ); //false
console.log( Object.is(NaN,NaN) ); //true
-
Object.keys() 返回一个数组,数组中的元素是对象的属性名
-
Object.values() 返回一个数组,数组中的元素是对象的属性值
Object.keys() 和 Object.values() 会忽略掉属性名为symbol的元素,
如果Object.values()的参数是一个字符串,会返回各个字符组成的一个数组 -
Object.entries() 方法返回的是一个数组,里面的元素是参数对象自身的所有可以遍历属性键值对数组,会忽略symbol
-
对象的属性简写
let obj = {
name:'王昭君',
say:function(){
console.log(this.name);
}
}
obj.say();
let str = 'name';
let aa = 'say';
let obj2 = {
[str]:'鲁智深',
-
对象的方法简写
-
对象的属性可以是变量
let obj2 = {
[str]:'鲁智深',
[aa](){
console.log(this[str]);
},
['a'+'b']:'拳打镇关西',
[Symbol()]:'哈哈哈'
};
console.log(obj2);
obj2[aa]();
console.log(obj2.ab);
10.字符串操作
includes,startWith,for of
- str.includes(e);
- str.startWith(e);str.endWith(e);
// includes(参数) 返回一个布尔值,表示操作字符串中是否含有
参数字符串
let str1 = '无限山河泪';
console.log(str1.includes('河'));
// startsWith(参数) 返回一个布尔值,表示操作字符串中是否以
参数字符串开头
console.log(str1.startsWith('无限'));
// endsWith(参数) 返回一个布尔值,表示操作字符串中是否以
参数字符串结尾
console.log(str1.endsWith('河泪'));
- 字符串遍历 for …of
let str7 = '霸道总裁爱上我';
for (let st of str7) {
// st 指的是当前循环的字符
console.log(st);
}
11.数组操作
from,of,copyWithin,find,findIndex
- Array.from(参数) 将类数组的对象变为真正的数组, (只要有iterator 接口的数据,都可以被from方法转化为数组)
Array.from(参数) 将参数变为真正的数组
参数是
1.类数组对象(长的像数组)
2.可以遍历的对象
具有length属性的对象
var obj = {
0: '名字',
1: '年龄',
2: '性别',
length: 3
};
var arr = Array.from(obj);
console.log(arr1);
// NodeList 操作
var li = document.querySelectorAll('li');
console.log(li);
let arr1 = Array.from(li);
console.log(arr1);
// arguments 操作
function aa() {
console.log(arguments);
let arr2 = Array.from(arguments);
console.log(arr2);
}
Array.from()还有第二个参数,是一个函数,该函数用来处理数据,返回给数组(类似于array.map)
let str1 = '不分好歹难为地';
let arr4 = Array.from(str1, function (item) {
return item + '123';
});
console.log(arr4);
- Array.of(参数) 参数是一组数据,将一组数据转化为数组
let arr5 = Array.of('豆儿', 12, true);
console.log(arr5);
- copyWithin(参数1,参数2,参数3)
在当前数组中,将指定位置的数组元素,替换到指定位置,返回值是当前数组,
该方法是可以修改当前数组的
参数1 : 开始替换的位置,必须具有该参数,参数不可省
参数2 : 从当前位置开始读取元素,默认是0,如果为负数,就倒着数(包含 )
参数3 : 到当前位置元素读取结束,默认是整个数组的长度,如果为负数,
就倒着数(不包含)
let arr9 = ['易烊千玺', '王源', '王俊凯', '张云雷', '郭德纲', '于谦'];
arr9.copyWithin(0, 3, 4);
console.log(arr9);
//["张云雷", "王源", "王俊凯", "张云雷", "郭德纲", "于谦"]
- find() 和 findIndex(),参数是函数
find()方法,用来查找第一个满足条件的数组元素,它的参数是一个函数,
查询条件写在函数里面,如果满足,就把满足条件的元素返回,如果没有满足
条件的元素,返回undefined
findIndex() 方法,用来查找第一个满足条件的数组元素的下标,如果满足
返回数组下标,如果没有满足条件的元素,返回-1
let arr10 = ['张云雷', '郭德纲', '于谦', '岳云鹏', '张鹤伦'];
let str2 = arr10.find(function (item) {
return item == '于谦';
});
console.log(str2);
let str4 = arr11.findIndex(function (item) {
return item % 30 == 0;
});
console.log(str4); // 第一个能被3整除的数组元素的下标
12.函数操作
- es6 可以给函数参数添加默认值
函数作用域,如果设置了参数的默认值,函数在进行初始化的时候,他所具有的参数会形成一个单独的作用域。初始化结束以后,该作用域消失。如果没有设置参数的默认值,是不会这样的。
let x = 10;
function some(x,y=x){
console.log(y);
}
some(20);//20
let c = 1;
function some1(d=c){
let c=2;
console.log(d);
}
some1();//1(没有实参,默认值)
let k=100;
function some2(k=k){
console.log(k);
}
k=k,形成一个单独的作用域,相当于 let k=k;其实就是一个暂时性死区,因此会报错k未定义
13. 箭头函数
如果参数为1个,可以省略()
如果函数体内只有一个return语句,则可以省略{}以及return关键字
如果函数体返回一个对象,需要使用()括起来,因为{}会被解析为一个代码块,为了避免混淆,必须添加一个()
注意
- 1.函数体内的this对象,指的是定义该函数时候所在的对象,而不是使用该函数时候的对像
- 2.箭头函数不能作为构造函数,不可以使用new关键字
- 3.不可以使用arguments对象,因为该对象在函数体内不存在,如果需要获取多个参数,可以使用rest参数
- 4.不可以使用yield命令,因此箭头函数不能作为生成器(generator)函数
let test5 = () => ({name:'林彪',age:40});
console.log(test5());
14 set 构造函数
Set是ES6新出的数据结构,它类似数组,但是所有的元素都是唯一的,
它本身没有重复的值。
Set是一个构造函数,使用的时候需要实例化(new)
-size() 获取size长度
- add(val)给set添加数据,返回的是Set结构
- delete(val) 删除某个值,返回一个布尔值,表示是否删除成功
- clear() 清空所有值,没有返回值。
- has(val) 返回一个布尔值,表示set中是否含有当前参数
- forEach(item=>s.add(item));(类似于map)
- forEach() 可以遍历set中的每一个元素
keys() 返回键名的迭代器
values() 返回键值的迭代器
entries() 返回键值对的迭代器 - 实例化一个set,可以用一个数组作为参数,来去重,但是返回值不是数组,最后用数组方法from返回数组
let s = new Set();
s.add('楚留香');
s.add('三少爷');
s.add('西门吹雪');
console.log(s);
let arr = ['西门吹雪','陆小凤','花满楼','司空灾星','楚留香'];
// arr.forEach(item=>s.add(item));
arr.forEach(item=>s.add(item));
15 map
Map数据结构是ES6提供的新的数据组结构,类似对象,也是键值对集合,但是它的键名不仅仅是字符串,可以是各种类型的值。
- Map的键值对 值->值
- 并且Map具有 iterator,可以进行for-of遍历(每一组返回键和值的数组)
let m = new Map();
let arr = ['孔子','庄子','孙子'];
m.set('name','老孔').set('age',16).set(arr,'老子');
console.log(m);
for(let v of m){
console.log(v);
}
console.log(Map.prototype);
map方法
- size 获取Map的元素个数
- set 增加一个元素,返回值是当前的Map
- get 返回的是当前参数对应的值
- has 查询map中是否含有某一个元素,返回的是一个bool
- clear 清空map
- delete 删除一个元素
Map实际上就是一个超级版的Object,只不过它的key可以是任意数据类型,object怎么用,map就怎么用
16.symbol
symbol.iterator
是一种新的数据类型,它代表数值是唯一的
Number Boolean String Object Undefined Null Symbol
- 注意:
- 每一个symbol的值都是唯一的,可以用来解决命名冲突的问题
- 它不能够与其他的数据类型进行运算
- 不能进行for-in遍历
- 传入参数,传入的参数仅仅是一个注释,它的值本身还是唯一的
- symbol做到了内部的唯一性,无法从外部查看
let obj = {
name:'朱婷',
job:'打球',
say:function(){
console.log('加油');
}
};
//不知道对象中的内容,通过symbol添加属性
let mm = {
say:Symbol(),
run:Symbol()
};
obj[mm.say] = function(){
console.log('中国加油');
};
obj[mm.run] = function(){
console.log('中国快跑');
};
console.log(obj);
obj[mm.say]();
- Symbol.for()
var a1=Symbol('aa');
var a2=Symbol('aa');
console.log(a1==a2) false
var a3=Symbol.for('aa');
var a4=Symbol.for('aa');
console.log(a3==a4) true
17.迭代器(iterator)
为各种不同的数据,提供了统一的访问机制
任何数据结构,只要部署了iterator接口,就可以通过for-of进行遍历具有迭代器的数据
迭代器的工作原理
1.创建一个指针对象,指向当前数据结构的起始位置
2.第一次调用对象的next方法,指针对象就会指向数据结构的第一个元素对象
3.依次调用对象的next方法,指针对象一直往后移动,直到移到最后一个元素对象,遍历完毕
每一次调用都会返回一个{value:’’,done:bool}对象,value是当前元素的值,布尔值如果为false则表示没有遍历到最后,如果为true,则表示遍历完毕。
let arr1 = ['唐','宋','元','明','清'];
let iterator = arr1[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
let obj1 = {
name:'林黛玉',
age:16,
love:['葬花','宝玉','喝酒','吃肉'],
// 创建一个迭代器
[Symbol.iterator]:function(){
let _this = this;
let index=0;
return {
next:function(){
if(index<_this.love.length){
let res = {value:_this.love[index],done:false};
index++;
return res;
}else{
return {value:undefined,done:true};
}
}
};
}
};
for(let v of obj1){
console.log(v);
}
18.生成器函数(generator)*
用于解决回调地狱
写法
function * aa(){
yield 语句;
}
- yield 他是函数代码的分隔符,把函数代码分割成若干个部分,每一个部分的返回值是yield 的内容
- 生成器函数不能直接运行,可以通过next方法执行
- 生成器函数传参,第二次next的参数,可以作为第一次yield语句的返回结果,依次类推
// 实例解决回调地狱
function test1(){
setTimeout(()=>{
console.log('一帆风顺');
it.next();
},2000);
}
function test2(){
setTimeout(()=>{
console.log('二龙戏珠');
it.next();
},2000);
}
function test3(){
setTimeout(()=>{
console.log('三七四妾');
it.next();
},2000);
}
function * abc(){
yield test1();
yield test2();
yield test3();
}
let it = abc();
it.next();
//生成器实例
function time1(){
setTimeout(()=>{
let str='一行白鹭上青天';
console.log(str);
gen.next(str);
},2000)
}
function time2(aa){
setTimeout(()=>{
let str=aa+'两只黄鹂鸣翠柳';
console.log(str);
gen.next(str);
},2000)
}function time3(aa){
setTimeout(()=>{
let str=aa+'三三十';
console.log(str);
},2000)
}
function *generator(){
let t1=yield time1();
let t2=yield time2(t1);
let t3=yield time3(t2);
}
let gen=generator();
gen.next();
19.promise
-
Promise 是异步编程的一个解决方案,可以有效的解决回调地狱
他可以将异步操作用同步的流程书写出来,避免了层层回调嵌套,并且还有一些操作方法,使异步操作更加简洁 -
Promise是一个构造函数,用new来生成实例
-
promise对象是一个异步操作,有三种状态, 进行中(pending),已完成(fulfilled)和已失败(rejected),当异步操作结果为true的时候,promise对象的状态改为已完成,否则为已失败
-
Promise的构造函数接受一个回调函数作为参数,该函数有两个参数,resolve,reject,他们两个是两个函数,这个两个函数均由js提供,不用自己去书写
-
resolve:它的作用是,是将Promise对象的pending状态,该为已完成状态,并且在异步操作成功的时候,把异步操作的结果,作为参数传递出去
-
reject:它的作用是,是将Promise对象的pending状态,该为已失败状态,并且在异步操作失败的时候,把异步操作报错的结果,作为参数传递出去
let p = new Promise((resolve,reject)=>{
if(true){
let su = '成功的结果';
resolve(su);
}else{
reject('失败');
}
});
console.log(p);
p.then(data=>{
console.log(data);
},err=>{
console.log(err);
});
-
Promise 实例生成以后,可以通过then()获取实例对象传递出来的数据
-
then() 接受两个参数,均为回调函数,第一个回调函数,在Promise 实例对象的异步操作成功的时候执行,第二个回调函数在Promise 实例对象的异步操作失败的时候执行,
-
then方法是Promise.prototype上的方法
-
then方法返回的是一个promise实例,但是不是原来的promise实例,是一个新的promise实例,因此后面可以在执行- - then方法,也就是then方法可以进行链式操作,then方法的第二个可以省略
then的所有返回值- promise实例
- 普通数据,普通数据可以在下一个then中输出
- 抛出错误 throw new Error(‘错误’)
function Pro(str){
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
if(true){
resolve(str);
}else{
reject('报错');
}
},2000);
});
return p;
}
Pro('一行白鹭上青天').then(data=>{
console.log(data);
return Pro('两只黄鹂并翠柳');
}).then(data=>{
console.log(data);
return '三只黄鹂';
}).then(data=>{
console.log(data);
throw new Error('错误');
}).then(data=>{
console.log(data);
},err=>{
console.log(err);
});
- ==catch()==也是原型的方法,他是发生错误的时候,执行的方法,返回并跳过该错误,执行后方代码
catch() 返回值也是一个promise,后面可以直接使用then()
20.class
es6中引入了类,创建类的关键字是 class
声明类:
- class aa{};
- const aa=class{}
class Animal {
//构造函数
constructor() {
this.name = '动物';
}
//方法
say(){
console.log(this.name);
}
run(){
console.log('动物都会跑');
}
}
let a = new Animal();
a.say();
- this 指代的就是类的实例对象
- 构造函数的prototype属性,在类中依然存在,类中所有的方法,都在prototype上
- 类中的constructor方法,是一个默认方法,通过new命令生成实例的时候,会自动调用constructor方法,如果有参数,该方法会自动接受参数,如果没有显式的声明该方法,会默认创建一个空的constructor方法
- constructor方法实际上返回的是一个实例(this)
- 类没有变量提升(注意书写的位置顺序)
- 和函数一样,类也可以通过 赋值表达式来声明
const Dog = class Wa {
constructor(name) {
this.name = name;
}
show(){
console.log(Wa.name);
}
};
let d = new Dog('旺财');
d.show();
/*
Dog 是类的名字,Wa 代表当前的类,只能再该类中使用
Wa.name 输出的是当前类的名字wa
如果类的代码中使用不到类的名字,则可以省略
- 类 类似于 函数,也可以立即执行
//注意new 和 最后的()
const Duck = new class {
constructor(name) {
this.name = name;
}
job(){
console.log(this.name+'会抓鱼');
}
}('斑马');
21.类的继承
通过 extends 关键字进行继承
//子 extends 父
class Dog extends Animal {
constructor(name,color) {
super(name); //调用父类的构造函数
this.color = color;
}
job(){
let str = `${this.color}色的${this.name}会砍价`;
console.log(str);
}
}
let dog = new Dog('猫咪','绿');
dog.job();
- 类的继承,关键字是 extends
- 必须在子类的constructor中首先执行super()方法,用该方法来创建父类的this对象,如果没有super()方法,则会报错。因为子类没有自己的this对象,他是继承的父类的this对象
- 需要注意,子类的constructor中,只有在调用了super()方法以后,才可以使用this
- class内部可以使用get和set关键字,对某一个属性 设置 存储值函数 和 获取值函数作用是,可以从外部对属性的值进行设置。
class Cat {
constructor() {
this.color = '黄色';
}
get color(){
return 'get猫的名字叫兔子';
}
set color(val){
console.log('set猫的名字叫'+val);
}
}
let cat = new Cat();
console.log( cat.color );//执行get color
cat.color='钢镚';//执行set color
22.类的静态方法(static)
- 当实例化一个类的时候,实例化后的对象可以使用类中所有的方法
- 如果在某一个方法前面添加 static关键字,那么它所修饰的方法不能在实例化对象中使用,可以通过该类直接调用,这样的方法,叫静态方法
class Animal{
constructor(name) {
this.name = name;
}
say(){
console.log(this.name);
}
// 静态方法
static run(){
console.log('快跑!!!');
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
}
- 可以直接在类中调用执行静态的方法,在实例中无法访问类的静态方法
- 在类的扩展中的类也可以调用执行父类静态的方法,实例中无法访问类的静态方法
23.import和export导入导出其他js页面实现模块化
引入的js文件type类型为module
import defaultExport from "module-name";
01 import * as name from "module-name";
import { export } from "module-name";
import { export as alias } from "module-name";
02 import { export1 , export2 } from "module-name";
import { foo , bar } from "module-name/path/to/specific/un-exported/file";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
var promise = import("module-name");//这是一个处于第三阶段的提案。
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}
//01 导出列表
export { name1, name2, …, nameN };
// 重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };
// 02 解构导出并重命名
export const { name1, name2: bar } = o;
// 03 默认导出 只能用一次默认导出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };
// 导出模块合集
export * from …; // does not set the default export
export * as name1 from …; // Draft ECMAScript® 2O21
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;
24.nodejs是根据comment.js底层做导入导出的
导出:module.exports {}
导入:require('路径名/直接调用内置模块')