ECMAScript6新特性 | 总字数: 6.6k | 阅读时长: 26分钟 | 浏览量: |
let变量声明以及声明特性 let a;let a,b,c;let a=100 ;
特性:
let变量不能重复声明,但是var却可以。
块级作用域:变量只在代码块里有效,在代码块外无效。[全局、函数、eval]
不存在变量提升。(如果有变量提升,可以在变量未声明之前去使用这个变量)
不影响作用域链。
{ let name = "xiaolin0333" ; function fn ( ) { console .log (name); } fn (); }
const声明常量及其特点 const NAME = "xiaolin0333" ;
特性:
一定要赋初始值。
一般常量使用大写(潜规则)
常量值不能修改。
块级作用域
对于数组和对象的元素修改,不算对常量的修改,不会报错
const DATA = ['xiaolin' ,'03' ,'cmb' ];DATA .push ('dog' );DATA = 100 ;
以后声明数组或者对象的时候使用const来声明可以避免误操作
变量的解构赋值 ES6允许按照一定模式从数组和对象中提取值,对变量进行操作。
const F2 = ['lsh' ,'cmb' ];let [lin, chai] = F2 ;console .log (lin + chai);const lin = { name :'xiaolin0333' , age :18 , dadaima :function ( ) { console .log ('我可以打代码' ); } } let {name,age,dadaima} = lin;console .log (name + age);dadaima ();
【注】:一般函数使用解构的方法来写居多
let {dadaima} = lin;dadaima ();
模板字符串 ES6引入新的声明字符串的方式``
ES5:' '
或" "
特性:
内容里可以直接出现换行符(单引号、双引号不能直接出现换行符、只能用+来连接)
可以通过${变量名}
进行变量拼接
let lin = 'xiaolin0333' ;let wo = `我是${lin}
简化对象写法 ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法,这样的书写会更加简洁。
let name = 'xiaolin0333' ;let dadaima = function ( ) { console .log ('我爱打代码' ); } const lin = { name, dadaima paobu ( ) { console .log ('我也爱跑步' ); } } const lin = { name = name, dadaima = dadaima paobu :function ( ) { console .log ('我也爱跑步' ); } }
箭头函数 ES6允许使用箭头=>
来定义函数
let 函数名 = (形参 ) => { 代码体 } let fn = (a,b ) => { return a+b; } let result = fn (1 ,2 );
特性:
this是静态的,this始终指向函数声明时所在作用域下的 this的值。 (普通函数是:谁调用该函数,这个this就指向谁)
function getName ( ) { console .log (this .name ); } let getName2 = ( ) => { console .log (this .name ); } window .name = 'xiaolin0333' ;const lin = { name :'03' } getName ();getName2 ();getName.call (lin); getName2.call (lin);
不能作为构造函数实例化对象
let Person = (name,age) = { this .name = name; this .age = age; } let me = new Person ('lin' ,20 );
不能使用arguments变量
let fn = ( ) => { console .log (argument); } fn (1 ,2 ,3 );
箭头函数的简写
let add = (n ) => { return n+n; } let add = n => { return n+n; }
let pow = (n ) => { return n*n; } let pow = n =>n*n;
【注】此时return也必须省略,而且语句的结构就是函数的返回值
【适用场景】:
箭头函数适合与this无关的回调(定时器、数组的方法回调)
箭头函数不适合与this有关的回调(DOM元素的事件回调,对象的方法)
let ad = document .querySelector ('#ad' );ad.addEventListener ("click" ,function ( ) { let _this = this ; setTimeout (function ( ){ _this.style .background = 'pink' ; },2000 ) }) ad.addEventListener ("click" ,function ( ) { setTimeout ( ()=> { _this.style .background = 'pink' ; },2000 ) })
函数参数的默认值设置 ES6允许给函数参数(形参)赋初始值 特性:
具有默认值的参数,一般位置要靠后。(潜规则)【放前面意义不大,因为实参也会按顺序与实参对应】
function add (a,b,c=10 ) { return a+b+c; } console .log (add (1 ,2 ));
默认值可以与解构赋值结合使用
function connect (options ) { let host = options.host ; let username = options.username ; } connect ({ host :'localhost' , username :'root' , password :'root' , port :3306 }) function connect ({host="127.0.0.1" ,username,password,port} ) { let host = host; let username = username; }
rest参数 ES6引入rest(数组)参数,用于获取函数的实参,用来代替arguments(对象)
function data ( ) { console .log (arguments ); } data ('xiaolin' ,'03' );function data (...args ) { console .log (args); } data ('xiaolin' ,'03' );function fn (a,b,...args ) { }
扩展运算符 扩展运算符...
能够将数组转化为逗号分割的参数序列
const lin = ['xiaolin' ,'03' ];function name ( ) { console .log (arguments ); } name (...lin);
扩展运算符和rest区别:rest参数的声明是放在了函数声明的形参位置,扩展运算符...
是放在函数调用的实参位置
【应用】
数组的合并
const name1 = ['xiaolin' ];const name2 = ['03' ,'33' ];const name = [...name1,...name2];
数组的克隆
const name = ['xiaolin' ,'03' ,'33' ]const me = [...name];
【注】如果有引用类型,也是一个浅拷贝
将伪数组转为真正的数组
const divs = document .querySelectorAll ('div' );const divArr = [..divs ];
Symbol的介绍与创建 ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。他是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。 【特点】:
Symbol的值是唯一的,用来解决命名冲突的问题
Symbol值不能与其他数据类型进行运算(加减乘除、字符串拼接、比较)
Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
let s = Symbol ();let s2 = Symbol ('xiaolin' );let s3 = Symbol ('xiaolin' );console .log (s2===s3);let s4 = Symbol .for ('xiaolin' );let s5 = Symbol .for ('xiaolin' );console .log (s4===s5);let result = s+s;
【总结】:7种数据类型 undefined、string、symbol、object、null、number、boolean
Symbol的使用 向对象中添加属性和方法(如果给一个别人写的对象添加方法up(),不确定是否已经有这个方法,就可以使用Symbol来添加,更加简单高效安全。) 【例】:game是一个别人写的对象,我现在要添加up()和down()方法到这个对象里,但是不确定这个game对象里面是否已经存在这两个方法
let game = {...}let methods = { up :Symbol (), down :Symbol () }; game[methods.up ] = function ( ) { console .log ("我是up()方法" ); } game[methods.down ] = function ( ) { console .log ("我是down()方法" ); }
let youxi = { name :"狼人杀" , [Symbol ('say' )]:function ( ) { console .log ('我可以发言' ); }, [Symbol ('zibao' )]:function ( ) { console .log ('我可以自爆' ); }, }
Symbol内置值 除了定义自己使用的Symbol值之外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法 【例】Symbol.hasInstance:当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。
class Person { static [Symbol .hasInstance ](param) { console .log (param); console .log ("类型检测的时候调用我" ); } let o = {}; console .log (o instanceof Person ); }
Symbol.hasInstance都是Symbol内部的属性,这个整体又作为对象里边的属性,来改变对象在特定场景下的表现(扩展对象功能)
迭代器 迭代器(Iterator)是一种接口,为不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作。
ES6创建了一种新的遍历命令for…of循环。(只要数据结构部署了Interator接口,就可以使用for…of来遍历数据)
原生具备Interator接口的数据(可用for…of遍历):Array、Arguments、set、Map、String、TypedArray、NodeList
Interator就是指:对象里的一个函数Symbol(Symbol.Interator)
const lin = ['xiaolin' ,'03' ,'33' ];for (let v of lin) { console .log (lin); } for (let v in lin) { console .log (lin); }
【应用】:需要自定义遍历数据的时候,要想到迭代器。 【例】:使用for…of遍历对象,每次返回结果是数组stus的成员
const banji = { name :'物联网二班' , stus :[ 'xiaolin' , '03' , '33' ], [Symbol .interator ]() { let index = 0 ; let _this = this ; return { next :function ( ) { if (index<_this.stus .length ) { const result = {value :_this.stus [index],done :false }; index++; return result; } else { return {value :undefined ,done :true }; } } } } } for (let v of banji) { console .log (v); }
自定义迭代器工作原理如下:
创建一个对象,指向当前数据结构的起始位置
第一次调用对象的next方法(规定就叫做next方法),指针自动指向数据结构的第一个成员
接下来不断调用next方法,指针一直向后移动,直到指向最后一个成员
每次调用next方法返回一个包含value和done属性的对象 如果指针所指向的成员有定义,{value:指针所指成员,done:false},否则{value:undefined,done:true}
生成器函数生命与调用 生成器是一个特殊函数,用来进行异步编程(纯回调函数)。
function * gen ( ) { yield '一只没有眼睛' ; yield '一只没有尾巴' ; yield '真奇怪' ; let interator = gen (); console .log (interator.next ()); console .log (interator.next ()); console .log (interator.next ()); console .log (interator.next ()); for (let v of gen ()) { console .log (v); } }
【参数传递】
整体函数传参
next方法传参
function *gen (arg ) { console .log (arg); let one = yield 111 ; console .log (one); let two = yield 222 ; console .log (two); let three = yield 333 ; console .log (three) } let interator = gen ('AAA' ); interator.next (); interator.next ('BBB' ); interator.next ('CCC' ); interator.next ('DDD' );
【生成器函数实例】:异步编程:文件操作、网络操作(ajax、requests)、数据库操作 【例】:定时器案例(1s后控制台输出111 2s后控制台输出222 3s后控制台输出333)
setTimeout (()=> { console .log (111 ); setTimeout (()=> { console .log (222 ); setTimeout (()=> { console .log (333 ); },3000 ); },2000 ); },1000 ); function one ( ) { setTimeout (()=> { console .log (111 ); interator.next (); },1000 ); } function two ( ) { setTimeout (()=> { console .log (222 ); interator.next (); },2000 ); } function three ( ) { setTimeout (()=> { console .log (333 ); },3000 ); } function * gen ( ) { yield one (); yield two (); yield three (); } let interator = gen ();interator.next ();
Promise Promise是ES6引入的异步编程的解决方案(主要解决回调地狱的问题)。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
const p = new Promise (function (resolve,reject ) { setTimeout (function ( ) { if (成功){ let data = '数据库中的用户数据' ; resolve (data); } else { let err = '数据读取失败' ; reject (err); } },1000 ); const result = p.then (function (value ) { console .log (value); throw new Error ('出错啦' ); },function (reason ) { console .error (reason); }) console .log (result); }) p.then (value => {},reason => {}).then (value => {},reason => {}) p.then (value => {}).then (value => {})
Set ES6提供了新的数据结构Set(集合)。它类似于数组,但成员的值唯一,集合实现了Iterator接口,所以可以使用扩展运算符和for…of进行遍历。 【声明一个set】:
let s = new Set ();let s2 = new Set (['大事' ,'小事' ,'坏事' ,'小事' ]);console .log (s2);
【元素个数】:不包括重复元素size
【增】:添加新的元素add()
s2.add ('喜事' ); console .log (s2);
【删】:删除元素delete()
【是否存在】:检测has()
console .log (s2.has ('好事' ));
【遍历】:使用for…of遍历集合
for (let v of s2) { console .log (v); }
【清空】:清空clear()
【集合实践】:
let arr = [1 ,2 ,3 ,4 ,5 ,4 ,3 ,2 ,1 ];let result = [...new Set (arr)];console .log (result);let arr2 = [4 ,5 ,6 ,5 ,6 ];let result = [...new Set (arr)].filter (item => { let s2 = new Set (arr2); if (s2.has (item)) { return true ; } else { return false ; } }) console .log (result);let union = [...arr,...arr2];union = [...union];
Map ES6提供了Map数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map也实现了Iterator接口,所以可以使用扩展运算符和for…in进行遍历。
【增】:添加元素 对象.set(键,值)
m.set ('name' ,'xiaolin03' ); m.set ('hobby' ,function ( ) { console .log ('我爱打代码' ); }) let key = { name :'xiaolin03' } m.set (key,['宁德' ,'厦门' ,'福州' ]);
【元素个数】:获取元素个数 对象.size
【删】:删除 对象.delete(键)
【取】:获取 对象.get(键)
m.get ('hobby' ); m.get (key);
【遍历】:for…of遍历
for (let v of m) { console .log (v); }
【清空】:对象.chear();
class类 ES6提供了更接近传统语言的写法,引入了Class(类)这个概念。作为对象的模板。通过class关键字可以定义类。基本上,ES6的class可以看做只是一个语法糖,他的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
class Phone { constructor (brand,price ) { this .brand = brand; this .price = price; } call ( ) { console .log ("我可以打电话" ); } } let onPlus = new Phone ("1+" ,1999 );
静态成员 静态成员static标注的成员,属于类,而不属于函数对象 ====> 得用类名.成员名 来调用该属性
class Phone { static name = "手机" ; static change ( ) { console .log ("我可以改变世界" ); } } let huawei = new Phone ();console .log (huawei.name );console .log (Phone .name );
类继承 class Phone { constructor (brand,price ) { this .brand = brand; this .price = price; } call ( ) { console .log ("打电话" ); } } class SmartPhone extends Phone { constructor (brand,price,color,size ) { surper (brand,price); this .color = color; this .size = size; } photo ( ) { console .log ("拍照" ); } playGame ( ) { console .log ("玩游戏" ); } } const xiaomi = new SmartPhone ('小米' ,799 ,'黑色' ,'4.7inch' );xiaomi.call (); xiaomi.photo (); xiaomi.playGame ();
子类对父类方法的重写 重写:在子类声明一个和父类重名的方法,从而对父类的功能进行改进。当调用这个方法时,调用的是子类的方法。
class Phone { constructor (brand,price ) { this .brand = brand; this .price = price; } call ( ) { console .log ("打电话" ); } } class SmartPhone extends Phone { constructor (brand,price,color,size ) { surper (brand,price); this .color = color; this .size = size; } call ( ) { console .log ("打视频、聊天" ); } } const xiaomi = new SmartPhone ('小米' ,799 ,'黑色' ,'4.7inch' );xiaomi.call ();
ES6里,无法在子类里去调用父类中和他同名的那个方法,只能在子类里写。
getter和setter设置 对对象的属性
进行方法的绑定 get:对于对象的动态属性进行封装 set:添加更多的控制和判断
class Phone { get price () { console .log ("价格属性被读取了" ); return 'helloworld' ; } set price (newVAl ) { console .log ("价格属性被修改了" ); } } let s = new Phone ();console .log (s.price ());s.price = 'free' ;
数值扩展
Number.EPSILON 是 JavaScript 表示的最小精度
EPSILON 属性的值接近于 2.22E-16
主要用于浮点数运算(浮点数运算经常会有误差)
console .log (0.1 +0.2 );console .log (0.1 + 0.2 === 0.3 );function equal = (a,b ) => { if (Math .abs (a-b)<Number .EPSILON ) { return true ; }else { return false ; } } console .log (equal (0.1 +0.2 ,0.3 ));
二进制和八进制
let b = 0b1010 ;console .log (b);let o = 0o777 ;console .log (o);let x = 0xff ;console .log (x);
Number.isFinite 检测一个数值是否为有限数
console .log (Number .isFinite (100 ));console .log (Number .isFinite (Infinity ));console .log (Number .isFinite (100 /0 ));
Number.isNaN 检测一个数值是否为NaN
console .log (Number .isNaN (123 ));
Number.parseInt Number.parseFloat 字符串转整数
console .log (Number .parseInt ("520Love" ));console .log (Number .parseFloat ("5.20Love" ));
Number.isInteger 判断一个数是否为整数
console .log (Number .isInteger (4 ));console .log (Number .isInteger (4.4 ));
Math.trunc 将数字的小数部分抹掉
console .log (Math .trunc (3.5 ));
Math.sign 判断一个数到底为正数、负数还是零
console .log (Math .sign (100 ));console .log (Math .sign (0 ));console .log (Math .sign (-100 ));
对象方法扩展
Object.is(a, b)判断两个值是否完全相等
console .log (Object .is (120 ,120 ));console .log (Object .is (NaN ,NaN ));console .log (NaN ===NaN );
Object.assign(a, b)对象的合并
const config1 = { host : 'localhost' , port :3306 , name :'root' , pass :'root' , text :'text' }; const config2 = { host :'http://xiaolin03.com' , port :33060 , name :'xiaolin03.com' , pass :'cmb' , text2 :'text2' }; console .log (Object .assign (config1,config2));
Object.setPrototypeOf 设置原型对象 Object.getPrototypeOf
const school = { name :"学校名" } const cities = { xiaoqu :['北京' ,'上海' ,'深圳' ] } Object .setPrototypeOf (school,cities);console .log (school);
不建议这么做(效率低)
模块化 将一个大的程序文件,拆分成许多小的文件(模块),然后将小文件组合起来。 【好处】:
防止命名冲突
代码复用
高维护性 【语法】:模块功能主要由两个命令构成:export和import
export命令用于规定模块的对外接口
import命令用于输入其他模块提供功能
export let school = '学校名' ;export function teach ( ) { console .log ("heloworld" ); } <script type="module" > import * as m1 from './m1.js' ; console .log (m1); </script>
【暴露数据语法汇总】:
分别暴露(在每个需要暴露的数据前面加上export) m1.js
export let school = '学校名' ;export function teach ( ) { console .log ("heloworld" ); }
统一暴露(在某个地方直接用export,用对象简化写法格yin) m2.js
let school = '学校名' ;function teach ( ) { console .log ("heloworld" ); } export {school,teach};
默认暴露(对于这种方法,在调用的时候也需要上default 【例】m1.default.change()) m3.js
export default { school :"学校名" , change :function ( ) { console .log ("heloworld" ); } }
【引入模块数据语法汇总】:
通用的入方式
<script type="module" > import * as m1 from './m1.js' ; </script>
解构赋值形式
import {school,teach} from "./m1.js" ;import {school as guigu,teach as teaching} from "./m2.js" ;import {default as m3} form "./m3.js" ;
简便形式(只能针对默认暴露)
import m3 from "./m3.js" ;