深入浅出:了解JavaScript的ES6、ES7新特性

参照阮一峰博客:http://es6.ruanyifeng.com/#README 

es6常见题:https://blog.csdn.net/qq_39207948/article/details/80678800

数组用法:https://blog.csdn.net/tang15886395749/article/details/65629898 

导航:

1.箭头函数

2.字符串拓展

3.函数拓展

4.数组拓展

5.对象拓展 

 

一、简单介绍一下ES6加了些什么?

一、箭头函数

特点:①.简化代码;②改变this的指向,谁创建函数,this就指向谁。

 

1. 简单的定义:
胖箭头函数 Fat arrow functions,又称箭头函数,是一个来自ECMAScript 2015(又称ES6)的全新特性。有传闻说,箭头函数的语法=>,是受到了CoffeeScript 的影响,并且它与CoffeeScript中的=>语法一样,共享this上下文。
箭头函数的产生,主要由两个目的:更简洁的语法和与父作用域共享关键字this。接下来,让我们来看几个详细的例子
当需要编写一个简单的单一参数函数时,可以采用箭头函数来书写,标识名 => 表达式。
这样就可以省却 function 和 return 的输入,还有括号,分号等。箭头函数是ES6新增加的一个特性。
     let f = v => v;
最直接的感觉就是简便,当然不可能就是这么一点好处,下面就一起来探讨一下。
几个小细节 :
如果箭头函数的代码块多余一条语句,就必须要使用大括号将其括起来,并且使用return 语句返回。
由于大括号会被解释位为代码块,所以如果箭头函数直接返回一个对象,必须在外面加上括号。
let f = id => ({ age: 22, name: Alice })
箭头函数还可以和解构赋值 Destructuring 联合使用.
const f = ({ first, last }) => first + '' + last;
可以简化回调函数,大大简化和缩短代码行数。
2. 箭头函数和普通函数的区别(this的指向)
普通函数与箭头函数有个微小的不同点。 箭头函数没有自己的this值 ,其this值是通过继承其它传入对象而获得的,通常来说是上一级外部函数的 this 的指向。
function f() {
setTimeout(() => {
console. log( "id:", this. id);
}, 100);
}

f. call({ id: 42 }); //id: 42;
这个例子中, setTimeout 的参数是一个箭头函数, 每隔100毫秒运行一次,如果是普通函
数,执行的 this 应该指向全局对象, 但是箭头函数会让 this 总是指向函数所在的对象
箭头函数里面嵌套箭头函数会有多少个this呢?
看一个简单的例子
function f() {
return () => {
return () => {
return () => {
console. log( "id:", this. id);
};
};
};
}
f(). call({ id: 42 })()()(); //id: 42
上面的代码中只有一个 this, 就是函数f的this 。这是因为所有的内层函数都是箭头函数都没有自己的this,都是最外层f函数的this。
注意:还有三个变量在箭头函数中也是不存在的arguments , super, new.target所以顺理成章,箭头函数也就不能再用这些方法call(),apply(),bind(),因为这是一些改变this指向的方法,箭头函数并没有this啊。
var adder = {
base: 1,
add : function ( a) {
var f = v => v + this. base; return f( a);
},
addThruCall : function ( a) {
var f = v => v + this. base;
var b = { base: 2 };
return f. call( b, a);
}
};
console. log( adder. add( 1));
3. 怎么处理好箭头函数的使用问题呢?
使用非箭头函数来处理由object.method()语法调用的方法。因为它们会接收到来自调用者的有意义的this值。
在其它场合都使用箭头函数。
4. 使用箭头函数的注意点
箭头函数在参数和箭头之间不能换行。函数体内的this对象就是定义时所在的对象,而不是使用时所在的对象。
'use strict';
var obj = { a: 10 };
Object. defineProperty( obj, "b", {
get : () => {
console. log( this. a, typeof this. a, this);
return this. a + 10;
// represents global object 'Window', therefore 'this.a' returns 'undefined'
}
});
不可以当作构造函数,简单说就是不能再使用new命令了,不然会报错。
var Foo = () => { };
var foo = new Foo();
// TypeError: Foo is not a constructor
不可以使用arguments 对象,该对象在函数体内不存在,如果实在要用可以用rest代替。
不可以使用yield命令,箭头函数不可用作Generator函数。
值得注意的一点就是this对象的指向是可变的,但在箭头函数内是固定的。
5. 总结
箭头函数是我最喜欢的ES6特性之一。使用=>来代替function是非常便捷的。但我也曾见过只使用
=>来声明函数的代码,我并不认为这是好的做法,因为=>也提供了它区别于传统function,其所 
独有的特性。我个人推荐,仅在你需要使用它提供的新特性时,才使用它。
当只有一条声明语句(statement)时, 隐式 return。
需要使用到父作用域中的this。

