中软Day16
ES6,全称ECMA Script6.0,是 新一代的JS语言标准,发布于15年左右。
目标让js语言成为能支持去编写大型复杂的应用语言, 成为企业级开发语言。
ECMAscript和javascript区别:
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)。日常场合,这两个词是可以互换的。
变量有什么新特性?
可以使用let去定义变量,可以使用const去定义常量,解构赋值。
let命令作用:用于声明变量,类似于var,但是,它只在let所在的代码块内部有效。
<script type="text/traceur">
{
var a=100;
let b=200;
}
console.log(a); //100
console.log(b); //Error,b is not defined
</script>
let与var的区别
var
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
/*变量i是var声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的function在运行时,会通过闭包读到这同一个变量i,导致最后输出的是最后一轮的i的值,也就是10。
let
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
//变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。
性质:
let具备块级作用域(一是内层变量可能会覆盖外层变量。二是用来计数的循环变量泄露为全局变量。)
let声明的变量只能在代码块内部调用
没有变量提升
ES5
<script type="text/traceur">
//ES5
console.log("ES5");
for(var i=0;i<10;i++){
var c=i;
a[i]=function(){
console.log(c);
};
};
a[5](); //9
</script>
ES6
//在let声明变量的时候,就不会如此结果
<script type="text/traceur">
//ES6
console.log("ES6");
for(let j=0;j<10;i++){
let c=j;
a[i]=function(){
console.log(c);
};
};
a[5](); //5
</script>
解析:由于在执行函数时,将j=5作为变量赋值给传入函数中,所以执行完毕即退出。
暂时性死区
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区” 。
//只要块级作用域中存在let命令,所声明的该变量是有效的“绑定的”,不再受外部影响。
//a在let a声明前就console了,即表示“未定义undefined”,在let之前的区域为“暂时性死区”。
<script type="text/traceur">
//var a=100;
{
console.log(a); //undefined
let a=100;
console.log(a); //100
}
</script>
<!--在该案例中,多了“var a”,但是let所声明的变量,并不在乎外界的影响,所以在let作用域内部,var声明的变量是无效的,即“console.log(a)”还是defined(3)let不允许重复声明情况1:模块内部重复声明(不允许用let命令重复声明)>
<script type="text/traceur">
var a=100;
{
console.log(a); //undefined
let a=100;
console.log(a); //100
}
</script>
变量作用域不同
<script type="text/trancer">
{
var a=1;
var a=2;
console.log(a); //2
}
{
let a=2;
console.log(a); //2
}
</script>
不允许重复声明
let不允许在相同作用域内部重复声明同一个变量,所以也是不允许在函数中重新声明参数。
<script type="text/trancer">
{
var a=1;
var a=2;
}
console.log(a); //2
{
var b=1;
let b=2;
}
console.log(b);
{
let c=1;
let c=2;
}
console.log(c);
</script>
//解析:由于var重复声明的变量是可以运行的,即后边的会覆盖前边的变量。但是,只要声明的变量存在let,则若重复声明一个变量,都会报错。无论有一个let,let在前还是在后;还是有两个重复let声明的变量,都是有错误的。
模块之间不影响,可重复声明
<script type="text/trancer">
{
var a=1;
var a=2;
console.log(a); //2
}
{
let a=2;
console.log(a); //2
}
</script>
const定义的变量不可以修改,而且必须初始化。
const b = 2;//正确
// const b;//错误,必须初始化
console.log('函数外const定义b:' + b);//有输出值
// b = 5;
// console.log('函数外修改const定义b:' + b);//无法输出
var定义的变量可以修改,如果不初始化会输出undefined,不会报错。
var a = 1;
// var a;//不会报错
console.log('函数外var定义a:' + a);//可以输出a=1
function change(){
a = 4;
console.log('函数内var定义a:' + a);//可以输出a=4
}
change();
console.log('函数调用后var定义a为函数内部修改值:' + a);//可以输出
let是块级作用域,函数内部使用let定义后,对函数外部无影响。
let c = 3;
console.log('函数外let定义c:' + c);//输出c=3
function change(){
let c = 6;
console.log('函数内let定义c:' + c);//输出c=6
}
change();
console.log('函数调用后let定义c不受函数内部定义影响:' + c);//输出c=3
ES5 VS ES6
ES5:在ES5中,只有两种作用域:全局作用域 + 局部作用域
场景1——内部作用域会覆盖外部作用域
场景2——用于计数的循环变量泄露为全局变量(循环变量结束,变量依然存在,内存占用)
ES6
块级作用域
//ES6:增加了“块级作用域”的概念
<script type=”text/traceur”>
console.log(“ES6:”);
let num=100;
if(true){
let num=200;
}
console.log(num); //100
</script>
<script type=”text/traceur”>
function fun(){
console.log(“I am outside!”);}
(function(){
if(false){
function fun(){
console.log(“I am inside!”);
};
};
fun(); //I am outside!
})();
ES5
<script type=”text/javascript”>
console.log(“ES5”);
var num=100;
if(true){
var num=200;
}
console.log(num); //200
</script>
立即执行函数
<script type=”text/javascript”>
function fun(){
Console.log(“I am outside!”);
}
(function(){
if(false){
function fun(){
console.log(“I am inside!”);
};
};
fun(); //I am inside!
})();
</script>
do表达式
本质上,块级作用域是一个语句,将多个操作封装在一起,没有返回值。
{
let t = f();
t = t * t + 1;
}
块级作用域将两个语句封装在一起。但是,在块级作用域以外,没有办法得到t的值,因为块级作用域不返回值,除非t是全局变量。
do表达式可以返回值
let x = do {
let t = f();
t * t + 1;
};
//变量x会得到整个块级作用域的返回值。
const一旦声明变量,就必须立即初始化,不能留到以后赋值。 因为以后再没法赋值了,所有声明的时候一定有值 。
只在声明所在的块级作用域内有效
const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
用途:为了防止意外修改变量
比如:引入库名,组件库
Const也是声明变量,但是它声明的是一个常量。一旦声明,就不能改变。
<script type=”text/traceur”>
const Pi =3.1415926;
console.log(Pi);
Pi=3;
console.log(Pi); //Pi is read-only——Error
</script>
使用const命令
<script type=”text/traceur”>
const Pi =3.1415926;
console.log(Pi);
Pi=3;
console.log(Pi); //Pi is read-only——Error
</script>
const块级作用域
<script type=”text/traceur”>
if(true){
const Pi=3.1415926;
}
console.log(Pi); // Pi is not defined!——error
</script>
const对象
<script type=”text/traceur”>
const person={
};
person.name=”Zhangsan”;
person.age=30;
console.log(person.name);
console.log(person.age);
console.log(person) ; //object{name: age}
</script>
const数组
<script type=”text/traceur”>
const arr=[];
console.log(arr);
console.log(arr.length);
console.log(“------”);
arr.push(“Hello world!”);
console.log(arr);
console.log(arr.length);
arr.length=0;
console.log(arr.length);
//错误用法
arr = [“Hello world”];
</script>
const对象冻结
<script type=”text/traceur”>
const person = Object.freeze({
name = “Zhangsan”;
age=12;
}); //冻结对象;
console.log(person.name); //Zhangsan
console.log(person.age); //12
console.log(person); //Object
</script>
彻底冻结对象
var constantize=(obj) => {
object.freeze(obj);
object.keys(obj).forEach(key , value) => {
if( typeof obj[key] === ‘object’ ){
constantize( obj[key] );
};
};
};
用处:用于解决异步数据获取时数据向外传递,例如ajax获取的数据向外传递
<script type=”text/traceur”>
// module1.js
export const intVariantName =100;
export const floatVariantName =3.14;
export const charVariantName =”variantValue”;
// user.js
import * as var from ‘./module’;
console.log(variant.IntvariantName); // 100
console.log(variant.floatvariantName); //3.14
console.log(variant.charvariantName); //”variantValue”
//otherUser.js
import{
intVariantName,floatVariantName } as variant from ‘./module’;
console.log(variant.IntvariantName); // 100
console.log(variant.floatvariantName); //3.14
</script>
字符串链接
let obj = {
f:'first',l:'last'};
var box = document.getElementById('box');
console.log(box);
var str = `
${
obj.f}
${
obj.l}
`;
console.log(str);
box.innerHTML=str;
字符串遍历
字符串的遍历:
for(let str of 'abc'){
console.log(str);
}
CharAt()方法:
'abc'.charAt(2)
方法
JavaScript只有 indexOf 方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6又提供了三种新方法。
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
var [a,b,c] = [12,4,5];
var {
a,b,c} = {
a:23,b:4,c:33} 跟顺序无关
模式匹配: 左侧和右侧模式必须一样
var [a,[b,c],c] = [2,[2,3],4];
var [a,b,{
a,b}] = [2,3,{
‘aa’,’bb’}]
//通常情况下
var first = someArray[0];
var second = someArray[1];
var third = someArray[2];
//解构赋值
let [first, second, third] = someArray; //比上面简洁多了吧
//还有下面例子
let [,,third] = [1,2,3];
console.log(third); //3
let [first,...last] = [1,2,3];
console.log(last); //[2,3]
//对象解构
let {
name,age} = {
name: "lisi", age: "20"};
console.log(name); //lisi
console.log(age); //20
//注意
let {
ept1} = {
};
console.log(ept1); //undefined
let {
ept2} = {
undefined};
console.log(ept2); //undefined
let {
ept3} = {
null};
console.log(ept3); //null
数组的解构赋值
let [a,b,c] = [1,2,3];
console.log(a+b+c); //6
let [foo,[[bar]],baz] = [1,[[2]],3];
console.log(a+b+c); //6
let [ , ,third] = ["foo","bar","baz"];
console.log(third); //baz
let [head, ...tail] = [1,2,3,4];
console.log(tail); //[ 2, 3, 4 ]
let [x,y,...z] = ['a'];
console.log(x); //a
console.log(y); //undefined
console.log(z); //[]
以下情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组
let [aaa,bbb] = [1];
console.log(aaa); //1
注: 如果等号的右边不是数组(或者严格地说,不是可遍历的结构),那么将会报错。
事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
案例
数组对应位置
let [one, ,three] =[“one”,”two”,”three”];
console.log(one); //one
console.log(three); //three
let [head,...tail] =[0,1,2,3,4,5];
console.log(head); //0
console.log(tail); //[1,2,3,4,5]
不完全解构
定义:等号左边的模式,只匹配一部分的等号右边的数据。(不会出现溢出等现象)
<script type=”text/traceur”>
let [x,y] = [1,2,3];
console.log(x); //1
console.log(y); //2
let [a,[b],c] = [1,[2,3],4];
console.log(a); //1
console.log(b); //2
console.log(c); //4
let [a,[b,d],c] =[1,[2,3],4];
console.log(a); //1
console.log(b); //2
console.log(d); //3
</script>
默认值
解构赋值允许默认值。
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。
案例
指定默认值
<script type=”text/traceur”>
var [temp=”string”] = [];
console.log(temp); //string
var [temp=”string” ]= [“tempString”];
console.log(temp); //tempString
var [x=”aaa”,y] = [“bbb”];
console.log(x); //bbb
console.log(y); //undefined
var [m,n=”aaa”] = [“bbb”];
console.log(m); //bbb
console.log(n); //aaa
var [p,q=”aaa”] = [“bbb”,undefined];
console.log(p); //bbb
console.log(q); //aaa(由于undefined是未定义,所以有值即输出)
</script>
//非遍历数组解构产生报错
对象的解构赋值
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
案例:
let {
bar,foo} = {
foo:"aaa",bar:"bbb"};
console.log(bar+foo); //bbbaaa
let {
bar:b,foo:f} = {
foo:"aaa",bar:"bbb"};
console.log(b+f); //bbbaaa
let obj = {
p: ['hello',{
y:'world'}]
}
let {
p:[x,{
y}]} = obj;
console.log(x+y); //helloworld
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
}
let {
loc,loc:{
start},loc:{
start:{
line}}} = node;
// line // 1
// loc // Object {start: Object}
// start // Object {line: 1, column: 5}
let obj2 = {
};
let arr2 = [];
({
foo2:obj2.pro,bar2:arr2[0]}={
foo2:123,bar2:456});
console.log(obj2,arr2);
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
属性名与变量名
由于变量名与属性名并不一致,所以需要如下方式来改变,以实现如上的效果。
<script type=”text/traceur”>
var{
name:person_name,age:person_age,id:person_id}={
id:”007”,age:23,name:”zhangsan”};
console.log(person_name); //zhangsa
console.log(person_age); //23
console.log(person.id); //007
</script>
对象解构指定默认值生效条件
默认值生效的条件是,对象的属性值严格等于undefined。
<script type=”text/traceur”>
var {
a=3} = {
a= undefined};
console.log(a); //3
var {
b=3} = {
b=null };
console.log(b); // null
</script>
现有对象的方法
<script type=”text/traceur”>
console.log(Math.PI/6);
let {
sin,cos,tan} = Math;
console.log(sin(Math.PI/6));
</script>
字符串的解构赋值
字符串被转换为一个类似数组的对象。
属性的解构赋值:由于字符串属性length,可以利用该属性进行解构赋值。
const [a,b,c,d,e] = "hello";
console.log(a,b,c,d,e); //hello
let {
length:len} = "hello";
console.log(len); //5
数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
注:解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
函数参数的解构赋值
<script type=”text/traceur”>
function fun( {
x=0,y=0} = {
} ){
return [x,y];
};
console.log(fun( {
x:100,y:200} ) ); //[100,200]
console.log(fun({
x:100})); //[100,0]
console.log(fun({
})); //[0,0]
</script>
解构赋值的用途
交换变量的值
<script type="text/traceur">
//ES5
console.log("ES5:");
var a=100;
var b=200;
console.log("交换前:");
console.log("a="+a); //100
console.log("b="+b); //200
var temp;
temp=a;
a=b;
b=temp;
console.log("交换后:");
console.log("a="+a); //200
console.log("b="+b); //100
//ES6
console.log("ES6:");
var x,y;
console.log("交换前:");
console.log("a="+a); //100
console.log("b="+b); //200
//利用数组解构的方法进行交换
[x,y] = [y,x];
console.log("交换后:");
console.log("a="+a); //200
console.log("b="+b); //100
</script>
从函数中返回值
返回数组
<script type="text/traceur">
function fun(){
return [1,2,3];
};
var [x,y,z] = fun();
console.log(x); //1
console.log(y); //2
console.log(z); //3
</script>
返回对象
<script type="text/traceur">
function fun(){
return {
id:"007",
name:"zhao",
age:20
};
};
var {
id,name,age} = fun();
console.log(id);
console.log(name);
console.log(age);
var {
id:person_id,name:person_name,age:person_age} = fun();
console.log(person_id);
console.log(person_name);
console.log(person_age);
</script>
函数参数定义
function fun(id,name,age){
};
fun({
id:"007",name:"zhao",age:20});
//参数是一组无次序的值
function fun({
x,y,z}){
};
fun({
x:100,y:200,z:300});
函数参数默认值
<script type="text/traceur">
jQuery.ajax =function(url,{
async = true,
beforeSend = function(){
},
cache = true,
global = true,
}){
//
};
</script>
遍历Map结构
<script type="text/traceur">
var map =new Map();
map.set("id","007");
map.set("name","Zhao");
console.log(map); //Map{id => "007",name =>"Zhao"}
console.log(typeOf(map)); //Object
for(let [key,value] of map){
console.log(key+"is" + value);
}
// id is 007
// name is Zhao
//获取键名
for(let[key] of map){
console.log(key);
}
// id
// name
//获取键值
for(let[,value] of map){
console.log(value);
}
// 007
// Zhao
</script>
提取JSON数据
<script type="text/traceur">
var jsonData ={
id:"007",
name:"zhao",
age:20,
score:[100,90,89]
};
console.log(jsonData);
console.log("ES5");
console.log("Name"+jsonData.name);
console.log("age"+jsonData.age);
console.log("Chinese score"+jsonData.score[0]);
console.log("Math score"+jsonData.score);
console.log("ES6");
let{
id:number, name,age,score.score } =jsonData;
console.log(number);
console.log(name);
console.log(age);
conosle.log(score.Chinese);
</script>
(1).var arr = [2,3,4,5];
var arr2 = Array.from(arr);
(2). var arr = [2,3,4,5];
var arr2 = [];
for(var i = 0 ; i < arr.length ; i++){
arr2[i]=arr[i]
}
(3). var arr2 = [...arr];
案例:
function show(...args){
console.log(...args);
}
show(1,2,3,4);
ES6中可以使用 => 作为函数表达形式,极简风格,参数+ => +函数体。
var foo = function(){
return 1;};
//等价于
let foo = () => 1;
let nums = [1,2,3,5,10];
let fives = [];
nums.forEach(v => {
if (v % 5 === 0)
fives.push(v);
});
console.log(fives); //[5,10]
//箭头函数中的 this 指的不是window,是对象本身。
//arguments不能使用this
const full = ({
first,last}) => first + ' ' + last;
//等同于
function full(person){
return person.first + ' ' + person.last;
}
//箭头函数可以与变量解构结合使用。
注意点:
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
不可以使用yield命令,因此箭头函数不能用作Generator函数。
箭头函数this指向问题
箭头函数里面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域。
this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
对象语法简洁化
var name = 'a';
var age = 122;
var person = {
name,
age,
showName(){
return this.name;
},
showAge(){
return this.age;
}
}
面向对象:
Es5:
function Person(name,age){
//类,构造函数
this.name = name;
this.age = age;
}
Person.prototype.showName = function(){
return this.name;
}
Person.prototype.showAge = function(){
return this.age;
}
var p1 = new Person('aaa',23);
console.log(p1.showName());
es6:
类: class
构造函数: constructor 生成完实例以后,自己就执行的
class Person{
constructor(name='default',age=0){
函数的默认值
this.name = name ;
this.age = age;
}
showName(){
return this.name;
}
showAge(){
return this.age;
}
}
var p = new Person('aaa',12);
console.log(p.showName());
继承:
Es5:
子类.prototype = new 父类();
Es6:
class Worker extends Person{
}
var w1 = new Worker('mmm',232);
console.log(w1.showAge());
class Worker extends Person{
constructor(name,age,job='扫地的'){
super(); //调用父级的构造
this.job = job;
}
showJob(){
return this.job;
}
}
var w1 = new Worker('mmm',232);
console.log(w1.showAge());
console.log(w1.showJob());
循环遍历整个对象
var arr = ['aa','bb','dd'];
for(var i in arr){
console.log(arr[i]);
} //for in 循环数组,i为下标
for(var i of arr){
console.log(i);
} //for of 循环数组,i为值
var json = {
'a':'apple','b':'banan','o':'orange'};
for(var i in json){
console.log(json[i]);
} // for in 循环数组,数组为键,但不能用for of 循环json
全局对象:最顶层对象。
ES6中规定:
属于全局对象的属性:var、function声明的全局对象
不属于全局对象属性:let、const、class命令声明的全局对象
全局对象的属性
<script type=”text/traceur”>
var varName =”varValue”;
//浏览器环境
console.log(window.varName); //varValue
//node.js环境
console.log(global.varName); //varValue
//通用环境
console.log(this.varName); //varValue
let letName =”letValue”;
console.log(window.letName); //letValue || undefined—use strict
console.log(this.letName); //letValue || undefined—use strict
</script>
必须引入traceur和bootstrap,type必须写成module
ES6自带模块化
如何定义(导出)模块
const a = 12;
export default a;
const b = 12;
export default {a,b}
如何使用(引用)
Import modA from ‘./a.js’
三种状态:
pendingz(等待、处理中)——》Resolve(完成)
——》Rejected(拒绝、失败)
var p1 = new Promise(function(resolve,reject){
//resolve 成功了
//reject 失败了
});
var p1 = new Promise(function(resolve,reject){
if(异步处理成功了){
resolve(成功的数据)
}else{
reject(失败的原因)
}
});
p1.then(成功(resolve),失败(reject))
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
案例:
let s1 = Symbol();
let s2 = Symbol();
console.log(s1 === s2); //false
let s11 = Symbol('aaa');
let s22 = Symbol('bbb');
console.log(s11 === s22); //false
Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity。
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
Number.isNaN()用来检查一个值是否为NaN。
Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true'/0) // true
Number.isNaN('true'/'true') // true
新方法与传统全局方法区别
它们与传统的全局方法isFinite()和isNaN()的区别在于:
isFinite(25) // true
isFinite("25") // true
Number.isFinite(25) // true
Number.isFinite("25") // false
isNaN(NaN) // true
isNaN("NaN") // true
Number.isNaN(NaN) // true
Number.isNaN("NaN") // false
Number.isNaN(1) // false
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
这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
Number.isInteger()用来判断一个数值是否为整数。
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
Number.isInteger("15") // false
Number.isInteger(true) // false
Number.EPSILON
ES6在Number对象上面,新增一个极小的常量Number.EPSILON。
Number.EPSILON
// 2.220446049250313e-16
Number.EPSILON.toFixed(20)
// '0.00000000000000022204'
Math.trunc方法用于去除一个数的小数部分,返回整数部分。
Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
Math.trunc(-4.9) // -4
Math.trunc(-0.1234) // -0
对于非数值,Math.trunc内部使用Number方法将其先转为数值。
Math.trunc('123.456')
// 123
对于空值和无法截取整数的值,返回NaN。
Math.trunc(NaN); // NaN
Math.trunc('foo'); // NaN
Math.trunc(); // NaN
Math.sign方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
Math.sign(-5) // -1
Math.sign(5) // +1
Math.sign(0) // +0
Math.sign(-0) // -0
Math.sign(NaN) // NaN
Math.sign('foo'); // NaN
Math.sign(); // NaN
Math.imul方法返回两个数以32位带符号整数形式相乘的结果,返回的也是一个32位的带符号整数。
Math.imul(2, 4) // 8
Math.imul(-1, 8) // -8
Math.imul(-2, -2) // 4
Math.fround方法返回一个数的单精度浮点数形式。
Math.fround(0) // 0
Math.fround(1) // 1
Math.fround(1.337) // 1.3370000123977661
Math.fround(1.5) // 1.5
Math.fround(NaN) // NaN
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set 本身是一个构造函数,用来生成 Set 数据结构。
const s = new Set();
[2,3,4,4,6,7].forEach(x => s.add(x));
for(let i of s){
console.log(i);
}
const set = new Set([2,3,4,4,6,7]);
console.log(...set);
console.log(set.size);
数组去重:
展示了一种去除数组重复成员的方法。
[...new Set(array)]
const items = new Set([1,2,3,4,5,5]);
const array = Array.from(items);
console.log(items);
console.log(array);
Set的属性:
set.size,返回Set实例的成员总数。
Set的方法:Set 实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。
Set的遍历操作:
let set = new Set(['red','green','blue']);
for(let item of set.keys()){
console.log(item);
}
for(let item of set.values()){
console.log(item);
}
for(let item of set.entries()){
console.log(item);
}
set.forEach(x => console.log(x));
let arr = [...set];
console.log(arr);
JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
map和object比较
Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应。
var map = new Map();
map.set('a','apple'); //设置值
map.set('b','banana');
map.set('o','orange');
console.log(map);
console.log(map.get('a')); //获取值
console.log(map.get('b'));
map.delete('a'); //删除
console.log(map);
//遍历map
for(var name of map){
console.log(name); //键值
}
for(var [key,value] of map){
console.log(key,value); //键和值
}
for(var name of map.entries()){
//默认
}
for(var key of map.keys()){
console.log(key); //只循环键
}
for(var value of map.values()){
console.log(value); //只循环值
}
for of 也可循环数组,但不能单独循环值
Map实例属性
遍历方法 §
Map 结构原生提供三个遍历器生成函数和一个遍历方法。
const map = new Map([
['f','no'],
['t','yes']
]);
for(let key of map.keys()){
console.log(key);
}
for(let value of map.values()){
console.log(value);
}
for(let item of map.entries()){
console.log(item);
}
map.forEach(item => console.log(item));
全局对象:最顶层对象。
ES6中规定:
属于全局对象的属性:var、function声明的全局对象
不属于全局对象属性:let、const、class命令声明的全局对象
ES5中顶层对象是window,顶层对象的属性与全局变量是等价的
ES6规定,var 和 function 命令是全局变量,依旧是顶层对象的属性,但是let和const,class命令的全局变量不属于顶层对象的属性,也就是说es6开始,全局变量逐渐与顶层对象的属性脱钩
ctrl+shift+方向键 使代码跳到上下行