JavaScript语言本身指的就是ECMAScript。
ECMA官方网站 http://www.ecma-international.org/
1、nodemon 修改代码后,自动运行库
node 1.js
nodemon 1.js
2、块级作用域 let const
let 和const只针对作用域内的变量。闭包作用的一种延伸。先声明变量再使用变量。
const 声明常量和恒量。只读。声明的时候,必须赋值。不修改内存指向。例如
const name = 'zce';
name = 'jack'; // 会报错。修改了内存指向
const obj = {};
obj.name = 'ace'; //不报错。属性可以修改。
var声明变量,会对变量进行提升。提到代码的最前边。
最佳实践:不用var,主用const,配合let
3、数组的解构
const arr = [100,200,300];
//传统的写法
const foo = arr[0];
const bar = arr[1];
const bar2 = arr[2];
//数组解构的写法
const [ foo,bar,bar2 ] = arr;
//获取最后一个
const [ ,,bar2 ] = arr;
//提取当前位置后边的所有值,回返回一个数组(解构位置的最后使用)
const [foo,...rest] = arr;
console.log(rest);// [200, 300]
4、对象的解构
const obj = { name:'zce',age:18 };
const { name } = obj;
//解构的重命名
const name = 'tom';
const { name : objName = 'jack' } = obj;//重命名和给默认值
console.log(objName); // 解决命名冲突的问题.
//对console的解构
const { log } = console;
log('foo');
log('foo1');
log('foo2');
5、模板字符串字面量 反单引号
${} 支持变量名,运算符,有返回值的js语句。
let name = 'zce';
let str =`my name is ${name},age ${10+8} ${Math.random()}`;
console.log(str);
//标签函数
const str = console.log`hello world`;
6、字符串的扩展方法
const msg = 'Error: foo is not defined.';
// includes
msg.includes('foo'); // true
//startsWith
msg.startsWith('Error'); // true
//endsWith
msg.startsWith('.'); // true
7、参数默认值
//如果是是传多个形参,有默认值的形参放到最后
function foo(enable = true){
console.log(enable)
}
foo();
8、剩余参数rest
//...args 只能使用一次,并且放在最后的位置
function foo(first,...args){
console.log(args);
};
foo(1,2,3,4);
9、展开数组 spread
//打印每一项
const arr = ['foo','bar','baz'];
//最笨的方法
console.log(
arr[0],
arr[1],
arr[2]
)
//ES5
console.log.apply(console,arr);
//ES6
console.log(...arr);
10、箭头函数
优点:代码更简短已读,不改变this的指向,当前作用域的this。
//原始写法
function inc (number){
return number+1;
}
//ES6
const inc = (n,m)=>n+1; //省略return,直接将结果作为返回值
console.log(inc(100))
//this指向
const person = {
name:"tom",
sayHiAsync:function(){
const _this = this;
setTimeout(function(){
console.log(_this.name);
},1000)
},
sayHiAsyncNew:function(){
setTimeout(()=>{
console.log(this.name);
},1000)
},
}
11、对象字面量增强
const bar = '345';
const obj = {
foo:123,
//bar:bar,
bar,
method:function(){
console.log("12345");
},
method1(){
console.log("123456");
},
[1+1]:'123', //计算属性名
}
12、对象扩展方法
Object.assign:
将多个源对象中的属性复制到一个目标对象中
后边的对象覆盖到前边的对象
const soucre1 = {
a:123,
b:123,
}
const target = {
a:456,
c:456,
}
const res = Object.assign(target,source1);
console.log(target);// {a:123,c:456,b:123}
console.log(res === target); // true
Object.is
判断两个对象是否相当,用的比较少
Object.is(NaN,NaN);//true
Object.is(+0,-0);//false
13、Proxy 监视对象的改变
Object.defineProperty vue 3.0 以前使用,进行双向数据绑定
优势:defineProperty 只能监视属性的读写
- proxy能够监视到更对对象操作, 例如。对象的删除,对象方法的调用。
- 更好的支持数组对象的监视(重写数组的操作方法)
- 以非侵入的方式监管了对象的读写
const person = {
name:"ace",
age:20
};
const personProxy = new Proxy(person,{
get(target,property){
return property in target ? target[property]:'default';
},
set(target,property,value){
if( property === 'age'){
if(!Number.isInteger(value)){
throw new TypeError(`${value} is not an int `);
}
}
target[property] = value;
},
deleteProperty(target,property){
console.log('delete',property);
delete target[property];
}
});
console.log(personProxy.name);// zce
//设置
personProxy.age = "adfadad";//报错
personProxy.age = 100;
//执行删除的方法
delete personProxy.age;
console.log(person); // {name:"zce"}
汇总
如何使用proxy对数组进行监视?
const list = [];
const listProxy = new Proxy(list,{
set(target,propertty,value){
console.log('set',property,value);
target[property] = value;
return true;//表示设置成功
}
})
listProxy.push(100);
14、Reflect 统一的对象操作API
- 统一提供一套用于操作对象的API
- Reflect属于一个静态类,不能通过new Reflect()方式去构造一个实例对象,只能去调用静态类中的方法,如Reflect.get()。
- Reflect内部封装了一系列对对象的底层操作,提供了13个静态方法。
- Reflect成员方法就是Proxy处理对象的默认实现。
const obj = {
name:'zce',
age:18
};
console.log( 'name' in obj );
console.log( delete obj['age'] );
console.log(Object.keys(obj));
//Reflect使用方法
console.log(Reflect.has(obj,'name'));
console.log(Reflect.deleteProperty(obj,'age'));
console.log(Reflect.ownKeys(obj));
15、class类
//ES5
function Person(name){
this.name = name;
}
Person.prototype.say = function(){
console.log(`hi,my name is ${this.name}`)
}
//ES6
class Person{
constructor(name){
this.name = name;
}
say (){
console.log(`hi,my name is ${this.name}`)
}
}
16、实例方法VS静态方法
静态方法,需要注意this指向,this不会指向某一个实例对象,指向当前的类
class Person{
constructor(name){
this.name = name;
}
say (){
console.log(`hi,my name is ${this.name}`)
}
static create(name){
console.log(this);
return new Person(name);
}
}
const tom = Person.create('tom');
tom.say();
17、类的继承 extends
class Person{
constructor(name){
this.name = name;
}
say (){
console.log(`hi,my name is ${this.name}`)
}
}
//extends
class Student extends Person{
constructor(name,number){
super(name);//始终指向父类,调用就是调用父类的构造函数,继承父类的所有方法和属性
this.number = number;
}
hello(){
super.say();
console.log(`my school number is ${this.number}`)
}
}
const s = new Student('jack','100');
s.hello();
18、Set数据结构
特定:Set中的元素只会出现一次,即 Set 中的元素是唯一的。
- Set.prototype.size 返回 Set 对象中的值的个数
- Set.prototype.add(value) 在Set对象尾部添加一个元素。返回该Set对象。
- Set.prototype.clear() 移除Set对象内的所有元素。
- Set.prototype.delete(value)
移除Set中与这个值相等的元素,返回Set.prototype.has(value)在这个操作前会返回的值(即如果该元素存在,返回true,否则返回false)。Set.prototype.has(value)在此后会返回false。 - Set.prototype.entries()
返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值的[value,
value]数组。为了使这个方法和Map对象保持相似, 每个值的键和值相等。 - Set.prototype.forEach(callbackFn[, thisArg])
按照插入顺序,为Set对象中的每一个值调用一次callBackFn。如果提供了thisArg参数,回调中的this会是这个参数。 - Set.prototype.has(value) 返回一个布尔值,表示该值在Set中存在与否。
- Set.prototype.keys()
与values()方法相同,返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。 - Set.prototype.values() 返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值
- Set.prototype@@iterator 返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。
const s = new Set();
s.add(1).add(2).add(3)
console.log(s);
s.forEach(i=>console.log(i));
for(let i of s){
console.log(i)
}
//利用set进行数组去重
const arr = [1,2,3,4,1,3];
const res = new Set(arr);//利用set的特性去重
console.log(res);
//set 转换为数字
Array.from(new Set(arr));
[...new Set(arr)]
19、Map数据结构
const m = new Map();
const tom = {"name":"tom"};
m.set(tom,90);
console.log(m);
console.log(m.get(tom));
// m.has()
//m.delete();
// m.clear()
20、Symbol 数据类型
独一无二,实现方法内的私有方法
最主要的作用就是为对象添加独一无二的属性名
//Symbol数据类型
console.log(Symbol() === Symbol()); //false
//静态方法 for。 如果传的值不是字符串,会强制转成字符串
const s1 = Symbol.for('foo');
const s2 = Symbol.for('foo');
console.log(s1 === s2);//true
//获取属性名的区别
const obj = {
[Symobol()]:’symbol value',
"foo":"normal value"
};
for( var key in obj){
console.log(key);
}
// 结果:foo; 只能获取到字符串类型的key
console.log(Object.keys(obj)); // 结果: ["foo"]
console.log(JSON.stringify(obj));// {"foo":"normal value"}
console.log(Object.getOwnPropertySymbols(obj));// 才能获取 Symbol() 类型的key
JS的7种数据类型
Number,boolean , Object , Symbol , String, Null, Undefined
21、for …of 循环
做完遍历所有数据结构的统一方式
可以使用break终止循环
const arr = [100,200,300,400,500];
for( const item of arr ){
console.log(item);
if(item > 100){
break;
}
}
22、迭代器 Iterable接口
for…of 内部实现原理
const set = new Set(["foo","bar","baz"]);
const iterator = set[Symbol.iterator]();
console.log(iterator.next());// {value:"foo",done:false}
console.log(iterator.next());//{value:"bar",done:false}
console.log(iterator.next());//{value:"baz",done:false}
console.log(iterator.next());//{value:undefined,done:true}
console.log(iterator.next());//{value:undefined,done:true}
//实现可迭代接口
const obj = {
[Symbol.iterator]:function(){
return {
next:function(){
return {
value:"zce",
done:true //迭代有没有结束
}
}
}
}
}
//迭代器内部实现
const obj = {
store:["foo","bar","baz"],
[Symbol.iterator]:function(){
let index = 0 ;
const self = this;
return {
next:function(){
const res = {
value:self.store[index],
done:index >= self.store.length
}
index++;
return res;
}
}
}
}
for ( const item of obj ){
console.log(item);
}
23、迭代器设计模式
对外提供统一的遍历接口
// 迭代器设计模式
// 场景: 你我协同开发一个任务清单应用
//我的代码
const todos = {
life:['吃饭','睡觉','打豆豆'],
learn:['语文','数学','英语'],
work:['喝茶','code'],
each:function(cb){
const all = [].concat(this.life,this.learn,this.work);
for( const item of all ){
cb(item);
}
},
[Symbol.iterator]:function(){
const all = [...this.life,...this.learn,...this.work];
let index = 0 ;
return {
next:function(){
const res = {
value:self.store[index],
done:index >= self.store.length
}
index++;
return res;
}
}
}
};
//你的代码
for( const item of todos ){
console.log(item);
}
24、生成器 Generator
避免异步编程中回调嵌套过深
踹一下,走一步
//应用
// 案例1:发号器
function * createIdMaker(){
let id = 1;
while(true){
yield id++;
}
}
const idMaker = createIdMaker();
console.log(idMaker.next().value);
console.log(idMaker.next().value);
console.log(idMaker.next().value);
console.log(idMaker.next().value);
//案例2:使用Generator 函数实现,iterator方法
const todos = {
life:['吃饭','睡觉','打豆豆'],
learn:['语文','数学','英语'],
work:['喝茶','code'],
[Symbol.iterator]:function(){
const all = [...this.life,...this.learn,...this.work];
let index = 0 ;
for(const item of all){
yield item
}
}
};
for( const item of todos ){
console.log(item)
}
25、 ECMAScript 2016
//Array 添加includes方法
const arr = ['foo',1,NaN,false];
console.log(arr.includes("foo"));// true ,相比于indexOf可以验证NaN是否存在
console.log(arr.includes(NaN));
//指数运算符
console.log(Math.pow(2,10));//借助于Math函数
console.log(2**10);//新的指数运算符
26、 ECMAScript 2017
对Object的三个扩展方法
const obj = {
foo:'val1',
bar:'val2'
};
//Object.values 类似于 Object.keys keys返回的是key,values返回的是value
console.log(Object.valuse(obj));// ['val1','val2']
//Object.entries 返回一个 key,val的数组
console.log(Object.entries(obj)); // [ ['foo','val1'],['bar','val2'] ]
for( const [ key,val] of Object.entries(obj) ){
console.log(key,val);
}
//Object.getOwnPropertyDescriptors 获取对象中完整的描述信息
const p1 = {
firstName:'Lei',
lastName:'Wang',
get fullName (){
return this.firstName + ' ' +this.lastName;
}
}
console.log(p1.fullName);// Lei Wang
//Object.assign 在复制时,把fullName当成了一个普通的属性,复制过来
const p2 = Object.assign({},p1);
p2.firstName = 'zce';
console.log(p2);// [firstName:'Lei',lastName:'Wang', fullName:'Lei Wang' ]
const desriptors = Object.getOwnPropertyDescriptors(p1);
console.log(desriptors);//获取详情
const p3 = Object.defineProperties({},desriptors);
p3.firstName = 'zce';
console.log(p3.fullName); // zce wang
//String.prototype.padStart / String.prototype.padEnd
//字符串填充方法
const books = {
html:5,
css:123,
javascript:1290
}
for( const [ name,count ] of Object.entries(books)){
console.log(`${name.padEnd(16,'-')}|${count.toString().padStart(4,'0')}`);
}
//在函数中添加尾逗号
function foo(bar,baz,){}
const arr = [1,23,4,]
//Async/Await
//promise的语法糖,使代码,整体看起来更加整洁,易读