二、字符串的一些新特性
1.字符的 Unicode 表示法
2.codePointAt()
3.String.fromCodePoint()
ES5 提供String.fromCharCode方法,用于从码点返回对应字符,但是这个方法不能识别 32 位的 UTF-16 字符(Unicode 编号大于0xFFFF)。
String. fromCharCode( 0x20BB7)
// "ஷ"
上面代码中,String.fromCharCode不能识别大于0xFFFF的码点,所以0x20BB7就发生了溢出,最高位2被舍弃了,最后返回码点U+0BB7对应的字符,而不是码点U+20BB7对应的字符。
ES6 提供了String.fromCodePoint方法,可以识别大于0xFFFF的字符,弥补了String.fromCharCode方法的不足。在作用上,正好与codePointAt方法相反。 
String. fromCodePoint( 0x20BB7)
// "?"
String. fromCodePoint( 0x78, 0x1f680, 0x79) === 'x \u D83D \u DE80y'
// true

  上面代码中,如果String.fromCodePoint方法有多个参数,则它们会被合并成一个字符串返回。

注意,fromCodePoint方法定义在String对象上,而codePointAt方法定义在字符串的实例对象上。

4.字符串的遍历器接口

5.normalize()

 

6.includes(), startsWith(), endsWith()

传统上,JavaScript 只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6 又提供了三种新方法。

1.includes():返回布尔值,表示是否找到了参数字符串。

2.startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。

3.endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。 

let s = 'Hello world!';
s. startsWith( 'Hello') // true
s. endsWith( '!') // true
s. includes( 'o') // true
这三个方法都支持第二个参数,表示开始搜索的位置。
let s = 'Hello world!';
s. startsWith( 'world', 6) // true
s. endsWith( 'Hello', 5) // true
s. includes( 'Hello', 6) // false
上面代码表示,使用第二个参数n时, endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。

 

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

'x'. repeat( 3) // "xxx"
'hello'. repeat( 2) // "hellohello"
'na'. repeat( 0) // ""
参数如果是小数,会被取整。
'na'. repeat( 2.9) // "nana"
如果repeat的参数是负数或者Infinity,会报错。 
'na'. repeat( Infinity)
// RangeError
'na'. repeat(- 1)
// RangeError

  但是,如果参数是 0 到-1 之间的小数,则等同于 0,这是因为会先进行取整运算。0 到-1 之间的小数,取整以后等于-0,repeat视同为 0。

'na'. repeat(- 0.9) // ""

参数NaN等同于 0。 

'na'. repeat( NaN) // ""

  如果repeat的参数是字符串,则会先转换成数字。

'na'. repeat( 'na') // ""
'na'. repeat( '3') // "nanana"

 

8.padStart(),padEnd()

ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
'x'. padStart( 5, 'ab') // 'ababx'
'x'. padStart( 4, 'ab') // 'abax'
'x'. padEnd( 5, 'ab') // 'xabab'
'x'. padEnd( 4, 'ab') // 'xaba'
上面代码中,padStart和padEnd一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串。
如果原字符串的长度,等于或大于指定的最小长度,则返回原字符串。 
'xxx'. padStart( 2, 'ab') // 'xxx'
'xxx'. padEnd( 2, 'ab') // 'xxx'

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

