你的浏览器不支持canvas

深入浅出:了解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\uD83D\uDE80y'
// 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

 

posted @ 2018-09-06 20:01  云上丶无忧  阅读(3588)  评论(0编辑  收藏  举报

来场流星雨,吧