ES6知识点总结

1,for循环的特别之处,即是循环语句部分是一个父作用域,而循环体内部是一个单独的子作用域。

for (var i=0;i<3;i++){ 
    var i='andy'; 
    console.log('i='+i)//i=andy(打印一次然后退出循环)
}

我们看下let语句

for(let i=0;i<3;i++){ let i='andy'; console.log(i); }

结果是:

andy

andy

andy

输出了3次,这表明函数内部的变量i和外部的变量i是分离的;

2,es6中不存在变量提升

console.log(aa);// undefiend(变量提升,但是没有值,所以会打印出undefined) 
var aa = 2; 

console.log(bb);// 引用错误(let不会发生变量提升,说明在声明之前,bb是不存在的,此时会抛出错误); 
let bb = 2;

3,暂时性封闭性死区

//只要在块级作用域中存在let命令,它所声明的变量就绑定了在这个区域,不再受外部的影响; 
var aa = 'andy'; 

if(aa){ 
    aa = 'jack';// 引用错误 
    let aa; 
}

//因此衍生的一个问题是typeof 操作符的运用是否安全

typeof aa;//referenceError 

let aa; //然而,如果一个变量没有let声明,反而不会出错;
typeof bb;//undefined

在没有let之前,typeof运算符是安全的;现在在es6中则会出现问题;

这一设计原则是为了让大家,变量一定要在声明之后使用

否则会报错;

4,隐含的容易出错的

function act(x=y,y=2){
     console.log(x+y);
    // 参数x默认等于参数y,而此时y没有声明,有些浏览器会打印出NAN,有些浏览器会报错
} 
act(); //如果y的值默认是x,就不会报错,因为此时x已经声明过了

function acts(x=2,y=x){ 
    console.log(x+y);
} 
acts();//4

5,使用let声明变量时,只要变量在还没有声明完成前使用,就会报错;

var x=x;// 不会报错

let x=x;//使用let声明变量时,只要变量在还没有声明完成前使用,就会报错

6,不允许重复声明变量;

