javascript_ES6新特性

参考链接:https://www.jianshu.com/p/87008f4f8513,

https://www.cnblogs.com/20gg-com/p/6687443.html?utm_source=itdadao&utm_medium=referral

参考内容:妙味课堂

 let、const 

let 定义的变量不会被变量提升,const 定义的常量不能被修改,let const 都是块级作用域

ES6前,是var命名变量,有“预编译”功能(变量会先赋值为undefined),js 是没有块级作用域 {} 的概念的。(有函数作用域、全局作用域、eval作用域)

ES6后,let const 的出现,js 也有了块级作用域的概念,前端的知识是日新月异的~

变量提升:在ES6以前,var关键字声明变量。无论声明在何处,都会被视为声明在函数的最顶部;不在函数内即在全局作用域的最顶部。这样就会引起一些误解。例如:

<script>
	console.log(a); // undefined
	var a = 'hello1';
			 
	// 上面的代码相当于,即预编译
	var a;
	console.log(a);	//hello1
	a = 'hello1';
			 
	// 而 let 就不会被变量提升;且不能重复对同一变量声明赋值,可以写成 a='hello',但不能let声明
	console.log(a); // hello1
	//报错,SyntaxError: Identifier 'a' has already been declared
	a = 'hello2';
	let a = 'hello2';
</script>
<script>
	 console.log(a);	//undefined
	 var a = 1;
	 a = 1000;
	 var a = 300;
	 console.log(a);	//300
	 {
	 	var a = 1;
	 }
	 console.log(a)		//1
</script>
<script>
	 {
	 	let b = 100;
	 	console.log(b);	//100
	 }
	 console.log(b)	//b is not defined
</script>
<script>    
     console.log(b);
     //ReferenceError: Cannot access 'b' before initialization
	 let b = 2;
	 let b = 200;
	 // Identifier 'b' has already been declared
	 console.log(b);
</script>

const 定义的常量不能被修改

<script>
	var name = "bai";
	name = "ming1";
	console.log(name); // ming1
 
	const name = "bai";
	name = "ming2"; // Assignment to constant variable.
	console.log(name);
</script>
<script>
//var 可以重复对同一变量修改赋值,  let则不可以
			 var x = 10;
			 x = 30;
			 console.log(x);

//const可以重复对同一变量修改赋值
			 const c = 3.14;
			 c = 10;
			 console.log( c )
			// Assignment to constant variable.

//不可以直接对对象赋值,但可以对它声明属性并赋值
			 const obj = {};
			 // obj = 1
			 obj.name = "kimoo";
			 console.log( obj )		//{name: "kimoo"}
</script>

importexport

import导入模块、export导出模块

<script>
	// 全部导入
	import people from './example'
	 
	// 将整个模块当作单一对象进行导入,该模块的所有导出都会作为对象的属性存在
	import * as example from "./example.js"
	console.log(example.name)
	console.log(example.getName())
	 
	// 导入部分,引入非 default 时,使用花括号
	import {name, age} from './example'
	  
	// 导出默认, 有且只有一个默认
	export default App
	 
	// 部分导出
	export class App extend Component {};

</script>

classextendssuper

ES5中最令人头疼的的几个部分:原型、构造函数,继承,有了ES6我们不再烦恼!

ES6引入了Class(类)这个概念。

<script>
	class Animal {
	constructor() {
		this.type = 'animal';
		}
		says(say) {
			console.log(this.type + ' says ' + say);
		}
	}
	 
	let animal = new Animal();
	animal.says('hello'); //animal says hello
	 
	class Cat extends Animal {
	constructor() {
		super();
		this.type = 'cat';
		}
	}
	 
	let cat = new Cat();
	cat.says('hello'); //cat says hello
    
    class Person{
			constructor(name,age){
				this.name = name;
				this.age = age;
			}
			say(){
				console.log( "我叫"+this.name+"今年,"+this.age )
			}
			eat(){
				console.log( "eat...." )
			}
		}
	
		var p1 = new Person( "kimoo",27 );
		console.log( Person.prototype );	//{constructor: ƒ, say: ƒ, eat: ƒ}
//		Person("kimoo",27)//出错

</script>

  

<script>
	class Person{
		constructor(name,age){
			this.name = name;
			this.age = age;
		}
		//加上static将变成静态方法或静态属性,必须用 父类. 来调用,如(Person.sex,Person.isHuman(1))
		static isHuman( obj ){
			return obj instanceof Person
		}
		static sex = 'man';
		say(){
			console.log( "我叫"+this.name+"今年,"+this.age )
		}
		eat(){
			console.log( "eat...." )
		}
	}
	//添加静态属性
	Person.staticProps = "miaov";
	console.log( Person.sex );				//man
	console.log( Person.staticProps )		//miaov
	var p1 = new Person( "kimoo",27 );	
	// p1.say();
	// p1.isHuman();// 静态方法,报错
	console.log( Person.isHuman( 1 ) );		//false
	console.log( Person.isHuman( p1 ) );	//true
	// var str = "妙";
	// console.log( str.charCodeAt(0) ) //22937
	// console.log( String.fromCharCode( 22937 ) ) 