'abc'. padStart( 10, '0123456789')
// '0123456abc'
如果省略第二个参数,默认使用空格补全长度。
'x'. padStart( 4) // ' x'
'x'. padEnd( 4) // 'x '
padStart的常见用途是为数值补全指定位数。下面代码生成 10 位的数值字符串。
'1'. padStart( 10, '0') // "0000000001"
'12'. padStart( 10, '0') // "0000000012"
'123456'. padStart( 10, '0') // "0000123456"

 另一个用途是提示字符串格式。

'12'. padStart( 10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'. padStart( 10, 'YYYY-MM-DD') // "YYYY-09-12"


9.matchAll()

matchAll方法返回一个正则表达式在当前字符串的所有匹配 

10.模板字符串 
11.实例:模板编译
12.标签模板
13.String.raw()
14.模板字符串的限制

三、函数的一些新属性

1.函数参数的默认值
基本用法:
ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
function log( x, y) {
y = y || 'World';
console. log( x, y);
}

log( 'Hello') // Hello World
log( 'Hello', 'China') // Hello China
log( 'Hello', '') // Hello World
面代码检查函数log的参数y有没有赋值,如果没有,则指定默认值为World。这种写法的缺点在于,如果参数y赋值了,但是对应的布尔值为false,则该赋值不起作用。就像上面代码的最后一行,参数y等于空字符,结果被改为默认值。
为了避免这个问题,通常需要先判断一下参数y是否被赋值,如果没有,再等于默认值。
if ( typeof y === 'undefined') {
y = 'World';
}

  ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

function log( x, y = 'World') {
console. log( x, y);
}

log( 'Hello') // Hello World
log( 'Hello', 'China') // Hello China
log( 'Hello', '') // Hello
可以看到,ES6 的写法比 ES5 简洁许多,而且非常自然。下面是另一个例子。
function Point( x = 0, y = 0) {
this. x = x;
this. y = y;
}

const p = new Point();
p // { x: 0, y: 0 }
除了简洁,ES6 的写法还有两个好处:首先,阅读代码的人,可以立刻意识到哪些参数是可以省略的,不用查看函数体或文档;其次,有利于将来的代码优化,即使未来的版本在对外接口中,彻底拿掉这个参数,也不会导致以前的代码无法运行。
参数变量是默认声明的,所以不能用let或const再次声明。
function foo( x = 5) {
let x = 1; // error
const x = 2; // error
}
上面代码中,参数变量x是默认声明的,在函数体中,不能用let或const再次声明,否则会报错。
...

2.rest 参数

ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

function add(... values) {
let sum = 0;

for ( var val of values) {
sum += val;
}

return sum;
}

add( 2, 5, 3) // 10
上面代码的add函数是一个求和函数,利用 rest 参数,可以向该函数传入任意数目的参数。
下面是一个 rest 参数代替arguments变量的例子。
// arguments变量的写法
function sortNumbers() {
return Array. prototype. slice. call( arguments). sort();
}

// rest参数的写法
const sortNumbers = (... numbers) => numbers. sort();
上面代码的两种写法,比较后可以发现,rest 参数的写法更自然也更简洁。
arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.prototype.slice.call先将其转为数组。rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法都可以使用。下面是一个利用 rest 参数改写数组push方法的例子。
function push( array, ... items) {
items. forEach( function ( item) {
array. push( item);
console. log( item);
});
}

var a = [];
push( a, 1, 2, 3)
注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
// 报错
function f( a, ... b, c) {
// ...
}
函数的length属性,不包括 rest 参数。
( function ( a) { }). length // 1
( function (... a) { }). length // 0
( function ( a, ... b) { }). length // 1
3.严格模式

从 ES5 开始,函数内部可以设定为严格模式。 

function doSomething( a, b) {
'use strict';
// code
}
ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。

 pasting

// 报错
function doSomething( a, b = a) {
'use strict';
// code
}

// 报错
const doSomething = function ({ a, b }) {
'use strict';
// code
};

// 报错
const doSomething = (... a) => {
'use strict';
// code
};

const obj = {
// 报错
doSomething({ a, b }) {
'use strict';
// code
}
};

  这样规定的原因是,函数内部的严格模式,同时适用于函数体和函数参数。但是,函数执行的时候,先执行函数参数,然后再执行函数体。这样就有一个不合理的地方,只有从函数体之中,才能知道参数是否应该以严格模式执行,但是参数却应该先于函数体执行。

// 报错
function doSomething( value = 070) {
'use strict';
return value;
}
上面代码中,参数value的默认值是八进制数070,但是严格模式下不能用前缀0表示八进制,所以应该报错。但是实际上,JavaScript 引擎会先成功执行value = 070,然后进入函数体内部,发现需要用严格模式执行,这时才会报错。
虽然可以先解析函数体代码,再执行参数代码,但是这样无疑就增加了复杂性。因此,标准索性禁止了这种用法,只要参数使用了默认值、解构赋值、或者扩展运算符,就不能显式指定严格模式。
两种方法可以规避这种限制。第一种是设定全局性的严格模式,这是合法的。 
'use strict';

function doSomething( a, b = a) {
// code
}
第二种是把函数包在一个无参数的立即执行函数里面。
const doSomething = ( function () {
'use strict';
return function ( value = 42) {
return value;
};
}());

4.name 属性

函数的name属性,返回该函数的函数名。
function foo() { }
foo. name // "foo"

这个属性早就被浏览器广泛支持,但是直到 ES6,才将其写入了标准。 需要注意的是,ES6 对这个属性的行为做出了一些修改。如果将一个匿名函数赋值给一个变量,ES5 的name属性,会返回空字符串,而 ES6 的name属性会返回实际的函数名。
var f = function () { };

// ES5
f. name // ""

// ES6
f. name // "f"
5.箭头函数
6.双冒号运算符
箭头函数可以绑定this对象,大大减少了显式绑定this对象的写法(call、apply、bind)。但是,箭头函数并不适用于所有场合,所以现在有一个提案,提出了“函数绑定”(function bind)运算符,用来取代call、apply、bind调用。
函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。
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);
}
 

如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上面。


var method = obj:: obj. foo;
// 等同于
var method = :: obj. foo;

let log = :: console. log;
// 等同于
var log = console. log. bind( console);

 

如果双冒号运算符的运算结果,还是一个对象,就可以采用链式写法。 

import { map, takeWhile, forEach } from "iterlib";

getPlayers():: map( x => x. character()):: takeWhile( x => x. strength > 100):: forEach( x => console. log( x));

 

7.尾调用优化
尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。

8.函数参数的尾逗号

四、数组的一些新特性

https://blog.csdn.net/wbiokr/article/details/65939582
1.扩展运算符
2.Array.from()
3.Array.of()
4.数组实例的 copyWithin()
5.数组实例的 find() 和 findIndex()
6.数组实例的 fill()
7.数组实例的 entries(),keys() 和 values()
8.数组实例的 includes()
9.数组实例的 flat(),flatMap()
10.数组的空位

 

四、对象的一些新特性

1.对象写法:允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

变量
const foo = 'bar';
const baz = { foo };
baz // {foo: "bar"}
// 等同于
const baz = { foo: foo };
属性
function f( x, y) {
return { x, y };
}
// 等同于
function f( x, y) {
return { x: x, y: y };
}
f( 1, 2) // Object {x: 1, y: 2}

方法
const o = {
method() {
return "Hello!";
}
};

// 等同于

const o = {
method : function () {
return "Hello!";
}
};

 

属性的遍历

ES6 一共有 5 种方法可以遍历对象的属性。
(1)for...in
for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
(2)Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
首先遍历所有数值键,按照数值升序排列。
其次遍历所有字符串键,按照加入时间升序排列。
最后遍历所有 Symbol 键,按照加入时间升序排列。

 

 

 

https://www.cnblogs.com/liutie1030/p/5997446.html

 

转载于:https://www.cnblogs.com/yunshangwuyou/p/9594411.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值