function aa(){ let a=2; var a=1;//报错 }

aa();

因此不能在函数内部重新声明参数;

function aa(name){ let name;//报错 }

function aa(name){ { let name;//正确 } }

7,块级作用域

 

var mydate = new Date(); function create(){ console.log(mydate); if(false){ var mydate = 'andy'; } } create();// undefined

变量提升导致内部的mydate覆盖外层的mydate变量;

var a = 'andy'; for(var i =0;i

而es6规定了块级作用域

function a(){ let i = 1; if(true){ let i =2; console.log(i);//2 } console.log(i);//1---外层变量不受内部变量的影响 } a();

 

而es6也允许块级作用域的嵌套

{ { { let name = 'andy'; console.log(name);//andy } console.log(name);//为空或者报错(看浏览器) } }

 

块级作用域的出现,实际上说明了我们之前用到了立即执行函数的退下历史舞台;

(function(){ let name = 'andy'; })(); { let name = 'andy'; }

 

考虑到环境导致的行为差异太大,应该避免在块级作用域中声明函数;如果确实需要也应该写成函数表达式而不是函数声明语句;

{ //函数声明语句 let name = 'andy'; function f(){ return name; } } { //函数表达式---推荐 let names = 'andy'; let f = function(){ return names; } }

 

提示:es6允许在块级作用域中声明函数,前提是必须有大括号,否则会报错;

if(true){ function f(){ } }

 

if(true) function f(){//报错,如果用es6编译的话,就提示报错 }

8,const命令

const声明的常量值,不允许改变;

const a = 1; console.log(a); a = 3;//报错

也就是说,一但声明了常量值,就必须赋值;

const a;//必须赋值,否则会报错

当然了,const和let作用域一样,必须在块级才生效;同时,不可重新赋值;

9,es6声明变量的6种方法;

1,var 2,function 3,let 4,const 5,import 6,class

10,顶层对象的属性;

顶层对象在浏览器中指的是window,在node环境中指的是global;

顶层对象的属性和全局变量关联;

window.a= 1; console.log(a);//1

而es6规定,let,const,class声明的全局变量不属于顶层对象;也就是说从es6开始,全局变量逐步与顶层对象的属性脱离;

11,数组的结构赋值

//以前,为变量赋值,只能指定值; let a =1; let b=2; let c=3; console.log(a,b,c);//1,2,3 //而es6,可以这样写--可以从数组中提取值,按照对应位置,对变量赋值。 let [a,b,c] = [1,2,3]; console.log(a,b,c);//1,2,3 let [a,[b,c]] = ['andy',[2,3]]; console.log(a,b,c);//andy,2,3

 

这种就是模式匹配,只要左边和右边的值对应,就会产生一一对应;

let [,,name] = [1,2,'andy']; console.log(name);//andy let [school,...name] = ['香港城市大学','andy','lucy','jack']; console.log(school,name);//香港城市大学 [andy,lucy,jack] let [x, y, ...z] = ['a']; console.log(x,y,z);//a,undefiend,[]

 

当然,如果解构不成功,就会返回undefiend;

let [foo] = []; let [bar, foos] = [1]; console.log(foo,bar,foos);//undefined,1,undefined

另外,

let [age] = 20; console.log(age);//报错

 

而对于Set结构,也同样可以使用数组的结构赋值

let [x,y,z] = new Set(['a','b','c']); console.log(x,y,z);//a,b,c

 

重点:迭代器iterators

Iterator接口的意思就是说:符合Iterator接口的对象里需要有一个叫next的函数,这个函数需要返回一个对象,

并且这个对象符合IteratorResult接口规范;

IteratorResult接口里面定义了两个属性,一个是done,代表迭代是否已经完成。另一个属性value代表迭代过程中产生的值。

之所以可以采用数组的结构赋值,是因为只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值;

12,es6中的默认值

let [x,y = 'b'] = ['a']; console.log(x,y);//a,b let [bar = true] = []; console.log('bar='+bar);//true let [a,b='2'] = ['1',undefined]; console.log(a,b);//1,2 let [m,n]= [1,2]; console.log(m,n);//1,2 //es6内部使用严格相等运算符(===),判断一个位置是否有值; //所以一个数组成员不严格等于undefiend,默认值就不会生效;即严格等于undefiend,默认值就会生效 let [m1 = '1'] = [undefined]; console.log(m1);//1 let [m2 = '2'] = [null]; console.log(m2);//null 因为此处相当于将null赋值给了m2

 

上面中一个数组成员为null,默认值就不会生效;因为null不严格等于undefiend;

但是,如果默认值是一个表达式,只有在用到到时候才会调用;

function f(){ return 1; } let [x=f()] = [2]; console.log(x);//2--x能取到值,所以不用吊用f()函数 let [y=f()]=[]; console.log(y);//1--y不能取到值,掉用了f()函数

 

默认值可以引用解构赋值的其他变量,但该变量必须已经声明

let [x1=1,y1=x1] =[]; console.log(x1,y1);//1,1 let [x2=2,y2=x2]=[2]; console.log(x2,y2);//2,2 let [x3=3,y3=x3]=[1,2]; console.log(x3,y3);//1,2 let [x4=y4,y4=4]=[]; console.log(x4,y4);//报错

 

13,对象的解构赋值;

let {x1,y1} = {x1:'1',y1:'2'}; console.log(x1,y1);//1,2

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;

而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

let {x2,y2} = {y2:'1',x2:'2'}; console.log(x2,y2);//2,1 let {x3,y3} = {x3:'1',y4:'3'}; console.log(x3,y3);//1,undefiend--变量没有对应的同名属性,导致取不到值,最后undefiend

 

如果,变量名和属性名不一致,可以写成这样:

let {foo:baz}= {foo:'1',bar:'2'}; console.log(baz);//1 let obj = {foo:'1',bar:'2'}; let {foo:f,bar:b} = obj; console.log(f,b);//1,2

 

实际上,对象的解构赋值的内部机制,先找到同名属性,然后再赋给对应的变量;

正在被赋值的是后者,不是前者;

let {foo:baz}= {foo:'1',bar:'2'}; console.log(baz);//1 console.log(foo);//报错,foo is undefined

 

上面foo是匹配模式,bar才是变量;也就是说真正被赋值的是bar,不是foo;

这种写法,变量的声明和赋值是一体的;对于let和const来说,变量不能重新声明,否则会报错;

let foo; let {foo} = {foo:'1'};//报错 //和数组一样,解构也可以用于嵌套结构的对象; let obj ={ p:[ 'hello', { y:'world' } ] }; let {p:[x,{y}]}= obj; console.log(x,y);//hello,world

 

此时,p是模式,不是变量;

同时,解构允许,等号左边的模式之中,不放置任何变量名;因此会写出非常奇怪的赋值表达式;

虽然没有任何意义,但是是合法的;

({} = [true,false]); ({}='abc');

 

14,字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

let [a,b,c,d,e] = 'andys'; console.log(a,b,c,d,e);//a,n,d,y,s //类数组的对象都有一个length属性,因此还可以对这个属性解构赋值。 let {length:len} = 'hello';//转化为了{0:h,1:e,2:l,3:l,4:o,length:5} console.log(len);//5

 

15,数值和布尔值的解构赋值

//解构赋值时,如果等号右边是数值和布尔值,则会先转为对象 let {toString:s} = 132; console.log(s===Number.prototype.toString);//true let {toString:b} = true; console.log(b===Boolean.prototype.toString);//true

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。

由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。

let {foo:x} = undefined;//报错

 

16,函数参数的解构赋值

function f([x,y]){//--在传入参数的时候,数组参数就被解构成变量 console.log(x+y); } f([1,2]);//3 //函数的参数的解构也可以使用默认值 //通过对这个对象解构,得到x和y的值,如果解构失败,则使用默认值 function f({x=0,y=0} = {}){ console.log([x,y]); } f({x:3,y:4});//[3,4] f({x:3});//[3,0] f({});//[0,0] f();//[0,0]

 

17,圆括号的问题

如果模式中出现圆括号怎么处理。

ES6的规则是,只要有可能导致解构的歧义,就不得使用圆括号;

注意:以下三种情况不要使用圆括号

(1)声明变量的时候

let [(a)] = [1]; let {x:(y)} = {};

(2)函数参数中不能带圆括号

function f([(a)]){ console.log(a); }

(3)赋值语句中,不能将整个模式或者嵌套模式中的一层,放在圆括号之中;

({m:n}) = {m:42}; ([x]) = [5];

其实,可以使用圆括号的只有一种情况:

赋值语句的非模式部分,可以使用圆括号

let b; let d; [(b)] = [2]; console.log(b);//2 ({p:(d)} = {}); console.log(d);//undefined

那么,变量的解构赋值都有哪些用途呢?

(1)交互变量的值

let x=1; let y=2; [x,y] = [y,x]; console.log(x,y);//2,1

(2)从函数返回多个值

//函数只能返回一个值,如果要返回多个值,只能将他们放在数组或对象里返回. //返回一个数组 function f(){ return ['a','b','c']; } let [a,b,c] = f(); console.log(a,b,c); //返回一个对象 function m(){ return{ foo:1, bar:2 } } let {foo,bar} = m(); console.log(foo,bar);//1,2

(3)函数参数的定义

//解构赋值可以很方便的将一组参数与变量名对应起来 function f([a,b,c]){ console.log(a,b,c); } f([1,2,3]);//1,2,3 function m({x,y,z}){ console.log(x,y,z); } m({y:2,z:1,x:3});//3,2,1

(4)提取json数据

let myJson = { name:'andy', age:28, school:'香港城市大学', className:['刘德华','梁朝伟'] }; let {name,age,school,className:names} = myJson; console.log(name,age,school,names);

因此,可以快速提取json数据的值;

(5)函数参数的默认值

(6)遍历map结构

//部署了iterator接口的对象,都可以使用for..of遍历,Map结构原生支持iterator接口, //配合变量的解构赋值,获取键名和键值就方便多了; var map = new Map(); map.set('first','hello'); map.set('second','andy'); for(let [key,value] of map){ console.log(key+' is '+value) } //first is hello //second is andy

Map

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

 Map的定义。

//空map设值key-value var m = new Map(); m.set("XiaoMing",99); m.set("XiaoHong",66); //构造参数传key-value var m = new Map([['XiaoMing', 99], ['XiaoHong', 66]]);

  Map中的方法

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

 对一个key重复设值,后面的值会将前面的值覆盖。

var m = new Map(); m.set('XiaoMing', 99); m.set('XiaoMing', 98); m.get('XiaoMing'); // 98

Set

 Set和Map类似,但set之存储key,且key不重复。

 Set的创建。

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

 插入重复的值,set会将重复的值进行过滤

var s = new Set([1, 2, 3]); s.add(3); >>s; // Set{1,2,3} s.delete(3); >>s; // Set([1,2]);

 

(7)输入模块的制定方法

18,字符串的扩展

//js允许\uxxxx形式表示一个字符,其中'xxxx'表示字符的码点 '\u0061'; //但是,这种表示法只限于\u0000——\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表达。 "\uD842\uDFB7"; "\u20BB7";//' 7' //上面代码表示,如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JavaScript会理解成\u20BB+7。 // 由于\u20BB是一个不可打印字符,所以只会显示一个空格,后面跟着一个7。 //ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。 "\u{20BB7}";

 

ES6为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历。

for(let codePoint of 'foo'){ console.log(codePoint);//f,o,o }

(1),includes(),startsWith(),endsWith();

//传统上,js只有indexof方法可以用来确定一个字符串是否包含在另一个字符串中 
//ES6又提供了三种新方法 
/** includes():返回布尔值,表示是否找到了参数字符串。
 startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。 
endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
 */
var s = 'andy'; 
console.log(s.includes('y'));//true 
console.log(s.startsWith('a'));//true 
console.log(s.endsWith('y'));//true
 //这三个方法都支持第二个参数,表示开始搜索的位置。
var m= 'andy';
 console.log(m.includes('y',1));//true
 console.log(m.startsWith('a',0));//true 
console.log(m.endsWith('y',3));//false 
//上面代码表示,使用第二个参数n时,endsWith的行为与其他两个方法有所不同。
 // 它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。

 

(2)repeat()

repeat方法返回一个新字符串,表示将原字符串重复n次。

var m ='x'.repeat(3); 
console.log(m);//xxx 
//参数如果是小数,会被取整。
 console.log('andy'.repeat(2.6));//andyandy
 //如果repeat的参数是负数或者Infinity(无穷),会报错。 
//console.log('andy'.repeat(-1));//报错
 /** * 但是,如果参数是0到-1之间的小数,则等同于0,这是因为会先进行取整运算。 
* 0到-1之间的小数,取整以后等于-0,repeat视同为0。
 * 参数NaN等同于0。 
* 如果repeat的参数是字符串,则会先转换成数字。 * */ console.log('andy'.repeat('2'));//andyandy

(3)padStart(),padEnd()

ES7引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。

padStart()用于头部补全,padEnd()用于尾部补全。

如果原字符串的长度,等于或大于指定的最小长度,则返回原字符串。

console.log('cc'.padStart(2, '123'));//cc console.log('cccc'.padStart(2, '123'));//cccc

如果用来补全的字符串与原字符串,两者的长度之和超过了指定的最小长度,则会截去超出位数的补全字符串。

console.log('cccc'.padStart(6, '123'));//12cccc

位数不够 自动补充

var data = new Date(); var h = data.getHours().toString().padStart(2,'0'); var m = data.getMinutes().toString().padStart(2,'0'); var s = data.getSeconds().toString().padStart(2,'0'); console.log(h + ':' + m + ':' + s);//21:27:02

(4)模板字符串

$('#mydiv').append(` 荣贺,${'成龙'}拿了奥斯卡奖, 对此,我们庆幸,他说,${'很高兴自己是个中国人!'} `);

模板字符串(template string)是增强版的字符串,用反引号(`)标识。

它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

// 字符串中嵌入变量
 var name = "andy", 
time = "today"; 
console.log(`Hello ${name}, how are you ${time}?`);
 //模板字符串中嵌入变量,需要将变量名写在${}之中。
 //如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
 var greeting = `\`You\` World!`; 
console.log(greeting);//`You` World! 
//如果使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
 $('#mydiv').html(`
 
  • 加油
  • 中国!
`);

(5)标签模板

//它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。 
// 这被称为“标签模板”功能(tagged template)。 
alert('123'); //等同于 alert`456`; 
//标签模板其实不是模板,而是函数调用的一种特殊形式。
 // “标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
 //但是,如果模板字符里面有变量,就不是简单的调用了, 
// 而是会将模板字符串先处理成多个参数,再调用函数。
 let a= 1; 
let b=2;
tag`hello ${a+b} world ${a*b}`; //等同于 tag(['hello ',' world',''],3,2);
 //上面代码中,模板字符串前面有一个标识名tag,它是一个函数。
 // 整个表达式的返回值,就是tag函数处理模板字符串后的返回值。 
//函数tag依次会接收到多个参数 
function tag(stringArr, value1, value2){ // ... } 
// 等同于 function tag(stringArr, ...values){ // ... } 
//tag函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分, 
// 也就是说,变量替换只发生在数组的第一个成员与第二个成员之间、第二个成员与第三个成员之间,以此类推。 
// 
//tag函数的其他参数,都是模板字符串各个变量被替换后的值。 
// 由于本例中,模板字符串含有两个变量,因此tag会接受到value1和value2两个参数。 
// //tag函数所有参数的实际值如下: 
//第一个参数:['Hello ', ' world ', ''] 
//第二个参数: 15 
//第三个参数:50 
//也就是说,tag函数实际上以下面的形式调用。 
tag(['Hello ', ' world ', ''], 15, 50); 
var a = 5; var b = 10; 
function tag(s, v1, v2) { 
    console.log(s[0]); 
    console.log(s[1]); 
    console.log(s[2]); 
    console.log(v1); 
    console.log(v2);
     return "OK"; 
} 
tag`Hello ${ a + b } world ${ a * b}`;
 let a=2;
 let b=3; 
function tag(s,n1,n2){ 
    console.log(s[0]);
     console.log(s[1]);
     console.log(s[2]);
     console.log(n1); 
    console.log(n2); 
    console.log('ok!') 
} 
tag(['hello ',' world',''],5,6); 
tag`hello ${a+b} world ${a*b}`;

“标签模板”的一个重要应用,就是过滤HTML字符串,防止用户输入恶意内容。

var message = SaferHTML`

${'成龙'} has sent you a message.

`; function SaferHTML(templateData) { console.log(templateData); // ["

", " has sent you a message.

"] var s = templateData[0]; console.log(arguments); //[["

", " has sent you a message.

"],"成龙"] console.log(arguments.length);//2 for (var i = 1; i < arguments.length; i++) { var arg = String(arguments[i]); console.log(arg)//成龙 s += arg.replace(/&/g, "&") .replace(//g, ">"); s += templateData[i]; } return s; } console.log(message)//

成龙 has sent you a message.

(6)String.raw()

//String.raw方法,往往用来充当模板字符串的处理函数,
 //返回一个斜杠都被转义(即斜杠前面再加一个斜杠)的字符串,对应于替换变量后的模板字符串。 console.log(String.raw`Hi\n${2+3}!`);//Hi\n5! 
//String.raw方法可以作为处理模板字符串的基本方法,它会将所有变量替换,而且对斜杠进行转义,


//方便下一步作为字符串来使用。
 //String.raw方法也可以作为正常的函数使用。
 //这时,它的第一个参数,应该是一个具有raw属性的对象,且raw属性的值应该是一个数组。 
console.log(String.raw({raw:'andy'},1,2,3));//a1n2d3y
 console.log(String.raw({raw:['a','n','d','y']},1,2,3));//a1n2d3y

19,正则的使用

(1)RegExp构造函数

//RegExp构造函数 //es5中regexp有两种写法 //第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。 var reg = new RegExp('andy','i'); var reg = /andy/i; //第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝。 var reg = new RegExp(/andy/i); var reg = /andy/i; //但是,此时,es5不允许使用第二个参数添加修饰符,否则会报错;如下: var reg = new RegExp(/andy/,'i'); //ES6改变了这种行为。如果RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。 //而且,返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。 var reg = new RegExp(/andy/ig,'i').flags;//---此时i会覆盖ig;

(2)字符串的正则方法

//字符串对象共有4个方法,可以使用正则表达式:match()、replace()、search()和split()。
 //ES6将这4个方法,在语言内部全部调用RegExp的实例方法,从而做到所有与正则相关的方法,全都定义在RegExp对象上。
 //String.prototype.match 调用 RegExp.prototype[Symbol.match] 
//String.prototype.replace 调用 RegExp.prototype[Symbol.replace] //String.prototype.search 调用 RegExp.prototype[Symbol.search]
 //String.prototype.split 调用 RegExp.prototype[Symbol.split]

 

20,数值的扩展

(1)二进制和八进制的写法

es6提供了二进制和八进制新的写法,分别使用前缀0b(或者0B)和0o(或者0O)表示;

(2)Number.isFinite(),Number.isNaN()为number对象提供了两个方法;

//Number.isFinite()用来检查一个数值是否为有限的(finite) console.log(Number.isFinite(15));//true console.log(Number.isFinite(true));//false console.log(Number.isFinite('10'));//false //Number.isNaN()用来检查一个值是否为NaN。 console.log(Number.isNaN(0));//fasle console.log(Number.isNaN(NaN));//true console.log(Number.isNaN('10'));//false

它们与传统的全局方法isFinite()和isNaN()的区别在于,传统方法先调用Number()将非数值的值转为数值,

再进行判断,而这两个新方法只对数值有效,非数值一律返回false。

(3)Number.parseInt(), Number.parseFloat()

为了逐步减少全局性方法,使得语言逐步模块化。

ES6将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变;

// ES5的写法 console.log(parseInt('12.34')); // 12 console.log(parseFloat('123.45#33')); // 123.45 // ES6的写法 console.log(Number.parseInt('12.34')); // 12 console.log(Number.parseFloat('123.45#33')); // 123.45

(4)Number.isInteger()

Number.isInteger()用来判断一个值是否为整数。

需要注意的是,在JavaScript内部,整数和浮点数是同样的储存方法,所以4和4.0被视为同一个值;

console.log(Number.isInteger(2));//true console.log(Number.isInteger(2.0));//true console.log(Number.isFinite(true));//false console.log(Number.isFinite(false));//false

(5)Number.EPSILON

//ES6在Number对象上面,新增一个极小的常量Number.EPSILON 读音:ε,值为2.220446049250313e-16 //引入一个这么小的量的目的,在于为浮点数计算,设置一个误差范围。我们知道浮点数计算是不精确的。 console.log(0.1+0.2);//0.30000000000000004 //但是如果这个误差能够小于Number.EPSILON,我们就可以认为得到了正确结果。 console.log(5.551115123125783e-17 < Number.EPSILON);//true //因此,Number.EPSILON的实质是一个可以接受的误差范围。

(6)Math对象的扩展

ES6在Math对象上新增了与数学相关的方法。所有这些方法都是静态方法,只能在Math对象上调用;

Math.trunc() --Math.trunc方法用于去除一个数的小数部分,返回整数部分

console.log(Math.trunc(4.1));//4 console.log(Math.trunc(-5.89));//-5

对于非数值,Math.trunc内部使用Number方法将其先转为数值;

对于空值和无法截取整数的值,返回NaN;

console.log(Math.trunc('1234.56'));//1234 console.log(Math.trunc());//NaN console.log(Math.trunc('sa'));//NaN

Math.sign方法用来判断一个数到底是正数、负数、还是零;

  • 参数为正数,返回+1;
  • 参数为负数,返回-1;
  • 参数为0,返回0;
  • 参数为-0,返回-0;
  • 其他值,返回NaN。

Math.cbrt方法用于计算一个数的立方根;

对于非数值,Math.cbrt方法内部也是先使用Number方法将其转为数值。

console.log(Math.cbrt('8'));//2 console.log(Math.cbrt('andy'));//NaN

三角函数方法

Math.sinh(x) 返回x的双曲正弦(hyperbolic sine) Math.cosh(x) 返回x的双曲余弦(hyperbolic cosine) Math.tanh(x) 返回x的双曲正切(hyperbolic tangent) Math.asinh(x) 返回x的反双曲正弦(inverse hyperbolic sine) Math.acosh(x) 返回x的反双曲余弦(inverse hyperbolic cosine) Math.atanh(x) 返回x的反双曲正切(inverse hyperbolic tangent)

21,数组的扩展

(1)Array.from()将两类对象转为真正的数组,第一个参数是数组,还可以接受第二个参数,方法类似于map,用来对每个元素进行处理

//类似数组的对象(array-like object)和可遍历(iterable迭代器)的对象(包括ES6新增的数据结构Set和Map)。
 let arr = { '0':'a', '1':'b', '2':'c', length:3 };
//类数组对象 let newArr = Array.from(arr); 
console.log(newArr);//['a','b','c']

实际应用中,常见的类似数组的对象是DOM操作返回的NodeList集合,

以及函数内部的arguments对象。Array.from都可以将它们转为真正的数组。

Nodelist对象

let li = document.querySelectorAll('li');
 Array.from(li).forEach(function(m){ console.log(m); });

querySelectorAll方法返回的是一个类似数组的对象,只有将这个对象转为真正的数组,才能使用forEach方法。

arguments对象

function createArr(n1,n2,n3){
    var arr = Array.from(arguments); 
    console.log(arr); 
} 
createArr(1,2,3);//[1,2,3]


let nameset = new Set(['a','b']); 
console.log(Array.from(nameset));//['a','b'] 
console.log(Array.from('andy'));//["a", "n", "d", "y"] 
//上面Set结构和字符串都具有iterator接口,因此可以被Array.from都能将其转化为数组;


//当然,如果参数本身就是一个数组,Array.from会返回一个一模一样的数组 
console.log(Array.from([1,2,3,4]));//[1, 2, 3, 4]


//有一点,扩展运算法(...)也可以将某些数据结构转换为数组 
//arguments对象
 function num1(){ var args = [...arguments]; } //nodelist对象 [...document.querySelectorAll('li')]; 
//扩展运算符背后调用的是遍历接口(symbol.iterator),如果一个对象没有部署这个接口,则无法转换;
 //Array.from还支持类似数组的对象.类似数组对象,本质上只有一点,就是具备length属性;
 //因此,任何具有length属性的对象,都可以通过Array.from方法转换为数组, 
//而此时扩展运算符就无法转换; console.log(Array.from({length:2}));
//[undefined, undefined]


//Array.from还可以接受第二个参数,方法类似于map,用来对每个元素进行处理
 //将处理后的值放入返回的数组; Array.from(arr,x => x*x); 
//等同于 Array.from(arr).map(x => x*x);
 console.log(Array.from([1,2,3,4], (x) => x*x));//[1, 4, 9, 16]


//下面的例子是取出一组DOM节点的文本内容
 let _doc = document,
 _div = _doc.getElementsByClassName('names')[0],
 _b = _div.getElementsByTagName('b');
 //map()
 let _names = Array.prototype.map.call(_b, s => s.textContent); 
console.log(_names);//["刘德华", "张学友", "郭富城", "黎明"] 
//Array.from() 
let _names1 = Array.from(_b,s => s.textContent);
 console.log(_names1);//["刘德华", "张学友", "郭富城", "黎明"]


//下面的例子会把数组中布尔值false转换为0 
console.log(Array.from([1,,3,4],(n) => n || 0));//[1, 0, 3, 4]

 

22,Array.of方法用于将一组值,转换为数组。

console.log(Array.of(1,20,23));//[1, 20, 23]

console.log(Array.of(34));//[34]

console.log(Array.of(3).length);//1

 

//这个方法主要的目的,是为了弥补数组构造函数Array()的不足,因为参数个数的不同,会导致Array()的行为差异; console.log(Array());//[] console.log(Array(2));//[] 长度length为2 console.log(Array(1,2,3));//[1,2,3] //上面代码中,Array方法没有参数、一个参数、三个参数时,返回结果都不一样。 //只有当参数个数不少于2个时,Array()才会返回由参数组成的新数组。参数个数只有一个时,实际上是指定数组的长度

Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。

console.log(Array.of());//[]

console.log(Array.of(2));//[2]

console.log(Array.of(1,2));//[1,2]

console.log(Array.of(undefined));//[undefined]

23,数组实例的copyWithin方法

数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),

然后返回当前数组。也就是说,使用这个方法,会修改当前数组。

Array.prototype.copyWithin(target, start = 0, end = this.length)

它接受三个参数。

  • target(必需):从该位置开始替换数据。
  • start(可选):从该位置开始读取数据,默认为0。如果为负值,表示倒数。
  • end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。

这三个参数都应该是数值,如果不是,会自动转为数值。

console.log([1,2,3,4,5].copyWithin(0,3));//[4, 5, 3, 4, 5] //将3号位置替换到0位 console.log([1,2,3,4,5].copyWithin(0,3,4));//[4, 2, 3, 4, 5]

 

24,数组实例的find方法

数组实例的find方法,用于找出第一个符合条件的数组成员。

它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。

如果没有符合条件的成员,则返回undefined

console.log([1,2,-3,-4,5].find((n) => n<0));//-3 
[1,2,5,20].find(function(value,index,arr){ return value > 10; });//20
 //上面代码中,find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。
 //数组实例的findIndex方法的用法与find方法非常类似,
 //返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。 
console.log([34,22,-5,100].findIndex((n) => n<0));//2 

//最后,这两个方法都可以发现NaN,弥补了数组方法的indexOf方法的不足; console.log([NaN].indexOf(NaN));//-1 
console.log([NaN].findIndex(y => Object.is(NaN,y)));//0

 

25,fill方法使用给定值,填充一个数组。

console.log(['a','b',1].fill('8'));//["8", "8", "8"] 
console.log(new Array(3).fill(8));//[8,8,8] 
//上面代码表明,fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。
 //fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置 console.log([1,3,4,6].fill(8,1,3));//[1,8,8,6]

26,entries(),keys()和values()——用于遍历数组

ES6提供三个新的方法——entries(),keys()和values()——用于遍历数组。它们都返回一个遍历器对象(详见《Iterator》一章),可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

for(let i of ['a','b',1].keys()){ console.log(i);//0,1,2 } for (let [index, elem] of ['a', 'b'].entries()) { console.log(index, elem);//0 'a' 1 'b' }

27,includes()

console.log([1,2,3,4].includes(2));//true
 console.log([1,2,3,4].includes(2,2));//false 
//该方法的第二个参数表示搜索的起始位置,默认为0。如果第二个参数为负数,则表示倒数的位置,
 //如果这时它大于数组长度(比如第二个参数为-4,但数组长度为3),则会重置为从0开始 
//没有该方法之前,我们通常使用数组的indexOf方法,检查是否包含某个值。
 //indexOf方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,
 //所以要去比较是否不等于-1,表达起来不够直观。 
//二是,它内部使用严格相当运算符(===)进行判断,这会导致对NaN的误判。 console.log([NaN].indexOf(NaN));//-1 
console.log([NaN].includes(NaN));//true

 

28,数组的空位

数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。

注意,空位不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值,in运算符可以说明这一点。

ES6则是明确将空位转为undefined。

Array.from方法会将数组的空位,转为undefined,也就是说,这个方法不会忽略空位。

console.log(Array.from([,1,undefined]));//[undefined, 1, undefined]

由于空位的处理规则非常不统一,所以建议避免出现空位。

 

你可能感兴趣的:(ES6,ES6,数组扩展,数值扩展)