</script>
<script>
	class Person{
		constructor(name,age){
			this.name = name;
			this.age = age;
		}
		static isHuman( obj ){
			// console.log( "isHuman" )
			return obj instanceof Person
		}
		say(){
			console.log( "我叫"+this.name+"今年,"+this.age );
		}
		eat(){
			console.log( "eat...." );
		}
	}
	//继承必须加super()继承父级属性,
	class Coder extends Person{
		constructor(name,age,money){
			super(name,age);
			this.money = money;
		}
		say(){
			console.log( "我叫"+this.name+"今年,"+this.age+",一月赚"+this.money );
		}
	}
	var c1 = new Coder("zm",30,30000);
	console.log( c1 );		//Coder
	c1.say();				//我叫zm今年,30,一月赚30000
	console.log( Coder.isHuman( c1 ) );		//true

	//继承不会改写原先父级的方法
	var p1 = new Person("momo",20);
	console.log( p1 );		//Person
	p1.say();				//我叫momo今年,20
</script>

     上面代码首先用class定义了一个,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。简单地说,constructor内定义的方法和属性是实例对象自己的,而constructor外定义的方法和属性则是所有实力对象可以共享的。Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。上面定义了一个Cat类,该类通过extends关键字,继承了Animal类的所有属性和方法。super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。ES6的继承机制,实质是先创造父类的实例对象this(所以必须先调用super方法,写在第一行),然后再用子类的构造函数修改this

<script>
	// ES5
	var Shape = function(id, x, y) {
			this.id = id,
			this.move(x, y);
		};
	Shape.prototype.move = function(x, y) {
			this.x = x;
			this.y = y;
		};
	 
	var Rectangle = function id(ix, x, y, width, height) {
			Shape.call(this, id, x, y);
			this.width = width;
			this.height = height;
		};
	Rectangle.prototype = Object.create(Shape.prototype);
	Rectangle.prototype.constructor = Rectangle;
	 
	var Circle = function(id, x, y, radius) {
	Shape.call(this, id, x, y);
			this.radius = radius;
		};
	Circle.prototype = Object.create(Shape.prototype);
	Circle.prototype.constructor = Circle;
	 
	// ES6
	class Shape {
	constructor(id, x, y) {
			this.id = id;
			this.move(x, y);
		}
	move(x, y) {
			this.x = x;
			this.y = y;
		}
	}
	 
	class Rectangle extends Shape {
	constructor(id, x, y, width, height) {
			super(id, x, y) this.width = width this.height = height;
		}
	}
	 
	class Circle extends Shape {
	constructor(id, x, y, radius) {
			super(id, x, y) this.radius = radius;
		}
	}

</script>

解构赋值

<script>
    var obj = {
		name: "kim",
		age: 28,
		c:undefined,
		a: 1,
		b: 2
	};
	var {a,b,...r} = obj;
	console.log(r)
	/*Object
	age: 28
	c: undefined
	name: "kim"*/
	//r 可以任意写,表示从除了a,b以外其他的属性值

    //普通取值
	 var name = obj.name;
	 var age = obj.age;
	 console.log( name,age );		//kim 28

	//对对象里的属性取值,但以下方式取出来的属性名仍然是对象里的属性名
	 var {name, age} = obj;
	 console.log( name,age );		//kim 28

     var name = "";
	 ({name} = obj);
	 console.log( name );		//kim

    //以下方式可以赋值改名字
	 var { name: str } = obj;
	 console.log( str,name );	//kim kim
	 console.log( typeof str );	//string
	//以下方式给默认值,即对象中没有或undefined,则使用默认值
	 var {c=100} = obj;
	 console.log(c);	//100
	
	//赋值并给默认值
	 var {gender:g="male"} = obj;
	 console.log(g);	//male

    	//数组也与上面json一样
	 var arr = "miaov".split("");
	 var f = arr[0];
	 var s = arr[1];
	 console.log(f,s);	//m i
	 
	//不取值可以写逗号
	 var [f,s,,fouth] = arr;	
	 console.log(f,s,fouth);	//m i o
	 arr[0] = undefined;
	 console.log(arr);		// [undefined, "i", "a", "o", "v"]
	//数组同样可以用默认值
	 var [ a="123456",b,c ] = arr;
	 console.log(a,b,c);	//123456 i a
	
	 var [a="879",b,c,...r] = arr;
	 console.log( a,b,c,r )	//879 i a ["o", "v"]
    
</script>

函数

<script>
/*	 function add( a,b ){
	 ||前面出现0与undefined时,会跳到后面
	 	// var _b = b || 100;

	 	var _b = b === undefined ? 100 : b;
	 	return a+_b;
	 }*/

	 function add( a,b=100 ){
	 	return a+b;
	 }

	 console.log( add( 10 ) ) // 110
	 console.log( add( 10,5 ) ) // 15
	 console.log( add( 10,0 ) ) // 10
	 console.log( add( 10,undefined ) ) // 110

//----------------------------------------------
	 function fn( a,b, ...r ){
//	 	console.log( a,arguments );
	 	console.log( r );		// [3, 4, 5]
	 }
	 fn(1,2,3,4,5)

	 /*function add(a,b){
	 	return a+b
	 }*/
	
	//箭头函数省略function,若是return输出,则可以省略return和{}
	// var add = (a,b)=>{return a+b}
	
	//若是return输出,则可以省略return和{}
	// var add = (a,b)=>a+b
	
//			若想输出对象,则需加()
	 var add = (a,b)=>({miaov: 3})
	console.log( add );		//(a,b)=>({miaov: 3})
	
	//若没有加(),则会变成表达式标签
	 var add = (a,b)=>{
	 	miaov: for( var i = 0;i<10;i++ ){
	 		console.log( i )
	 		if( i==3 ){
	 			break miaov;
	 		}
	 	}
	 }
	
	//若只有一个参数时,可以把(a)写成a,省略()。但如果没有传参数时,必须写()
	 var add = a=> a*100
	 console.log( add(2) )


	//.filter => 过滤
	 var arr = [10,2,31,48,15,6];
	// var res = arr.filter( function(item){
	// 	return item > 20
	// } );
		
	 var res = arr.filter( item=>item > 20 )
	 console.log( res )

