Skip to content

Instantly share code, notes, and snippets.

@simonid
Created February 1, 2018 14:55
Show Gist options
  • Save simonid/68e3a41ab456d7ae80a21ad64672d1fc to your computer and use it in GitHub Desktop.
Save simonid/68e3a41ab456d7ae80a21ad64672d1fc to your computer and use it in GitHub Desktop.
ES6笔记

ES6学习笔记

视频笔记

3-3 正则扩展

{
	let regex = new RegExp('xyz','i');
	let regex2 = new RegExp(/xyz/i);    //上述两个例子是ES5
	console.log(regex.test('xyz123'),regex2.test('xyz123'));
	//输出结果为两个true
	// 在ES5的正则中,类似"/xyz/i"这样的格式只能添加一个修饰符,比如这里的i

	let regex3 = new RegExp(/xyz/ig,'i');
	console.log(regex3.flags);	
	
	//flags是ES6新引入的用来获取正则对象的
	//输出结果是i
	//后面的参数回覆盖掉前面的
}

ES6引入的新正则修饰符y

{
	let s = 'bbb_bb_b'
	let a1 = /b+/g;
	let a2 = /b+/y;
	
	console.log('one',a1.exec(s),a2.exec(s));	  //两种修饰符都能匹配到bbb
	console.log('two',a1.exec(s),a2.exec(s));	  //g能匹配到bb,y不能

	//g是贪婪模式,不要求第一个字符匹配成功,一旦字符串中匹配的内容就可以匹配成功;但是如果使用y,假如前面的字符无法匹配,那么最后的结果就无法匹配上

	console.log(a1.sticky,a2.sticky); //检测是否使用修饰符y匹配
}

ES6引入的新正则修饰符u

{
	console.log('u-1',/^\uD83D/.test('\uD83D\uDC2A'));
	console.log('u-2',/^\uD83D/u.test('\uD83D\uDC2A'));
	
	//最后的结果是第一个匹配成功,第二个失败;原因在于当加入u参数后,系统认为'\uD83D\uDC2A'为一个字符

	console.log(/\u{61}/.test('a'));
	console.log(/\u{61}/u.test('a'));
	//最终结果是第一个false,第二个true;如果用户不加入u修饰,那么系统不会识别编码

// u修饰符还可以补充ES5中正则匹配的缺陷(当Unicode值大于FFFF时无法匹配)
}

3-4~3-5 字符串扩展

如果要表示编码大于FFFF的字符,也就是大于两个字节,需要补充上{ },例如: console.log('s',\u{20BB7});
结果:𠮷
注意这个字符的length属性就是2

let s='𠮷';
console.log('length',s.length);
console.log('0',s.charAt(0));
console.log('1',s.charAt(1));
console.log('at0',s.charCodeAt(0));
console.log('at1',s.charCodeAt(1));
//ES5

let s1='𠮷a';
console.log('length',s1.length);
console.log('code0',s1.codePointAt(0));
console.log('code0',s1.codePointAt(0).toString(16));
console.log('code1',s1.codePointAt(1));
console.log('code2',s1.codePointAt(2));
//ES6

console.log(String.fromCharCode('0x20bb7'));  //ES5
console.log(String.fromCodePoint('0x20bb7'));  //ES6

let str = '\u{20bb7}abc';
for(let i=0;i<str.length;i++)
	console.log('ES5',str[i]);
for(let code of str)
	console.log('ES6',code);


//ES6的字符串操作接口
{
	let str = "string";
	console.log("includes",str.includes("c"));
	console.log("start",str.startWith('str'));
	console.log('end',str.endWith('ng'));
}
{
	left str = 'abc';
	console.log(str.repeat(2));
}
{
	let name = "list";
	let info = "hello world";
	let m=`i am ${name},${info}`;
	console.log(m);
}
{
	console.log('1',padStart(2,'0'));
	//输出01
	console.log('1',padEnd(2,'0'));
	//输出10
}

{
	let user = {
		name : 'list',
		info : 'hello world'
	};
	console.log(abc`i am ${user.name},${user.info}`);
	function abc(s,v1,v2){
		console.log(s,v1,v2);
		return s+v1+v2;
	}
}

