es6总结
xiong.jpg
往期文章
1.es6简介
回顾javascrip组成:
核心(ECMAScript)
由ECMA-262定义的ECMAScript是一种在国际认可的标准的脚本语言规范,与Web浏览器没有依赖关系。
文档对象模型(DOM)
DOM(文档对象模型)是 HTML 和 XML 的应用程序接口(API)。DOM 将把整个页面规划成由节点层级构成的文档。HTML或XML页面中的每个组成部分都是某种类型的节点,这些节点又包含着不同类型的数据。
浏览器对象模型(BOM)
E 3.0 和 Netscape Navigator 3.0 提供了一种特性 - BOM(浏览器对象模型),可以对浏览器窗口进行访问和操作。使用 BOM,开发者可以移动窗口、改变状态栏中的文本以及执行其他与页面内容不直接相关的操作。
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
2.es6转码
转码原因:现在的Chrome浏览器已经支持ES6了,但是有些低版本的浏览器还是不支持ES6的语法,这就需要我们把ES6的语法自动的转变成ES5的语法。
浏览器es6支持度测试:ruanyf.github.io/es-checker
建立工程目录:
先建立一个项目的工程目录,并在目录下边建立两个文件夹:src和dist
src:书写ES6代码的文件夹,写的js程序都放在这里。
dist:利用Babel编译成的ES5代码的文件夹,在HTML页面需要引入的时这里的js文件。
编写index.html:
文件夹建立好后,我们新建一个index.html文件,需要注意的是index.html在引入js文件时,引入的是dist目录下的文件。
Babel 转码器:
{ "name": "es6", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "babel-cli": "^6.26.0", "babel-preset-es2015": "^6.24.1" } }
{ "presets":[ "es2015" ], "plugins":[] }
//es6 目录src/index.js let a=1; console.log(a); //es5 目录dist/index.js "use strict"; var a = 1; console.log(a);
修改package.json文件
npm run build 转码指令
npm run XXX
是执行配置在package.json中的脚本
简化转化命令
{ "name": "es6", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "babel src/index.js -o dist/index.js" //更换指令 }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "babel-cli": "^6.26.0", "babel-preset-es2015": "^6.24.1" } }
babel src/index.js -o dist/index.js ES6成功转化为ES5的命令
转换后:
新建.babelrc 在根目录下新建.babelrc文件,并打开录入下面的代码
npm init -y 先初始化我们的项目,-y代表全部默认同意,就不用一次次按回车了。命令执行完成后,会在项目根目录下生产package.json文件,可以根据自己的需要进行修改,比如我们修改name的值```
//package.json文件
{
"name": "es6",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}npm install -g babel-cli 全局安装Babel-cli
npm install --save-dev babel-preset-es2015 babel-cli 本地安装babel-preset-es2015 和 babel-cli
成功后package.json文件多了devDependencies选项
3.变量声明
let声明
// 报错 function func() { let a = 10; var a = 1; } // 报错 function func() { let a = 10; let a = 1; } function func(arg) { let arg; // 报错 } function func(arg) { { let arg; // 不报错 } }
块级作用域的需求场景
内层变量可能会覆盖外层变量。
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); // undefined
f()方法内定义的tmp变量提升,覆盖外部的变量,所有undefined
用来计数的循环变量泄露为全局变量
var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5
循环结束后i并没有消失,而是变成了全局变量
块级作用域
{ let a = 10; var b = 1; } a // 报错: a is not defined. b // 1 var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10 for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
分析:在var声明的循环中,在全局范围内都有效,所以全局只有一个变量
i
。每一次循环,变量i
的值都会发生改变,而循环内被赋给数组a
的函数内部的console.log(i)
,里面的i
指向的就是全局的i
。在let声明的循环中:变量
i
是let
声明的,当前的i
只在本轮循环有效,所以每一次循环的i
其实都是一个新的变量,所以最后输出的是6
声明变量不能提升
// var 的情况 console.log(foo); // 输出undefined var foo = 2; // let 的情况 console.log(bar); // 报错ReferenceError let bar = 2;
且let不能提升和块级的特性,导致暂时性死区
var tmp = 123; if (true) { tmp = 'abc'; // ReferenceError let tmp; }
区块中存在
let
和const
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。不允许重复声明
const声明
const PI = 3.1415; PI // 3.1415 PI = 3; // TypeError: Assignment to constant variable.
性质:块级作用域、不可变量提升、短暂死区、不可重复声明
定义:
const
声明一个只读的常量。一旦声明,常量的值就不能改变。
小知识:javascript6种变量声明
var
命令、function
命令、let
和const
命令、import
命令和class
命令
4.解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
数组解构赋值
//基础用法 let [a, b, c] = [1, 2, 3]; let [foo, [[bar], baz]] = [1, [[2], 3]]; foo // 1 bar // 2 baz // 3 let [ , , third] = ["foo", "bar", "baz"]; third // "baz" let [x, , y] = [1, 2, 3]; x // 1 y // 3 let [head, ...tail] = [1, 2, 3, 4]; head // 1 tail // [2, 3, 4] let [x, y, ...z] = ['a']; x // "a" y // undefined z // [] //不完全解构,解构不成功,变量的值就等于undefined let [foo] = []; //foo的值undefined let [bar, foo] = [1]; //foo的值undefined //解构设置默认值 let [x, y = 'b'] = ['a']; // x='a', y='b' let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'</pre>
对象解构赋值
与数组解构不同点:数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { bar, foo } = { foo: "aaa", bar: "bbb" }; foo // "aaa" bar // "bbb" let { baz } = { foo: "aaa", bar: "bbb" }; baz // undefined
字符串结构
const [a,b,c,d,e,f]="fengai"; console.log(a);//f console.log(b);//e console.log(c);//n console.log(d);//g console.log(e);//a console.log(f);//i
函数解构
//函数数组解构 function add([x, y]){ return x + y; } add([1, 2]); // 3 //函数对象解构 let json = { a:'xiao', b:'feng' } function fun({a,b='ha'}){//默认b='ha' console.log(a,b); } fun(json);
圆括号使用
如果在解构之前就定义了变量,这时候你再解构,编译会报错
//不使用圆括号 let {foo} ={foo:'JSPang'}; //使用圆括号 let foo; ({foo} ={foo:'JSPang'}); console.log(foo); //控制台输出jspang
5.字符串扩展
for...of 字符串遍历
for (let codePoint of 'foo') { console.log(codePoint) } // "f" // "o" // "o"
includes(), startsWith(), endsWith()
let s = 'Hello world!'; s.startsWith('Hello') // true s.endsWith('!') // true s.includes('o') // true
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
repeat() 字符串重复次数
'x'.repeat(3) // "xxx" 'hello'.repeat(2) // "hellohello" 'na'.repeat(0) // ""
字符串模板
//之前版本 let jspang='字符串'; let blog = '原来'+jspang+'拼接'; //es6版本 let jspang='字符串'; let blog = '原来${jspang}拼接'; //支持运算 let a=1; let b=2; let result=`${a+b}`;//3
6.正则扩展
String.prototype.matchAll
可以一次性取出所有匹配。不过,它返回的是一个遍历器(Iterator),而不是数组。
const string = 'test1test2test3'; // g 修饰符加不加都可以 const regex = /t(e)(st(\d?))/g; for (const match of string.matchAll(regex)) { console.log(match); } // ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"] // ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"] // ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]
7.数值的扩展
二进制、八进制表达
二进制和八进制数值的新的写法,分别用前缀
0b
(或0B
)和0o
(或0O
)表示。0b111110111 === 503 // true0o767 === 503 // true
Number.isFinite(), Number.isNaN()
Number.isFinite()
用来检查一个数值是否为有限的(finite),即不是Infinity
Number.isNaN()
用来检查一个值是否为NaN
。
Number.isFinite(15); // true Number.isFinite(0.8); // true Number.isFinite(NaN); // false Number.isFinite(Infinity); // false Number.isFinite(-Infinity); // false Number.isFinite('foo'); // false Number.isFinite('15'); // false Number.isFinite(true); // false</pre>
Number.parseInt(), Number.parseFloat()
ES6 将全局方法
parseInt()
和parseFloat()
,移植到Number
对象上面,行为完全保持不变。
// ES5的写法 parseInt('12.34') // 12 parseFloat('123.45#') // 123.45 // ES6的写法 Number.parseInt('12.34') // 12 Number.parseFloat('123.45#') // 123.45</pre>
Number.isInteger()
Number.isInteger()
用来判断一个数值是否为整数。Number.isInteger(25) // trueNumber.isInteger(25.1) // false</pre>
安全整数和 Number.isSafeInteger()
JavaScript 能够准确表示的整数范围在
-2^53
到2^53
之间(不含两个端点),超过这个范围,无法精确表示这个值。最大安全数:
Number.MAX_SAFE_INTEGER
最小安全数:
Number.MIN_SAFE_INTEGER
Number.isSafeInteger() :
判断一个数是否为安全数
Number.isSafeInteger('a') // falseNumber.isSafeInteger(null) // falseNumber.isSafeInteger(NaN) // falseNumber.isSafeInteger(Infinity) // falseNumber.isSafeInteger(-Infinity) // falseNumber.isSafeInteger(3) // trueNumber.isSafeInteger(1.2) // falseNumber.isSafeInteger(9007199254740990) // trueNumber.isSafeInteger(9007199254740992) // falseNumber.isSafeInteger(Number.MIN_SAFE_INTEGER - 1) // falseNumber.isSafeInteger(Number.MIN_SAFE_INTEGER) // trueNumber.isSafeInteger(Number.MAX_SAFE_INTEGER) // trueNumber.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false
8.Math对象的扩展
Math.trunc() 数字取整数
Math.sign() 判断一个数是否为正数、负数、0
参数为正数,返回
+1
;参数为负数,返回
-1
;参数为 0,返回
0
;参数为-0,返回
-0
;其他值,返回
NaN
。Math.cbrt() 计算一个数的立方根。
Math.hypot() 返回所有参数的平方和的平方根。
Math.hypot(3, 4); // 5Math.hypot(3, 4, 5); // 7.0710678118654755Math.hypot(); // 0Math.hypot(NaN); // NaNMath.hypot(3, 4, 'foo'); // NaNMath.hypot(3, 4, '5'); // 7.0710678118654755Math.hypot(-3); // 3
9.函数的扩展
函数参数设置默认值
function log(x, y = 'World') { console.log(x, y); } log('Hello') // Hello Worldlog('Hello', 'China') // Hello Chinalog('Hello', '') // Hello
函数的 length 属性
指定了默认值以后,函数的
length
属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length
属性将失真。(function (a) {}).length // 1(function (a = 5) {}).length // 0(function (a, b, c = 5) {}).length // 2</pre>
同理,后文的
rest 参数
也不会计入length
属性。rest 参数
rest 参数(形式为
...变量名
),用于获取函数的多余参数,这样就不需要使用arguments
对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
rest是真数组
function add(...values) { let sum = 0; for (var val of values) { sum += val; } return sum; } add(2, 5, 3) // 10 //剩余参数 function feng(first,...arg){ for(let val of arg){ console.log(val); //1,2,3,4,5,6,7 } } feng(0,1,2,3,4,5,6,7);
arguments回顾
arguments
对象不是数组,而是一个类似数组的对象,伪数组
arguments.length 参数个数
arguments[0] 第一个参数,...
转换成真数组:
function arg2arr(){ var arr = Array.prototype.slice.call(arguments); console.log(arr); } arg2arr(1,2,3);
name 属性
函数的
name
属性,返回该函数的函数名。function foo() {} foo.name // "foo"</pre>
箭头函数
var f = () => 5;// 等同于var f = function () { return 5 };var sum = (num1, num2) => num1 + num2;// 等同于var sum = function(num1, num2) { return num1 + num2; };//多个代码段用{}var sum = (num1, num2) => { console.log("feng"); return num1 + num2; }
函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象。不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误。不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
函数体中的严格模式
我们在ES中就经常使用严谨模式来进行编程,但是必须写在代码最上边,相当于全局使用。在ES6中我们可以写在函数体中,相当于针对函数来使用。
function add(a,b=1){ 'use strict' if(a == 0){ throw new Error('This is error'); } return a+b; }console.log(add(1));
双冒号运算符
函数绑定运算符是并排的两个冒号(
::
),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this
对象),绑定到右边的函数上面。(可替代apply,call,bind)foo::bar;// 等同于bar.bind(foo); foo::bar(...arguments);// 等同于bar.apply(foo, arguments);const hasOwnProperty = Object.prototype.hasOwnProperty;function hasOwn(obj, key) { return obj::hasOwnProperty(key); }
10.数组的扩展
扩展运算符
扩展运算符(spread)是三个点(
...
)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列console.log(...[1, 2, 3])// 1 2 3console.log(1, ...[2, 3, 4], 5)// 1 2 3 4 5[...document.querySelectorAll('div')]// [<div>, <div>, <div>]//替代apply,将数组分解成一个个函数参数// ES5 的写法function f(x, y, z) {// ...}var args = [0, 1, 2]; f.apply(null, args);// ES6的写法function f(x, y, z) {// ...}let args = [0, 1, 2]; f(...args);
[...'hello'] // [ "h", "e", "l", "l", "o" ]</pre>
复制数组
数组是复合的数据类型,直接复制的话,只是复制了指向底层数据结构的指针,而不是克隆一个全新的数组。
const a1 = [1, 2]; const a2 = a1;//传址而非传值 a2[0] = 2; a1 // [2, 2] //改变a2会影响a1的值
...扩运算克隆
const a1 = [1, 2];// 写法一const a2 = [...a1];// 写法二</pre>
合并数组
const arr1 = ['a', 'b']; const arr2 = ['c']; const arr3 = ['d', 'e']; // ES5 的合并数组 arr1.concat(arr2, arr3); // [ 'a', 'b', 'c', 'd', 'e' ] // ES6 的合并数组 [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ]
与解构赋值结合
// ES5a = list[0], rest = list.slice(1)// ES6[a, ...rest] = list
字符串
Array.from() 将伪数组转化为真数组
//伪数组: 1、伪数组是一个对象 2、这个对象必须要有length属性 3、如果这个对象的length不为0,那么必须要有按照下标存储的数据let arrayLike = {'0': 'a','1': 'b','2': 'c',length: 3};// ES5的写法var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c'];// ES6的写法let arr2 = Array.from(arrayLike); // ['a', 'b', 'c'];/ arguments对象function foo() {var args = Array.from(arguments);// ...}
Array.of() 将一组值,转换为数组
Array.of(3, 11, 8) // [3,11,8]Array.of(3) // [3]Array.of(3).length // 1
find() 和 findIndex()实例方法
find(): 用于找出
第一个
符合条件的数组成员。回调函数参数依次为
当前的值
、当前的位置
和原数组
find(function(value, index, arr) { return value > 9; })</pre>
findIndex(): 数组实例的
findIndex
方法的用法与find
方法非常类似,返回第一个
符合条件的数组成员的位置fill()实例方法 用给定值填充数组
['a', 'b', 'c'].fill(7) // [7, 7, 7] new Array(3).fill(7) // [7, 7, 7]
entries(),keys() 和 values()实例方法 数组遍历 同 for...of 循环使用
keys()
是对键名的遍历values()
是对键值的遍历entries()
是对键值对的遍历for (let index of ['a', 'b'].keys()) {console.log(index); }// 0// 1for (let elem of ['a', 'b'].values()) {console.log(elem); }// 'a'// 'b'for (let [index, elem] of ['a', 'b'].entries()) {console.log(index, elem); }// 0 "a"// 1 "b"
includes()实例方法 判断数组是否包含某一数组元素
[1, 2, 3].includes(2) // true[1, 2, 3].includes(4) // false[1, 2, NaN].includes(NaN) // true
entries( )实例方法
entries()实例方式生成的是Iterator形式的数组,那这种形式的好处就是可以让我们在需要时用next()手动跳转到下一个值。我们来看下面的代码:
let arr=['hao','ha','hi']let list=arr.entries();console.log(list.next().value);//haoconsole.log(list.next().value);//haconsole.log(list.next().value);//hi
11.对象的扩展
声明变量直接赋值
let name="jspang";let skill= 'web';var obj= {name,skill};console.log(obj); //Object {name: "jspang", skill: "web"}
对象Key值构建
有时候我们会在后台取出key值,而不是我们前台定义好的,这时候我们如何构建我们的key值那。比如我们在后台取了一个key值,然后可以用[ ] 的形式,进行对象的构建
let key='skill';var obj={ [key]:'web'}console.log(obj.skill);
Object.is( ) 对象比较
ES5 比较两个值是否相等,只有两个运算符:相等运算符(
==
)和严格相等运算符(===
)。它们都有缺点,前者会自动转换数据类型,后者的NaN
不等于自身Object.is
就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致var obj1 = {name:'feng'};var obj2 = {name:'feng'};console.log(obj1.name === obj2.name);//trueconsole.log(Object.is(obj1.name,obj2.name)); //trueconsole.log(+0 === -0); //trueconsole.log(NaN === NaN ); //falseconsole.log(Object.is(+0,-0)); //falseconsole.log(Object.is(NaN,NaN)); //true
Object.assign() 对象的合并
Object.assign(参数1,参数2,参数3) 将源对象(source)的所有可枚举属性,复制到目标对象(target)
一个参数是目标对象,后面的参数都是源对象
const target = { a: 1 } const source1 = { b: 2 };const source2 = { c: 3 };Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
注意:
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
//相当于同名属性替换
```浅拷贝 拷贝对象属性的址,而非值
const obj1 = {a: {b: 1}};const obj2 = Object.assign({}, obj1); obj1.a.b = 2; obj2.a.b // 2
同名属性替换
const target = { a: { b: 'c', d: 'e' } }const source = { a: { b: 'hello' } }Object.assign(target, source)// { a: { b: 'hello' } }
数组处理
Object.keys(),Object.values(),Object.entries()
Object.keys() 返回对象所有键的新数组
var obj = { foo: 'bar', baz: 42 };Object.keys(obj)// ["foo", "baz"]
Object.values() 返回对象所有值的新数组
const obj = { 100: 'a', 2: 'b', 7: 'c' };Object.values(obj)// ["b", "c", "a"]
Object.entries() 返回对象所有键值对的新数组
const obj = { foo: 'bar', baz: 42 }; Object.entries(obj) // [ ["foo", "bar"], ["baz", 42] ]
12.in的用法
in是用来判断对象或者数组中是否存在某个值的。我们先来看一下用in如何判断对象里是否有某个值
判断对象:
let obj={ a:'jspang', b:'技术胖'}console.log('a' in obj); //true
判断数组:
ES5判断的弊端:以前会使用length属性进行判断,为0表示没有数组元素。但是这并不准确,或者说真实开发中有弊端
let arr=[,,,,,];console.log(arr.length); //5 这是个坑//es6let arr=[,,,,,];console.log(0 in arr); //false 空数组,判断0下标是否存在let arr1=['jspang','技术胖'];console.log(0 in arr1); // true
作者:理想三旬7
链接:https://www.jianshu.com/p/969460bd4951