//----------------------------------------------

//箭头函数可以用...
	var fn = (...r)=>{
		 console.log( this )	//Window 
//		console.log( arguments );
		//arguments is not defined
		console.log( r );	//[MouseEvent]
	}

//箭头函数,this在编写时已确定指向,不会因为谁调用而指向谁
/*	 var fn = function(){
	 	console.log( this )
	 }*/
/*	 var fn = () =>{
	 	console.log( this );
	 }
	 fn(1,2,3) 
			 fn.bind({a:1});   .bind()依然无法修改this指向*/
	 document.onclick = fn;
	
	//箭头函数不能new,没有arguments
	// var obj = new fn();
</script>

arrow functions (箭头函数)

函数的快捷写法。不需要 function 关键字来创建函数,省略 return 关键字,继承当前上下文的 this 关键字

<script>
	// ES5
	var arr1 = [1, 2, 3];
	var newArr1 = arr1.map(function(x) {
	return x + 1;
	});
	 
	// ES6
	let arr2 = [1, 2, 3];
	let newArr2 = arr2.map((x) => {
	x + 1
	});
</script>

箭头函数小细节:当你的函数有且仅有一个参数的时候,是可以省略掉括号的;当你函数中有且仅有一个表达式的时候可以省略{}

<script>
	let arr2 = [1, 2, 3];
	let newArr2 = arr2.map(x => x + 1);
</script>

JavaScript语言的this对象一直是一个令人头痛的问题,如setTimeout中的this指向的是全局对象。

<script>
	class Animal {
	constructor() {
		this.type = 'animal';
	}
	says(say) {
	setTimeout(function() {
				console.log(this.type + ' says ' + say);
			}, 1000);
		}
	}	 
	var animal = new Animal();
	animal.says('hi'); //undefined says hi
</script>

解决办法:

<script>
	class Animal {
	constructor() {
		this.type = 'animal';
	}

    // 传统方法1: 将this传给self,再用self来指代this
	says(say) {
	var self = this;
	setTimeout(function() {
		console.log(self.type + ' says ' + say);
		}, 1000);
	}
	 
	// 传统方法2: 用bind(this),修改this指向,即
	says(say) {
	setTimeout(function() {
		console.log(this.type + ' says ' + say);
		}.bind(this), 1000);
	}
	 
	// ES6: 箭头函数
	// 当我们使用箭头函数时,函数体内的this对象,就是定义时所在的对象
	says(say) {
	setTimeout(() => {
		console.log(this.type + ' says ' + say);
			}, 1000);
		}
	}
	
	var animal = new Animal();
	animal.says('hi');

</script>

字符串

<script>
	 var str = "miaovketang";
	 console.log( str.indexOf("ke") !== -1 );	//true
	
	//includes() => 检查字符串中是否包括
	 console.log( str.includes("zzz") );		//false
	
	//startsWith() => 以()开头
	 console.log( str.startsWith("miao") );		//true
	 console.log( str.startsWith("iao") );		//false

	//endsWith => 以()结尾
	 console.log( str.endsWith("tang") );		//true
	 console.log( str.endsWith("tan") );		//false

	//repeat() => 重复打印()遍
	 var str = "miaovketang |";
	 console.log( str.repeat(3) );		//miaovketang |miaovketang |miaovketang |
	 console.log( str );				//miaovketang |
	
	//``超级运算符,里面可传参${},可以回车,空格不会报错;还可以三目运算,调用函数
	 var classStr = "yellow"
 		var html = `
 <ul>
 	<li class="red"></li>
<li class='green'></li>
<li class='${classStr}'></li>
 </ul>`
 		console.log( html )

		 var n = 2;
		 var m = 3;
		 console.log( "n+m="+(n+m) )  
	 console.log( `n+m=${n+m}` )

	 var isRaining = false
	 console.log( `今天天气是 ${ isRaining?"雨天":"晴天" }` )

	function fn(){
		return "miaov"
	}
	console.log( `fn执行结果是 : ${ fn() }` )
</script>

template string (模板字符串)

解决了 ES5 在字符串功能上的痛点。

第一个用途:字符串拼接。将表达式嵌入字符串中进行拼接,用 ` 和${}`来界定。

<script>
    // es5
    var name1 = "bai";
    console.log('hello' + name1);	//hellobai
 
    // es6
    const name2 = "ming";
    console.log(`hello${name2}`);	//helloming
</script>

第二个用途:在ES5时我们通过反斜杠来做多行字符串拼接。ES6反引号 `` 直接搞定。

<script>
    // es5
    var msg = "Hi \
    man!";
 
    // es6
    const template = `<div>
    <span>hello world</span>
    </div>`;

    console.log(msg);		//Hi man!
    console.log(template);	
    /*<div>
    <span>hello world</span>
    </div>*/
</script>

另外:includes repeat

<script>
	// includes:判断是否包含然后直接返回布尔值
	let str = 'hahah';
	console.log(str.includes('y')); // false
	 
	// repeat: 获取字符串重复n次
	let s = 'he';
	console.log(s.repeat(3)); // 'hehehe'
</script>

destructuring (解构)

简化数组和对象中信息的提取。

ES6前,我们一个一个获取对象信息;

ES6后,解构能让我们从对象或者数组里取出数据存为变量

<script>
	// ES5
	var people1 = {
		name: 'bai',
		age: 20,
		color: ['red', 'blue']
	};
	 
	var myName = people1.name;
	var myAge = people1.age;
	var myColor = people1.color[0];
	console.log(myName + '----' + myAge + '----' + myColor);
	//bai----20----red
	
	// ES6
	let people2 = {
		name: 'ming',
		age: 20,
		color: ['red', 'blue']
	}
	//解构
	let { name, age } = people2;
	let [first, second] = people2.color;
	console.log(`${name}----${age}----${first}`);
	//ming----20----red
</script>

default 函数默认参数

<script>
	// ES5 给函数定义参数默认值
	function foo(num) {
	num = num || 200;
	return num;
	}
	 
	// ES6
	function foo(num = 200) {
	return num;
	}
</script>

rest arguments rest参数)

解决了 es5 复杂的 arguments 问题

<script>
	//继承也可以用...
	function foo(x, y, ...rest) {
		console.log((x + y) * rest.length)
		return ((x + y) * rest.length);
	}
	foo(1, 2, 'hello', true, 7); // 9
</script>

Spread Operator (展开运算符)

第一个用途:组装数组

<script>
	let color = ['red', 'yellow'];
	let colorful = [...color, 'green', 'blue'];
	console.log(colorful); // ["red", "yellow", "green", "blue"]
</script>

第二个用途:获取数组除了某几项的其他项

<script>
	let num = [1, 3, 5, 7, 9];
        //解构
	let [first, second, ...rest] = num;
	console.log(rest); // [5, 7, 9]
</script>

对象

对象初始化简写

<script>
	// ES5
	function people(name, age) {
		return {
		name: name,
		age: age
		};
	}
	 
	// ES6
	function people(name, age) {
		return {
		//当键名与键值相同时,可省略
		name,
		age
		};
	}
</script>

对象字面量简写(省略冒号与 function 关键字)

<script>
	// ES5
	var people1 = {
	name: 'bai',
	getName: function () {
		console.log(this.name);
		}
	};
	 
	// ES6
	let people2 = {
	name: 'bai',
	getName () {
		console.log(this.name);
		}
	};
</script>

另外:Object.assign()

ES6 对象提供了Object.assign()这个方法来实现浅复制。Object.assign()可以把任意多个源对象自身可枚举的属性拷贝给目标对象,然后返回目标对象。第一参数即为目标对象。在实际项目中,我们为了不改变源对象。一般会把目标对象传为{}

<script>
	objA = {
		a:1
	}
	objB = {
		b:2
	}
	const obj = Object.assign({}, objA, objB) 
	console.log(obj)	//{a: 1, b: 2}
	// 给对象添加属性
	this.seller = Object.assign({}, this.seller, response.data)	
</script>

Promise

用同步的方式去写异步代码

<script>
	// 发起异步请求
	fetch('/api/todos')
	.then(res => res.json())
	.then(data => ({
	data
	}))
	.catch(err => ({
	err
	}));

	//Promise 封装异步请求demo

	export default function getMethods (url){
	    return new Promise(function(resolve, reject){
	        axios.get(url).then(res => {
	            resolve(res)
	        }).catch(err =>{
	            reject(err)
	        })
	    })
	}
	
	getMethods('/api/xxx').then(res => {
	    console.log(res)
	}, err => {
	    console.log(err)
	})
</script>
<script>	
    // 异步编程解决方案

	 var p = new Promise( ( resolve,reject )=>{
	 	console.log( "实例化..." );        //实例化...
		
	 	return resolve("成功!");
	 	 reject();
	 	 console.log( "222" );
	 } );

	  console.log( p )        //Promise {<resolved>: "成功!"}
        /*  __proto__: Promise
		[[PromiseStatus]]: "resolved"
		[[PromiseValue]]: "成功!"*/

	 p.then( ( data )=>{
	 	console.log( "then: ",data )   //then:  成功!
	 } )

     //主任务,隐式任务,队列		
			 console.log( 1 );
				
			 setTimeout( ()=>{
			 	console.log( 3 );
			 } )
	
			 setTimeout( ()=>{
			 	console.log( 4 );
			 } )
	
			 var p = new Promise( (res,rej)=>{
			 	console.log( 5 )
			 	res()
			 } )
	
			 p.then( ()=>{ 
			 	console.log( 6 )
			 } )
	
			 console.log( 2 );
//打印顺序:1,5,2   6   3,4


</script>
<script>
	 var p = new Promise( (res,rej)=>{
	 	res("成功")
//			 	 rej();
	 } )

	 p.then( (data)=>{
	 	console.log( data + "这里" )		//res表成功,会传递数据 =>成功这里
	 },()=>{
	 	console.log( "失败" + "走这里" )	//rej表失败,不会传递数据 =>失败走这里
	 } )
	
//			.catch是then的第二个参数,表失败
	 p.catch( ()=>{
	 	console.log( "失败" + "来吧")		//rej表失败,不会传递数据 =>失败走这里
	 } )
	 
	 var p2 = p.then( (data)=>{
		 console.log( data + "在哪呢")	//es表成功,会传递数据 =>成功在哪呢
	 } )
	 console.log( p2 === p )		//false