3-6 数值扩展

进制的表示

{
	console.log(0b11001);  //二进制
	console.log(0o602);  //八进制
}

数值判断

判断是否有穷尽的api Number.isFinte() and 判断是否为数字的apiNumber.isNaN()

{
	console.log('10',Number.isFinite(10));   //true
	console.log('NaN',Number.isFinite(NaN));    //false
	console.log('1/0',Number.isFinite('true'/0));   //false
	console.log(Number.isNaN(NaN));	
}

判断是否为整数的api Number.isInteger()

{
	console.log('10',Number.isInteger(10));  //true
	console.log('10',Number.isInteger(10.0));  //true
	console.log('10',Number.isInteger(10.1));  //false
}

注意,传入的参数是x.0也认为是整数,但是小数点后不是0那么就不认为是整数

向下取整api Math.trunc()

{
	console.log(Math.trunc(3.2));  //3
}

判断正负数apiMath.sign()

{
	console.log(Math.sign(-3));  //-1,表示为负数
	console.log(Math.sign(0));   //0,表示为0
	console.log(Math.sign(3));   //1,表示为正数
	console.log(Math.sign('3'));   //1,由数字组成的字符串会转换为数字
	console.log(Math.sign(‘te'));   //NaN
}

立方根api Math.cbrt()

3-7 数组扩展

创建数组api Array.of()

{
let arr = Array.of(1,2,3,4);
console.log(arr);   //[1,2,3,4]
}

集合转义为数组api Array.from()

{
	let p = document.querySelectorAll('p');
	left pArr = Array.from(p);
	pArr.forEach(function(item){
		console.log(item.textContent);
	});

	console.log(Array.from([1,2,3],function(item){	
		return item*2
	}));  
	//数组映射:[2,4,6]
}

数组元素替换api Array.fill()

{
	console.log([1,'a',undefined].fill(2));  //[2,2,2]
	console.log(['a','b','c'].fill(1,2,3));      //["a","b",1]  
	console.log(['a','b','c','d'].fill(1,2,4));   //["a", "b", 1, 1]
}

返回数组索引api Array.keys() and 索引对应值api Array.values() and 同时打印索引和对应值的api Array.entries()

{
	for(let index of ['a','b','c'].keys())
		console.log(index);
	//0  1  2

	for(let value of ['a','b','c'].values())
		console.log(value);
	//a b c
	//注意 chrome上values有兼容问题

	for(let [index,value] of ['a','b','c'].entries())
		console.log(index,value);

	let test = {k:12,o:34};
	for(let [key,value] of Object.entries(test)){
		console.log([key,value]);
	}
}

数组内元素值覆盖api Array.copyWithin()

{
	console.log([1,2,3,4,5].copyWithin(0,3,4));
	//[4,2,3,4,5]
	console.log([1,2,3,4,5].copyWithin(1,2,4));
	//[1, 3, 4, 4, 5]
}

数组内查找符合条件的元素api Array.find()

{
	console.log([1,2,3,4,5,6].find(function(item){
		return item>3;
	}));
	//4,注意只返回第一个符合条件的元素
	//如果是返回第一个符合条件的元素下标则使用findIndex
	//如果需要返回全部符合条件的元素,就用filter

	//补充,前面提到的includes可以判断数组内是否有符合条件的元素
	console.log([1,2,NaN.includes(NaN));  //true
}

3-8 函数扩展

函数默认值参数

{
	function test(x,y='world'){
		console.log('默认值',x,y);
	}
	test('hello');  //hello.world
	test('hello','ES6'); //hello,ES6
}

注意在函数默认值参数后面不能增加非默认值的参数,比如不能有 y='a',x 这样的形式,但是可以有 y='a',x='s'

函数作用域

{
	let x = 'test';
	function test1(x,y=x){
		console.log(x,y);
	}
	test1('new');  //new,new

	function test2(c,y=x){
		console.log(c,y);
	}
	test2('new');  //new,test
}

rest参数

将不确定的输入参数转换为数组。

注意,rest参数后面不能加任何参数

{
	function test3(...arg){
		for(let v of arg){
			console.log(v);
		}
	}
	test3(1,2,'a');
}
{
	console.log(...[1,2,3]);
	//将数组离散化,和前面的rest参数将离散化内容数组化相反
}

箭头函数

格式:函数名=参数=返回值

{
	let arrow = v => v*2;
	console.log(arrow(3));
	//6
	
	let arrow2 = () => 2;
	//2
}

伪调用

{
	function tail(x){
		console.log(x);
	}
	function fx(x){
		return tail(x);
	}
	fx(12); //12
}

3-9 对象扩展

//属性
{
	let es5 = {
		o : o,
		k : k
	};
	let es6 = {
		o,
		k
	};
	console.log(es5,es6);

//方法
	let es5Method = {
		hello : function(){
			console.log('hello');
		}
	};
	let es6Method = {
		hello(){
			console.log('hello');
		}
	};

//属性表达式
	let a = 'b';
	let es5Obj = {
		a : 'c',
		b : 'c'
	};
	let es6Obj = {
		[a] : 'c'
	}
	console.log(es5Obj,es6Obj);
	//{a: "c", b: "c"}    {b: "c"}
}

新增api

Object.is

判断两个对象是否全等,等价于 ===

console.log(Object.is('abc','abc');

Object.assign

浅拷贝

console.log(Object.assign({a:'a'},{b:'b'})); 
//{a: "a", b: "b"}

3-10 Symbol用法

Symbol声明的对象是独一无二的

let a1=Symbol();
let a2 =Symbol();
console.log(a1===a2);
//false

//还原对象:for
let a3=Symbol.for('a3');
let a4=Symbol.for('a3');
console.log(a3===a4);
//true

Symbol对象的作用:可以避免前一个对象被后面一个同名的对象覆盖

{
let a1 = Symbol.for('abc');
let obj = {
	[a1] : '123',
	'abc' : 345,
	'c' : 678
	};
console.log(obj);
//{abc: 345, c: 678, Symbol(abc): "123"}
}

注意,当对象中使用Symbol作为key值的时候,通过for-in或of都是不可获取它的属性的

{
	let a1 = Symbol.for('abc');
	let obj = {
		[a1] : '123',
		'abc' : 345,
		'c' : 678
	};
	console.log(obj);
	for(let [key,value] of Object.entries(obj)){
		console.log(key+":"+value);
		//abc:345   c:678   undefined
	}
	Object.getOwnPropertySymbols(obj).forEach(function(item){
		console.log(obj[item]);
	})
	//123

	Reflect.ownKeys(obj).forEach(function(item){
		console.log(item,obj[item]);
	})
	//可以获取Symbol(abc)  "123"
}  

3-11 set-map数据结构

{
	let list = new Set();
	list.add(1);
	list.add(2);
	console.log(list.size);
	//2

	let a = [1,2,3];
	let b = new Set(a);
	console.log(b.size);
	//3
}

添加重复的set数据是无法实现的,利用这个特性可以实现去重

{
	let a = [1,2,3,1,2];
	let b = new Set(a);
	console.log(b);
	//Set(3) {1, 2, 3}
}

Set的几个api

{
	let arr = ['add','delete','clear','has'];
	let list = new Set(arr);
	console.log(list.has(’add'));
	console.log(list.delete('add'),list);
	list.clear();
	console.log(list);
}

遍历set:

	let arr = ['add','delete','clear','has'];
	let list = new Set(arr);
	for(let key of list.keys()){
		console.lof(key);
	}
	for(let value of list.values()){
		console.lof(value);
	}
	for(let [key,calue] of list.entries()){
		console.lof(key,value);
	}

	list.forEach(function(item){console.log(item);});

WeakSet

和Set的区分:

  • 不能遍历
  • 支持的数据类型不一样:WeakSet的元素只能是对象
  • WeakSet对象都是弱引用,不会检测对象是否在其他地方引用过,所以不会和垃圾回收机制挂钩
  • 一些属性和方法不同

map

map的一个特点是可以用任何数据作key值

{
	let map1 = new Map();
	let arr = ['123'];
	map1.set(arr,456); //注意map添加数据是用set方法
	console.log(map1,map1.get(arr));
//Map(1) {Array(1) => 456} 456

	let map2 = new Map([['a',123],['b',456]]);
	console.log(map2);
//Map(2) {"a" => 123, "b" => 456}
	console.log(map2.size);
	console.log(map2.delete('a'),map2);
	console.log(map2.clear(),map2);
}

WeakMap

Set和WeakSet的关系等同map和WeakMap

3-12 map-set与数组和对象的比较

//map和数组array对比
{
	let map = new Map();
	let array = [];
	
	//增
	map.set('t',1);
	array.push({t:1});
	console.log('map-array',map.array);

	//查
	let map_exist = map.has('t');
	let array_exist = array.find(item=>item.t);
	console.log(map_exist,array_exist);

	//改
	map.set('t',2);
	array.forEach(item=>item.t?item.t=2:'');
	console.log(map,array);

	//删
	map.delete('t');
	let index = array.findIndex(item=>item.t);
	array.splice(index,1);
	console.log(map,array);
}

//set和数组array对比
{
	let set = new Set();
	let array = [];

	//增
	set.add({t:1});
	array.push({t:1});
	console.log(set,array);

	//查
	let set_exist = set.has({t:1});
	let array_exist = array.find(item=>item.t);
	console.log(set_exist,array_exist);

	//改
	set.forEach(item=>item.t?item.t=2:'');
	array.forEach(item=>item.t?item.t=2:'');
	console.log(set,array);

	//删
	set.forEach(item=>item.t?set.delete(item):'');
	let index = array.findIndex(item=>item.t);
	array.splice(index,1);
	console.log(set,array);
}

//map、set、object对比
{
	let item = {t:1};
	let map = new Map();
	let set = new Set();
	let obj = {};

	//增
	map.set('t',1);
	set.add(item);
	obj['t'] = 1;
	
	//查
	console.log({
		map_exis : map.has('t');
		set_exist : set.has(item);
		obj_exist : 't' in obj
	})

	//改
	map.set('t',2);
	item.t = 2;
	obj['t'] = 2;

	//删
	map.delete('t');
	set.delete(item);
	delete obj['t'];
}

总结:
优先使用map,如果要考虑到数据的唯一性,那么优先考虑set

3-13 Proxy和Reflect

Proxy和Reflect的方法是一样的

{
	let obj = {
		time : '2017-2-1',
		name : 'ES6',
		_t : 123
	};

	let monitor = new Proxy(obj,{
		//拦截对象属性的读取
		get(target,key){
			return target[key].replace('2017','2018')
		},

		//拦截对象设置属性
		set(target,key,value){
			if(key=='name'){
				return target[key] = value;
			}else{
				return target[key];
			}
		},

	//拦截key in object操作
	has(target,key){
		if(key=='name'){
			return target[key];
		}else{
			return false;
		}
	}

	//删除
	deleteProperty(target,key){
		if(key.indexOf('_') > -1){
			delete target[key];
			return true;
		}else{
			return target[key];
		}
	},

	//拦截object.key,object.getOwnPropetySymbols,Object.getOwnPropertyNames
	ownKeys(target){
		return Object.keys(target).filter(item=>item!='time')
	}
});
	console.log(Object.keys(monitor));

	console.log(monitor.time);  //2018-2-1

	monitor.name = 'ES';
	console.log(monitor.name);   //ES

	console.log('name' in monitor);  //true

	delete monitor.time;
	console.log(monitor);  //没有删除time属性
	delete monitor._t;
	console.log(monitor);   //删除了_t
}

3-14 类

{
	class Parent{
		constructor(name='mooc'){
			this.name = name;
		}
	}
	let v_parent = new Parent('v);
	console.log(v_parent.name);  //mooc
}
//类与构造函数创建

{
	class Parent{
		constructor(name='mooc'){
			this.name = name;
		}
	}

	class Child extends Parent{}	
	console.log(new Child());  //mooc
}
//继承

{
	class Parent{
		constructor(name='mooc'){
			this.name = name;
		}
	}

	class Child extends Parent{
		constructor(name='child'){
			super(name);   //在构造函数中使用super关键字,super必须放在第一行
			this.type = 'child';  
		}
	}	
	console.log(new Child(‘ES6’));  //ES6
}
//继承和修改

{
	class Parent{
		constructor(name='mooc'){
			this.name = name;
		}

		get longName(){  //注意这不是方法,是属性
			return 'mk' + this.name
		}
		set longName(value){
			this.name = value;
		}
	}
	
	let v = new Parent();
	console.log(v.longName);  //mkmooc
	v.longName = 'hello';
	console.log(v.longName);  //mkhello
}
//继承

{
	class Parent{
		constructor(name='mooc'){
			this.name = name;
		}

		static tell(){
			console.log('tell');
		}
	}

	Parent.tell();  //tell
}
//静态方法

{
	class Parent{
		constructor(name='mooc'){
			this.name = name;
		}
	}
	Parent.type = 'test';
	console.log(Parent.type); //test
}
//静态属性

3-15 Promise

{
	let pro = function(callback){
		console.log('excute');
		setTimeoout(function(){
			callback && callback.call()
		},2000);
	};
	pro(function(){
		console.log('test1');
	})
}

{
	let pro = function(){
		console.log('excute');
		return new Promise(function(resolve,reject){
			setTimeout(function(){
				resolve();
			},2000);
		})
	};
	pro().then(function(){
		console.log('resolve');
	},function(){
		console.log('reject');	
	})
}

{
	let pro = function(){
		console.log('excute');
		return new Promise(function(resolve,reject){
			setTimeout(function(){
				resolve();
			},2000);
		})
	};
pro()
	.then(function(){
		return new Promise(function(resolve,reject){
			setTimeout(function(){
				resolve();
			},2000);
		});
	})
	.then(functionn(){
		console.log('test');
	})
}

{
	let pro = function(num){
		console.log('excute');
		return new Promise(function(resolve,reject){
			if(num>5){
				resolve()
			}else{
				throw new Error('Error!');
			}
		})
	}
	pro(6).then(function(){
		console.log('6');
	}).catch(function(err){
		console.log(err);
	});
	
	pro(2).then(function(){
		console.log('2');
	}).catch(function(err){
		console.log(err);
	});
}

实际案例使用:
有些情况下,网页需要加载出所有图片才添加到页面上

{
	function loadImg(src){
		return new Promise((resolve,reject)=>{
			let img = document.createElement('img');
			img.src = src;
			img.onload = function(){
				resolve(img);
			}
			img.onerror = function(){
				reject(err);
			}
		})
	}

	function showImgs(imgs){
		imgs.forEach(function(){
			document.body.appendChild(img);
		})
	}

	Promise.all([   //创建一个新Promise实例,当传入的所有Promise实例状态完成才记载新的Promise实例
		loadImg("http://xxx");
		loadImg("http://xxx");
		loadImg("http://xxx");	
	]).then(showImgs)
}

有些情况,需要一张图片加载完成后就结束其他未加载内容的加载

{
	function loadImg(src){
		return new Promise((resolve,reject)=>{
			let img = document.createElement('img');
			img.src = src;
			img.onload = function(){
				resolve(img);
			}
			img.onerror = function(){
				reject(err);
			}
		})
	}

	function showImgs(imgs){
		imgs.forEach(function(){
			document.body.appendChild(img);
		})
	}

	Promise.race([
		loadImg("http://xxx");
		loadImg("http://xxx");
		loadImg("http://xxx");			
	]).then(showImgs)
}

3-16 Iterator接口

{
	let arr = ['hello','world'];
	let map = [Symbol.iterator]();
	console.log(map.next());
	console.log(map.next());
	console.log(map.next());
}

{
	let obj = {
		start : [1,2,3],
		end : [4,5,6],
		[Symbol.iterator](){
			let self = this;
			let index = 0;
			let arr = self.start.concat(self.end);
			let len = arr.length;
			return {
				next(){
					if(index<len){
						return {
							value : arr[index++],
							done : false;
						}
					}else{
						return {
							value : arr[index++];
							done : true
						}
					}
				}
			}
		}
	}
	for(let key of obj){
		console.log(key);
	}
}
//创建有iterator接口的object

3-17 Generator

{
	let tell = function* (){
		yield 'a';
		yield 'b';
		return 'c';
	};
	let k = tell();
	console.log(k.next());  //a
	console.log(k.next());  //b
	console.log(k.next());  //c
	console.log(k.next());  //undefined
}
{
	let obj = {};
	obj[Symbol.iterator] = function* (){
		yield 1;
		yield 2;
		yield 3;
	}
	for(let value of obj){
		console.log(value);
	}
}
{
	let state = function* (){
		while(1){
			yield 'A';
			yield 'B';
			yield 'C';
		}
	}
	let status = state();
	console.log(status.next());	//A
	console.log(status.next());	//B
	console.log(status.next());	//C
	console.log(status.next());	//A
	console.log(status.next());	//B
	console.log(status.next());	//C
}
{
	let state = async function (){
		while(1){
			await 'A';
			await 'B';
			await 'C';
		}
	}
	let status = state();
	console.log(status.next());	//A
	console.log(status.next());	//B
	console.log(status.next());	//C
	console.log(status.next());	//A
	console.log(status.next());	//B
	console.log(status.next());	//C
}

Generator的应用
抽奖活动:抽奖页面需要前后端一起配合,这里只是讲前端的
如果将抽奖剩余次数变量作为全局变量,首先是容易受污染,其次用户可能可以察觉并修改该变量
generator可以很好地实现

{
	let draw = function(count){
		console.log(`剩余${count}次`);
		//这里是抽奖逻辑
	}
	let residue = function* (count){
		while(count > 0){
			count--;
			yield draw(count); 
		}
	}
	let star = residue(5);
	let btn = document.createElement('button');
	btn.id = 'start';
	btn.textContent = '抽奖';
	document.body.appendChild(btn);
	document.getElementById('start').addEventListener('click',function(){
		star.next();
	},false);
}

长轮询

{
	let ajax = function* (){
		yield new Promise(function(resolve,reject){
			setTimeout(function(){  //模拟和后端通信
				resolve({code:0});  //如果不是0,那么就一直间隔轮询
			},200)
		})
	}
	let pull = function(){
		let generator = ajax();
		let step = generator.next();
		step.value.then(function(d){   //拿到d,代表后端数据
			if(d.code!=0){    //拿到数据不是最新的
				setTimeout(function(){
					console.log('wait');
					pull()
				},1000);
			}else{
				console.log(d);
			}
		})
	}
	pull();
}

3-18 Decorator

{
	let readonly = function(target,name,descriptor){
		descriptor.writable = false;
		return descriptor;
	};
	class Test{
		@readonly
		time(){
			return '2018-2-1'
		}
	}
	let test = new Test();
	console.log(test.time());  //2018-2-1
	
	test.time = function(){
		console.log('reset time');
	};
	console.log(test.time());  //报错
}

{
	let typename = function(target,name,description){
		target.myname = 'hello';
	}
	@typename
	class Test{}

	console.log(Test.myname); //hello
}

补充说明一个包含多种修饰器的第三方库:core-decorators ,可以通过npm安装

3-19 模块化

需要导出的模块(命为test.js):

export let A = 123;
export function test(){
	console.log('test');
}
export class Hello{
	test(){
		console.log('class');
	}
}

需要导入的模块:

import {A,test,Hello} from './test';
console.log(A,test,Hello);

或者:

import  *  as lesson from './test';
console.log(lesson.A);
//导出的模块:
let A = 123;
let test = function(){
	console.log('test');
}
class Hello{
	test(){
		console.log('class');
	}
}
export default {
	A,
	test,
	Hello
}


//导入的模块:
import lesson from './test';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment