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); // undefinedvar a = 'hello1';// 上面的代码相当于,即预编译var a;console.log(a); //hello1a = 'hello1';// 而 let 就不会被变量提升;且不能重复对同一变量声明赋值,可以写成 a='hello',但不能let声明console.log(a); // hello1//报错,SyntaxError: Identifier 'a' has already been declareda = 'hello2';let a = 'hello2';
</script>
<script>console.log(a); //undefinedvar 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 initializationlet b = 2;let b = 200;// Identifier 'b' has already been declaredconsole.log(b);
</script>
const 定义的常量不能被修改
<script>var name = "bai";name = "ming1";console.log(name); // ming1const 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 = 1obj.name = "kimoo";console.log( obj ) //{name: "kimoo"}
</script>
import、export
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>
class、extends、super
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 helloclass Cat extends Animal {constructor() {super();this.type = 'cat';}}let cat = new Cat();cat.says('hello'); //cat says helloclass 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 ); //manconsole.log( Person.staticProps ) //miaovvar p1 = new Person( "kimoo",27 ); // p1.say();// p1.isHuman();// 静态方法,报错console.log( Person.isHuman( 1 ) ); //falseconsole.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 ); //Coderc1.say(); //我叫zm今年,30,一月赚30000console.log( Coder.isHuman( c1 ) ); //true//继承不会改写原先父级的方法var p1 = new Person("momo",20);console.log( p1 ); //Personp1.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>// ES5var 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;// ES6class 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)/*Objectage: 28c: undefinedname: "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 28var name = "";({name} = obj);console.log( name ); //kim//以下方式可以赋值改名字var { name: str } = obj;console.log( str,name ); //kim kimconsole.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 oarr[0] = undefined;console.log(arr); // [undefined, "i", "a", "o", "v"]//数组同样可以用默认值var [ a="123456",b,c ] = arr;console.log(a,b,c); //123456 i avar [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 ) ) // 110console.log( add( 10,5 ) ) // 15console.log( add( 10,0 ) ) // 10console.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*100console.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 definedconsole.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>// ES5var arr1 = [1, 2, 3];var newArr1 = arr1.map(function(x) {return x + 1;});// ES6let 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来指代thissays(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") ); //trueconsole.log( str.startsWith("iao") ); //false//endsWith => 以()结尾console.log( str.endsWith("tang") ); //trueconsole.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 = falseconsole.log( `今天天气是 ${ isRaining?"雨天":"晴天" }` )function fn(){return "miaov"}console.log( `fn执行结果是 : ${ fn() }` )
</script>
template string (模板字符串)
解决了 ES5 在字符串功能上的痛点。
第一个用途:字符串拼接。将表达式嵌入字符串中进行拼接,用 ` 和${}`来界定。
<script>// es5var name1 = "bai";console.log('hello' + name1); //hellobai// es6const name2 = "ming";console.log(`hello${name2}`); //helloming
</script>
第二个用途:在ES5时我们通过反斜杠来做多行字符串拼接。ES6反引号 `` 直接搞定。
<script>// es5var msg = "Hi \man!";// es6const 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>// ES5var 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// ES6let 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;}// ES6function 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>// ES5function people(name, age) {return {name: name,age: age};}// ES6function people(name, age) {return {//当键名与键值相同时,可省略name,age};}
</script>
对象字面量简写(省略冒号与 function 关键字)
<script>// ES5var people1 = {name: 'bai',getName: function () {console.log(this.name);}};// ES6let 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 封装异步请求demoexport 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,值为"成功",不是222var p2 = p.then( ()=>{ return new Promise( (res,rej)=>{res(333)} ) } )//返回状态为resolved,值为333console.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 )/* 输出结果为:333123ReferenceError: 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()时间最快的 cconsole.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方法不仅返回值,它返回的对象具有两个属性:done和value。value是你获得的值,done用来表明你的generator是否已经停止提供值。继续用刚刚取票的例子,每张排队号就是这里的value,打印票的纸是否用完就这是这里的done。
<script>// 生成器function *createIterator() {yield 1;yield 2;yield 3;}// 生成器能像正规函数那样被调用,但会返回一个迭代器let iterator = createIterator();console.log(iterator.next().value); // 1console.log(iterator.next().value); // 2console.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
需要一个二维数组,或者直接初始化一个空Map
。Map
具有以下方法:
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(一)
Set
和Map
类似,也是一组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: 11: 22: 33: "3"4: 4length: 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]: 1name: "miaov"*/
</script>
<script>var m = new Map([ ["name","miaov"],["aaa",200] ]);console.log( m.size ); //2console.log( m.get( "name" ) ) //miaovm.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 ) ); //falseconsole.log( m.has( "z" ) ); //falsem.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,还是不能重复添加NaNs.add( NaN ).add( NaN );console.log(s)//删除元素var res = s.delete( "b" );//var res = s.delete( "z" ); //falseconsole.log( res ); //trueconsole.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: 11: 22: 33: 54: 45: "1"6: NaNlength: 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 ); //falsevar 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 ); //trueconsole.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" )//trueconsole.log( NaN === NaN )//falseconsole.log( NaN == NaN )//falseconsole.log( Object.is( 1,1 ) )//trueconsole.log( Object.is( 1,"1" ) )//falseconsole.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 1b 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 4var arr = [1,23,4,5];//=> 求数组的最大值console.log( Math.max( 1,23,4,5 ) ); //23console.log( Math.max( ...arr ) ); //23var 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.allvar 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 ) ) //falseconsole.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 60var res = arr.findIndex( function( item ){console.log(item)return item > 50//.findIndex => 当item>50时,跳出循环,返回对应下标} )console.log( res ) //10 20 60 2
</script>
javascript_ES6新特性相关推荐
- 我要学ASP.NET MVC 3.0(一): MVC 3.0 的新特性
摘要 MVC经过其1.0和2.0版本的发展,现在已经到了3.0的领军时代,随着技术的不断改进,MVC也越来越成熟.使开发也变得简洁人性化艺术化. 园子里有很多大鸟都对MVC了如指掌,面对问题犹同孙悟空 ...
- .NET 4.0 Interop新特性ICustomQueryInterface (转载)
.NET 4.0 Interop新特性ICustomQueryInterface 在.NET Framework v4.0发布的新功能中,在名字空间System.Runtime.InteropServ ...
- oracle如何查询虚拟列,Oracle11g新特性之--虚拟列(VirtualColumn)
Oracle 11g新特性之--虚拟列(Virtual Column) Oracle 11G虚拟列Virtual Column介绍 在老的 Oracle 版本,当我们需要使用表达式或者一些计算公式时, ...
- mysql8导入 psc 没有数据_新特性解读 | MySQL 8.0.22 任意格式数据导入
作者:杨涛涛 资深数据库专家,专研 MySQL 十余年.擅长 MySQL.PostgreSQL.MongoDB 等开源数据库相关的备份恢复.SQL 调优.监控运维.高可用架构设计等.目前任职于爱可生, ...
- mysql query browswer_MySQL数据库新特性之存储过程入门教程
MySQL数据库新特性之存储过程入门教程 在MySQL 5中,终于引入了存储过程这一新特性,这将大大增强MYSQL的数据库处理能力.在本文中将指导读者快速掌握MySQL 5的存储过程的基本知识,带领用 ...
- windows无法配置此无线连接_Kubernetes 1.18功能详解:OIDC发现、Windows节点支持,还有哪些新特性值得期待?...
Kubernetes 1.18发布,一些对社区产生影响的新特性日渐完善,如 KSA(Kubernetes Service Account) tokens的OIDC发现和对Windows节点的支持.在A ...
- java字符串去重复_Java 8新特性:字符串去重
本文首发与InfoQ. 8月19日,Oracle发布了JDK 8u20,JDK 8u20包含很多新特性,比如Java编译器更新.支持在运行时通过API来修改MinHeapFreeRatio和MaxHe ...
- Oracle 11g 新特性 -- Transparent Data Encryption (透明数据加密TDE) 增强 说明
一.TransparentData Encryption (TDE:透明数据加密) 说明 Orace TDE 是Orcle 10R2中的一个新特性,其可以用来加密数据文件里的数据,保护从操作系统层面上 ...
- .NET Framework 4.0的新特性
本文将揭示.NET 4.0中的3个新特性:图表控件.SEO支持以及ASP.NET 4可扩展的输出缓存. 图表控件 微软向开发者提供了大量可免费下载的图表控件,可以在.NET 3.5 ASP.NET或W ...
最新文章
- elasticsearch多表关联查询_Mybatis【15】 Mybatis如何实现一对一的情况多表关联查询?...
- Linux中yum和apt-get
- 判断任意控制台输入的十进制数是否为水仙花数
- python脚本语言采用声音作为手段_LKJ自动化测试脚本定义及生成技术研究
- Magento 获取当前店铺信息(首页,类别,地址等)
- 苹果将允许iPhone直接使用NFC接受信用卡付款
- 在gns3中搭建VTP演示实验
- teradata 数据定义
- 成为数据分析师需要具备的知识体系
- Java滑动窗口的最大值
- 倒立摆源码 旋转倒立摆 完整全功能 程序 倒立摆 pid算法 程序使用时可根据硬件需要自行调节
- AirTest进行自动化测试
- android定义圆角layout,Android布局切圆角
- 2021.02.17 GDKOI2021 好题记 第一记
- [Python] 开发植物大战僵尸游戏
- html首页问候语,每日一条问候语
- jsp+ssm计算机毕业设计宠物寻回系统【附源码】
- 精华文稿|用于无监督双目立体匹配学习的视差注意力机制
- java面经——基础篇(1)
- 通过Office 2007发布Blog