</script>
<script>
     var p = new Promise( (res,rej)=>{
	 	res("成功")
	 } )
     var p2 = p.then( ()=>{ return new Promise( (res,rej)=>{rej(111)} ) } );
	 //Uncaught (in promise) 111
	 //返回状态为rejected,值为222,但报错,应用.catch方法
	 var p2 = p.catch( ()=>{ return new Promise( (res,rej)=>{rej(222)} ) } );
     //返回状态为resolved,值为"成功",不是222
	 var p2 = p.then( ()=>{ return new Promise( (res,rej)=>{res(333)} ) } )
     //返回状态为resolved,值为333
	 
	 console.log( p2 )

	 p2.then( data=>{
	 	console.log( "p2 then: ",data )
	 } )
</script>
<script>
    var p = new Promise( (res,rej)=>{
			res("成功")
	} )	
	var res =  p.then( ()=>{
		console.log( 1 )
	} )
	.then( ()=>{
		console.log( 2 )
		//a
		//不注释a此处出错,不会执行下个then,即不会打印出3
	} )
	.then( ()=>{
		console.log( 3 )
		b
	} )
	//捕获异常,不会报错
	.catch( (err)=>{
		console.log( err )	//ReferenceError: b is not defined
	} )
	//.finally结束语句
	.finally( ()=>{
		console.log( "执行完了..." )	//finally是无论程序对错,一定会走这里
	} )			
	console.log( 333 )
	
/*	输出结果为:
	333
	1
	2
	3
	ReferenceError: b is not defined
	执行完了...*/
</script>
<script>
     var p = new Promise( (res,rej)=>{res()} )
	 p
	 .then( ()=>{ console.log(1) } )
	 .then( ()=>{ return new Promise( (res,rej)=>{res(200)} ) } )
				
	 .then( (data)=>{ return Promise.resolve( data) })	//调用.resolve可省略new Promise( (res,rej)=>{res(...)} ),要么res,要么rej
	 .then( ()=>{ return Promise.reject( "失败!" ) }) //调用.reject可省略new Promise( (res,rej)=>{rej(...)} )
	 .then( (data)=>{ console.log(data+"跑这里了") } ) 	
	 .catch( (err)=>{ console.log( err+"这里这里" ) } )
	/* 打印结果:
	 1 200跑这里
	 打开Promise.reject("失败:")会覆盖.resolve这一状态,结果变成了
	 1 失败!这里这里*/
</script>
<script>
	var p1 = new Promise( (res,rej)=>{
		setTimeout( ()=>{
			res("a")
		},1000 )
	} )
	var p2 = new Promise( (res,rej)=>{
		setTimeout( ()=>{
			res("b")
		},1500 )
	} )
	var p3 = new Promise( (res,rej)=>{
		setTimeout( ()=>{
			res("c")
		},500 )
	} )
	
//	var p = Promise.all( [p1,p2,p3] );	//all()一起执行完再打印	["a", "b", "c"]
	var p = Promise.race( [p1,p2,p3] );		//.race()时间最快的	c
	console.log( p )		//Promise {<pending>}
	p.then( data=>console.log( data ) )
</script>
//promise运动实例
<script>
	/* function move( obj,attr,target,duration,callback ){
	 	var b = parseInt(getComputedStyle(obj)[attr]);
	 	var c = target - b; 
	 	var d = duration;
	 	var temp = new Date().getTime();
	 	var timer = setInterval( function(){
	 		var t = new Date().getTime()-temp;
	 		if( t >= d ){
	 			clearInterval( timer );
	 			t = d;
	 		}
	 		var v = c/d*t+b ;
	 		obj.style[attr] = v + "px";
	 		if( t === d ){
	 			typeof callback === "function" && callback();
	 		}
	 	},20 )
	 }
	
	 move( box,"width",200,500,()=>{
	 	move( box,"height",300,500,()=>{
	 		move( box,"left",300,500,()=>{
	 			move( box,"top",200,500)
	 		})
	 	})
	 } )*/
	var box = document.getElementById( 'box' );
	function movePromise( obj,attr,target,duration ){
		return new Promise( (res,rej)=>{
			var b = parseInt(getComputedStyle(obj)[attr]);
			var c = target - b; 
			var d = duration;
			var temp = new Date().getTime();
			var timer = setInterval( function(){
				var t = new Date().getTime()-temp;			
				var v = c/d*t+b ;
				obj.style[attr] = v + "px";
				if( t >= d ){
					clearInterval( timer );
					res();
				}
			},20 )
		} )
	}
	movePromise( box,"width",200,500 )
	.then( ()=>movePromise( box,"height",300,1000 ) )
	.then( ()=>movePromise( box,"left",300,1000 ) )
	.then( ()=>movePromise( box,"top",200,1000 ) )
	.then( ()=>console.log( "done" ) )
</script>

Generators

生成器( generator)是能返回一个迭代器的函数。

       生成器函数也是一种函数,最直观的表现就是比普通的function多了个星号*,在其函数体内可以使用yield关键字,有意思的是函数会在每个yield后暂停。这里生活中有一个比较形象的例子。咱们到银行办理业务时候都得向大厅的机器取一张排队号。你拿到你的排队号,机器并不会自动为你再出下一张票。也就是说取票机“暂停住了,直到下一个人再次唤起才会继续吐票。

       迭代器:当你调用一个generator时,它将返回一个迭代器对象。这个迭代器对象拥有一个叫做next的方法来帮助你重启generator函数并得到下一个值。next方法不仅返回值,它返回的对象具有两个属性:donevaluevalue是你获得的值,done用来表明你的generator是否已经停止提供值。继续用刚刚取票的例子,每张排队号就是这里的value,打印票的纸是否用完就这是这里的done

<script>
	// 生成器
	function *createIterator() {
	yield 1;
	yield 2;
	yield 3;
	}
	 
	// 生成器能像正规函数那样被调用,但会返回一个迭代器
	let iterator = createIterator();
	 
	console.log(iterator.next().value); // 1
	console.log(iterator.next().value); // 2
	console.log(iterator.next().value); // 3
</script>

迭代器对异步编程作用很大,异步调用对于我们来说是很困难的事,我们的函数并不会等待异步调用完再执行,你可能会想到用回调函数,(当然还有其他方案比如Promise比如Async/await)。生成器可以让我们的代码进行等待。就不用嵌套的回调函数。使用generator可以确保当异步调用在我们的generator函数运行一下行代码之前完成时暂停函数的执行。

那么问题来了,咱们也不能手动一直调用next()方法,你需要一个能够调用生成器并启动迭代器的方法。就像这样子的:

<script>
	function run(taskDef) {
		// taskDef 即一个生成器函数
		// 创建迭代器,让它在别处可用
		let task = taskDef();
		 
		// 启动任务
		let result = task.next();
		 
		// 递归使用函数来保持对 next() 的调用
		function step() {
		// 如果还有更多要做的
		if (!result.done) {
			result = task.next();
			step();
			}
		}	 
	// 开始处理过程
	step();
	}
</script>

js 中 Map/Set 集合

Map(一)

Map是一组键值对的结构,具有极快的查找速度。

举个例子,假设要根据同学的名字查找对应的成绩,如果用Array实现,需要两个Array: 

var names = ['Michael', 'Bob', 'Tracy'];
var scores = [95, 75, 85]; 

给定一个名字,要查找对应的成绩,就先要在names中找到对应的位置,再从scores取出对应的成绩,Array越长,耗时越长。

如果用Map实现,只需要一个“名字”-“成绩”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢。用JavaScript写一个Map如下: 

var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95 

初始化Map需要一个二维数组,或者直接初始化一个空MapMap具有以下方法:

var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined

由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉:

var m = new Map();
m.set('Adam', 67);
m.set('Adam', 88);
m.get('Adam'); // 88 

Set(一)

SetMap类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。

要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set: 

var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3 

重复元素在Set中自动被过滤:

var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"} 

注意数字3和字符串'3'是不同的元素。

通过add(key)方法可以添加元素到Set中,可以重复添加,但不会有效果: 

<script>
	var s = new Set([1, 2, 3, 3, '3']);
	s.add(4)
 	console.log( s )
/* 	0: 1
	1: 2
	2: 3
	3: "3"
	4: 4
	length: 5*/

    s.add(4)
	console.log( s )
	//Set(5) {1, 2, 3, "3", 4}
</script>

通过delete(key)方法可以删除元素

Map(二)

<script>
	 var obj = {
	 	name: "miaov"
	 };
	 var momo = {
	 	name: "m"
	 };
	 console.log(momo.toString())	//[object Object]
	 obj[momo] = 1;
	 console.log( obj )		//Object   
	/* [object Object]: 1
	name: "miaov"*/
</script>
<script>
     var m = new Map([ ["name","miaov"],["aaa",200] ]);
	 console.log( m.size );				//2
	 console.log( m.get( "name" ) )		//miaov
	 m.set( "age",100 );
	 var momo = { name: "m" };
	 m.set( momo,1 );
	 console.log( m );	//Map(4) {"name" => "miaov", "aaa" => 200, "age" => 100, {…} => 1}
     var res = m.delete( momo );
	 var res = m.delete( "z" );
		
	 console.log( m );		//Map(3) {"name" => "miaov", "aaa" => 200, "age" => 100}
	 console.log( m.has( momo ) );		//false
	 console.log( m.has( "z" ) );		//false

     m.forEach( function( item,key,map ){
			 	console.log(item,key,map)
			 } )
			 /*miaov name Map(3) {"name" => "miaov", "aaa" => 200, "age" => 100}
			 200 "aaa" Map(3) {"name" => "miaov", "aaa" => 200, "age" => 100}
			 100 "age" Map(3) {"name" => "miaov", "aaa" => 200, "age" => 100}*/
    var res = m.keys();
	 console.log( res.next() );		//{value: "name", done: false}
	 console.log( res.next() );		//{value: "aaa", done: false}
	 console.log( res.next() );		//{value: "age", done: false}
	 console.log( res.next() );		//{value: undefined, done: true}

	 var res = m.values();
	 console.log( res.next() );		//{value: "miaov", done: false}
	 console.log( res.next() );		//{value: 200, done: false}
	 console.log( res.next() );		//{value: 100, done: false}
	 console.log( res.next() );		//{value: undefined, done: true}

	 var res = m.entries();
	 console.log( res.next() );		//{value: Array(2), done: false}
	 console.log( res.next() );		//{value: Array(2), done: false}
	 console.log( res.next() );		//{value: Array(2), done: false}
	 console.log( res.next() );		//{value: undefined, done: true}

    //两个不同的对象{}
	 m.set( {},2 );
	 m.set( {},3 );
	 console.log( m.get( {} ) );	//undefined

	//后者会覆盖前者
	 var obj = {};
	 m.set( obj,2 );
	 m.set( obj,3 );

	console.log( m.get( obj ) );	//3

</script>

set(二)

<script>
	var s = new Set(["a","b","c"]);
/*	console.log(s.size); 			 //=> 对象的长度
	s.add( 1 ).add( 2 ).add( 1 );	// => 不会添加相同的元素
	
	//尽管 NaN === NaN 为false,还是不能重复添加NaN
	 s.add( NaN ).add( NaN );
	 console.log(s)

	//删除元素
	var res = s.delete( "b" );
	//var res = s.delete( "z" );	//false
	console.log( res );		//true
	console.log( s );	//Set(2) {"a", "c"}
	
	//判断是否存在某元素
	// console.log(s.has("a"))
	// console.log(s.has("x"))
	
	//清除对象的元素
	s.clear();
	console.log( s );	//Set(0) {}*/

    //forEach遍历对象里的key,value,整个对象
/*	s.forEach( function(item,index,set){
	 	console.log( item,index,set )
	 	a a Set(3) {"a", "b", "c"}
	 	b b Set(3) {"a", "b", "c"}
	 	c c Set(3) {"a", "b", "c"}
	} )*/
    
    //此处keys与values相同
    /*	var keys = s.keys();
	console.log( keys );
	console.log( keys.next() )	//{value: "a", done: false}
	console.log( keys.next() )	//{value: "b", done: false}
	console.log( keys.next() )	//{value: "c", done: false}
	console.log( keys.next() )	//{value: undefined, done: true}*/

    /*var values = s.values();
	console.log( values.next() )	//{value: "a", done: false}
	console.log( values.next() )	//{value: "b", done: false}
	console.log( values.next() )	//{value: "c", done: false}
	console.log( values.next() )	//{value: undefined, done: true}*/

    //整一个对象
/*	var entries = s.entries();
	console.log( entries.next() )	//{value: Array(2), done: false}
	console.log( entries.next() )	//{value: Array(2), done: false}
	console.log( entries.next() )	//{value: Array(2), done: false}
	console.log( entries.next() )	//{value: undefined, done: true}

	console.log( s );	//Set(3) {"a", "b", "c"}*/

    var arr = [1,2,3,2,3,5,4,"1",NaN,NaN];
	var s = new Set(arr);
	console.log( s );
/*	0: 1
	1: 2
	2: 3
	3: 5
	4: 4
	5: "1"
	6: NaN
	length: 7*/
	//用以上方法去重
</script>

Synbol

<script>
	//symbol => 加标记,独一无二,不会被覆盖
	
	 var s = Symbol( "a" );
	 console.log( typeof s ) //"symbol"
	 console.log( s ) // Symbol(a)
	
	 var s2 = Symbol( "b" );
	 console.log( s2 ) // Symbol(b)
	
	 console.log( s === s2 );	//false

    var s3 = new Symbol();		//出错
	//Symbol is not a constructor
    
    //下面方法会覆盖原来的值
	 var obj = {
	 	a: 1
	 }
	 obj.b = 2;
	 obj.a = 3;
	 console.log( obj );		//{a: 3, b: 2}			
	//Symbol("a") => 括号里的"a"只是标记			
	 var a = Symbol("a");
	 obj[ a ] = "sa";
	 console.log( obj );		
	 //{a: 3, b: 2, Symbol(a): "sa"}	
	 var b = Symbol("a");	
	 obj[ b ] = "sb";
	 console.log( obj )
	//{a: 3, b: 2, Symbol(a): "sa", Symbol(a): "sb"}

     for( var attr in obj ){
	 	console.log( obj[attr] )
	 	//3 2
	 }
	
	//获取symbol值
	 console.log( Object.getOwnPropertySymbols( obj ) )
	// [Symbol(a), Symbol(a)]

    var s = Symbol();
//	console.log( s + 1 );
	//Cannot convert a Symbol value to a number
//	console.log( s + "a" );
	// Cannot convert a Symbol value to a string
	// !! => 转布尔值
	console.log( !!s );		//true
	console.log( Boolean( s ) );	//true
</script>

遍历接口

<script>
    /*	var els = document.getElementsByTagName("*");
	
		遍历所有	for( var attr of ele )
		for( var attr of els ){
			console.log( attr )
		}*/
	var arr = [10,20,30];
	/*console.log( arr[Symbol.iterator] );
	ƒ values() { [native code] }*/
	
	var k = arr.keys();
	console.log( k.next() );	//{value: 0, done: false}
	console.log( k.next() );	//{value: 1, done: false}
	console.log( k.next() );	//{value: 2, done: false}
	console.log( k.next() );	//{value: undefined, done: true}
	
	//模拟.keys()及.next()
	/*var k = i( arr );
	console.log( k.next() );	//{value: 0, done: false}
	console.log( k.next() );	//{value: 1, done: false}
	console.log( k.next() );	//{value: 2, done: false}
	console.log( k.next() );	//{value: undefined, done: true}
	
	function i( obj ){
	 	var index = -1;
	 	return {
	 		next: function(){
	 			index ++
	 			return  index < obj.length 
	 				? {
	 					value: index,
	 					done: false
	 				}
	 				:{
	 					value: undefined,
	 					done: true
	 				} 
	 		}
		}
	}*/
</script>

对象

<script>
     var a = 1;
	 var obj = {
	 	a: a,
	 	fn: function(){
	 		console.log( "fn" )
	 	}
	 }
//-------------------------------------------------
	 var obj = { 
	 	a,	//此处为a:a省略,原因是属性值与外部变量相同时,可简写	
	 	fn(){
	 		console.log( "fn执行了" )
	 	},
	 	b: 100
	 };
	 console.log( obj )		//{a: 1, fn: ƒ, b: 100}
	 obj.fn();				//fn执行了

//-------------------------------------------------
	 var attrname = "width";
	 var attrname = "height";
	 
	 var attrObj = {};
	 var attrFn = "fn";
	 var obj = {
	 	//解决键名可变问题
	 	[attrname]: 100,
	 	//对象不可以作为键名
	 	[attrObj]: "hello",
	 	//[attrFn]相当于fn
	 	[attrFn](){
	 		console.log( "attrFn执行了" )
	 	}
	 }
	 console.log( obj )		//{height: 100, [object Object]: "hello", fn: ƒ}
	 obj.fn()		//attrFn执行了
//-------------------------------------------------
	 console.log( 1 == "1" )//true
	 console.log( NaN === NaN )//false
	 console.log( NaN == NaN )//false
	 console.log( Object.is( 1,1 ) )//true
	 console.log( Object.is( 1,"1" ) )//false
	 console.log( Object.is( NaN,NaN ) )//true,解决了NaN不能判断的情况
	 console.log( Object.is( {},{} ) )//false,两个{}各自创建了新的空间
	 var obj = {};
	 console.log( Object.is( obj,obj ) )//true,同一对象obj
//--------------------------------------------------
	//新的值传入改变默认值,旧方法
	 function move(obj){
	 	var defaultObj = {
	 		ease: "linear",
	 		duration: 1000
	 	}
/*	 	 var para = {
	 	 	ease: obj.ease || defaultObj.ease,
	 	 	duration: obj.duration || defaultObj.duration
	 	 }*/
		
	//新的值传入改变默认值,新方法,Object.assign(),括号里的值越后面,等级越高,可以替换掉前面相同的属性值
	 	var para = {}
	 	Object.assign( para,defaultObj,obj )
	 	console.log( para )
	 }
	 move({
	 	duration: 2000
	 })
//-----------------------------------------------------
//	for( var attr of Object.keys(obj) ) => 遍历对象键名。values => 键值,entries => 键值+键名
	 var obj = {
	 	a: 1,
	 	b: 2
	 }
	
	 console.log( Object.keys(obj) )		// ["a", "b"]
	 console.log( Object.values(obj) )		// [1, 2]
	 console.log( Object.entries(obj) )		// [Array(2), Array(2)]

//	 for( var attr of Object.values(obj) ){
//		[key,val] => 解构赋值
	 for( var [key,val] of Object.entries(obj) ){
	 	console.log( key,val )
	 	/*a 1
		b 2*/
	 }
//-------------------------------------------------------
	 var obj = {
	 	a: 1,
	 	b: 2
	 }
	 var res = {
//				类似继承    ...
	 	...obj,
	 	c: 3
	 }
	 console.log( res )		//{a: 1, b: 2, c: 3}

	 var arr = [1,2,3,4];	
	 console.log( arr );	// [1, 2, 3, 4]
	// console.log( 1,2,3,4 );
	// ...可将数组值变成参数
	 console.log( ...arr );	//1 2 3 4
		
	 var arr = [1,23,4,5];
	  //=> 求数组的最大值
	 console.log( Math.max( 1,23,4,5 ) );	//23
	 console.log( Math.max( ...arr ) );	  //23
	
     var arr = [1,1,12,2,3,2,1,2];
	 //去重 => 先转化为Set对象,再用...将其转化为参数,然后在[]变为数组
	 var res = [...new Set(arr)];
	 console.log( res );		//[1, 12, 2, 3]

</script>

弱引用

<script>
	var m = new Map();
	var wm = new WeakMap();

	var zm = {
		name: "zmouse",
		age: 30
	};
	var reci = {
		name: "reci",
		age: 20
	}
	//对象作为键值
	 m.set( zm,"miaov" );
	 m.set( reci,"miaov2" );
	 m.set( 1,"miao3" );
	 for( var v of m ){
		console.log(v)
		//[{…}, "miaov"]  [{…}, "miaov2"]  [1, "miao3"]
	}
	wm.set( zm,"miaov1" );
	wm.set( reci,"miaov3" );

	console.log( wm );	//WeakMap {{…} => "miaov3", {…} => "miaov1"}
	//Map()为强引用,null清不了里面存进去的对象,m(a,b)中a可以不为对象。
	//WeakMap()为弱引用不能使用for-of方法,可以用null清除对象,且wm(a,b)中a必须为对象。
/*	for( var v of wm ){
		console.log(v)
		//wm is not iterable
	}*/
</script>

数组

<script>
	// new Array(10) => 创建长度为10的数组; Array.of(10) => 是添加元素为10
	/* var arr = new Array(10,20,30) //(3) [10, 20, 30]
	 var arr = new Array(10)	 //[empty × 10]
	
	
	 var arr = Array.of(10,20,30)	//(3) [10, 20, 30]
	 var arr = Array.of(10)		//[10]
	console.log( arr );
	
	//document.all <=> document.getElementsByTagName("*")
	 var els = document.all
	 var els = document.getElementsByTagName("*")
	 console.log( els )
	//HTMLCollection(6) [html, head, meta, title, body, script]
	
	//Array.from => 转化为数组,Array.isArray() => 检查()是否为数组 
	 var arrEls = Array.from( els );

	 console.log( Array.isArray( els ) )		//false
	 console.log( Array.isArray( arrEls ) )		//true  */

    	var arr = [10,20,60,30,40,50];
	var res = arr.find( function( item ){
	 	console.log(item)
	 	return item > 50
	 	//.find => 当item>50时,跳出循环,返回对应值
	 } )
	 console.log( res ) 
	//10 20 60 60
	
	var res = arr.findIndex( function( item ){
		console.log(item)
		return item > 50
		//.findIndex => 当item>50时,跳出循环,返回对应下标
	} )
	console.log( res ) 
	//10 20 60 2
</script>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值