對阮一峯老師-ECMAScript 6 入門的學習筆記
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
// let 聲明的變量,只在命令所在的代碼塊內有效。
{
{
let a = 10;
var b = 1;
}
//a // ReferenceError: a is not defined.
//b // 1
// let不像var那樣會發生“變量提升”現象。所以,變量一定要在聲明後使用,否則報錯。
{
console.log(foo); // 輸出undefined
//console.log(bar); // 報錯ReferenceError
var foo = 2;
let bar = 2;
}
// const 作用域與let相似,一旦聲明不能重新賦值
{
const PI = 3.1415;
PI
}
}
{
{
// es6中變量可以這樣聲明,這種方式稱爲解構(Destructuring)。
let [c, d, e] = [1, 2, 3];
console.log(c+","+d)
}
{
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 // []
}
{
//let [foo] = 1;
//let [foo] = false;
//let [foo] = NaN;
//let [foo] = undefined;
//let [foo] = null;
//let [foo] = {};
}
{
// 允許默認值
var [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
// [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
console.log(x + "," + y);
}
{
// 可以解構對象
var { bar, foo } = { foo: "aaa", sec: "bbb", bar: "bbb" };
foo // "aaa"
bar // "bbb"
var { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
}
{
let { log, sin, cos } = Math;
}
{
// 函數參數也可以解構
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
}
/* 解構實用功能 */
{
// 變換變量的值
let [x, y] = [1, 2];
[x, y] = [y, x];
console.log(x + "," + y);
}
{
// 函數返回多個值
// 返回一個數組
/*
function example() {
return [1, 2, 3];
}
var [a, b, c] = example();
*/
// 返回一個對象
function example() {
return {
foo: 1,
bar: 2
};
}
var { foo, bar } = example();
}
{
// 提取JSON數據
var jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
}
{
// 遍歷map結構
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
}
{
// 加載模塊時,往往需要指定輸入那些方法。解構賦值使得輸入語句非常清晰。
// const { SourceMapConsumer, SourceNode } = require("source-map");
}
}
/* 字符串的擴展 */
{
// 如果直接在\u後面跟上超過0xFFFF的數值(比如\u20BB7),JavaScript會理解成\u20BB+7。由於\u20BB是一個不可打印字符
// ES6 對這一點做出了改進,只要將碼點放入大括號,就能正確解讀該字符。
{
"\u{20BB7}"
// "��"
"\u{41}\u{42}\u{43}"
// "ABC"
let hello = 123;
hell\u{6F} // 123
'\u{1F680}' === '\uD83D\uDE80'
// true
}
// codePointAt
{
var s = '��a';
s.codePointAt(0) // 134071
s.codePointAt(1) // 57271
s.codePointAt(2) // 97
}
{
String.fromCodePoint(0x20BB7)
// "��"
String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y'
// true
}
// 除了遍歷字符串,這個遍歷器最大的優點是可以識別大於0xFFFF的碼點,傳統的for循環無法識別這樣的碼點。
{
var text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
for (let i of text) {
console.log(i);
}
// "��"
}
// ES5對字符串對象提供charAt方法,返回字符串給定位置的字符。該方法不能識別碼點大於0xFFFF的字符。
{
// 'abc'.at(0) // "a"
// '��'.at(0) // "��"
}
{
var s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
console.log(s.startsWith('Hello'));
console.log(s.endsWith('!'));
console.log(s.includes('o'));
}
// repeat方法返回一個新字符串,表示將原字符串重複n次。
{
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) //
console.log('x'.repeat(3));
console.log('x'.repeat(-0.5)); // "" (-1,0]
//'na'.repeat(Infinity)
// RangeError
// 'na'.repeat(-1)
// RangeError
}
// ES7推出了字符串補全長度的功能。
// 如果某個字符串不夠指定長度,會在頭部或尾部補全。padStart用於頭部補全,padEnd用於尾部補全。
{
// 'x'.padStart(5, 'ab') // 'ababx'
// 'x'.padStart(4, 'ab') // 'abax'
// 'x'.padEnd(5, 'ab') // 'xabab'
// 'x'.padEnd(4, 'ab') // 'xaba
}
{
// 普通字符串
`In JavaScr
ipt '\n'is a line-feed.`
console.log(`In JavaScript this is
not legal.`);
// 多行字符串
//`In JavaScript this is
// not legal.`
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入變量
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
console.log(`Hello ${name}, how are you ${time}?`);
}
{
var x = 1;
var y = 2;
`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"
console.log(`${x} + ${y} = ${x + y}`);
`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"
console.log(`${x} + ${y * 2} = ${x + y * 2}`);
var obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// 3
}
// 模板之中還可以調用函數
{
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
// foo Hello World bar
}
{
// 寫法一
let str = 'return ' + '`Hello ${name}!`';
let func = new Function('name', str);
func('Jack') // "Hello Jack!"
// 寫法二
// let str = '(name) => `Hello ${name}!`';
// let func = eval.call(null, str);
// func('Jack') // "Hello Jack!"
}
// 模板嵌套
{
const tmpl = addrs => `
<table>
${addrs.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}
</table>
`;
const data = [
{ first: '<Jane>', last: 'Bond' },
{ first: 'Lars', last: '<Croft>' },
];
console.log(tmpl(data));
}
{
var template = `
<ul>
<% for(var i=0; i < data.supplies.length; i++) { %>
<li><%= data.supplies[i] %></li>
<% } %>
</ul>
`;
/*
echo('<ul>');
for(var i=0; i < data.supplies.length; i++) {
echo('<li>');
echo(data.supplies[i]);
echo('</li>');
};
echo('</ul>');
*/
var evalExpr = /<%=(.+?)%>/g;
var expr = /<%([\s\S]+?)%>/g;
template = template
.replace(evalExpr, '`); \n echo( $1 ); \n echo(`')
.replace(expr, '`); \n $1 \n echo(`');
template = 'echo(`' + template + '`);';
console.log(template);
/*
// 封裝成一個方法返回
var script =
`(function parse(data){
var output = "";
function echo(html){
output += html;
}
${ template }
return output;
})`;
return script;*/
}
// “標籤”指的就是函數,緊跟在後面的模板字符串就是它的參數。
{
// alert`123`
// 等同於
// alert(123);
}
// 如果模板字符裏面有變量,就不是簡單的調用了,而是會將模板字符串先處理成多個參數,再調用函數。
{
var a = 5;
var b = 10;
//tag`Hello ${ a + b } world ${ a * b }`;
// 等同於
//tag(['Hello ', ' world ', ''], 15, 50);
/*
* tag函數的第一個參數是一個數組,
* 該數組的成員是模板字符串中那些沒有變量替換的部分,
* 也就是說,變量替換隻發生在數組的第一個成員與第二個成員之間、
* 第二個成員與第三個成員之間,以此類推。
*/
function tag(stringArr, value1, value2){
// ...
}
// 等同於
function tag(stringArr, ...values){
// ...
}
}
{
var message =
SaferHTML`<p>& has sent you a message.</p>`;
function SaferHTML(templateData) {
var s = templateData[0];
for (var i = 1; i < arguments.length; i++) {
var arg = String(arguments[i]);
// Escape special characters in the substitution.
s += arg.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
// Don't escape special characters in the template.
s += templateData[i];
}
return s;
}
console.log(message);
}
// String.raw方法可以作爲處理模板字符串的基本方法,
// 它會將所有變量替換,而且對斜槓進行轉義,方便下一步作爲字符串來使用。
{
String.raw`Hi\n${2+3}!`;
// "Hi\\n5!"
String.raw`Hi\u000A!`;
// 'Hi\\u000A!'
}
}
{
//返回的正則表達式會忽略原有的正則表達式的修飾符,只使用新指定的修飾符。
{
var regex = new RegExp(/xyz/, 'i');
}
}
// Array.from方法用於將兩類對象轉爲真正的數組:
// 類似數組的對象(array-like object)和可遍歷(iterable)的對象
{
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']
}
// 對於還沒有部署該方法的瀏覽器,可以用Array.prototype.slice方法替代。
{
const toArray = (() =>
Array.from ? Array.from : obj => [].slice.call(obj)
)();
}
{
let spans = document.querySelectorAll('.name');
// map()
let names1 = Array.prototype.map.call(spans, s => s.textContent);
// Array.from()
let names2 = Array.from(spans, s => s.textContent)
console.log(names1)
}
// 將數組中布爾值爲false的成員轉爲0。
{
Array.from([1, , 2, , 3], (n) => n || 0)
}
// Array.of方法用於將一組值,轉換爲數組
{
Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]
}
/**
target(必需):從該位置開始替換數據。
start(可選):從該位置開始讀取數據,默認爲0。如果爲負值,表示倒數。
end(可選):到該位置前停止讀取數據,默認等於數組長度。如果爲負值,表示倒數。
*/
{
// 將從3號位直到數組結束的成員(4和5),複製到從0號位開始的位置,結果覆蓋了原來的1和2
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
}
// 數組實例的find()和findIndex()
{
[1, 4, -5, 10].find((n) => n < 0)
// -5
/*[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10*/
/*// 返回第一個符合條件的數組成員的位置,如果所有成員都不符合條件,則返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2*/
}
// 數組實例的fill()
{
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
// fill方法還可以接受第二個和第三個參數,用於指定填充的起始位置和結束位置
//['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
}
{
for (let index of ['a', 'b'].keys()) {
console.log(index);
};
// 0
// 1
/*for (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"
}
// Array.prototype.includes方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的includes方法類似
{
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
[1, 2, NaN].includes(NaN); // true
console.log([1, 2, 3].includes(6))
}
{
// forEach方法
[,'a'].forEach((x,i) => console.log(i)); // 1
// filter方法
['a',,'b'].filter(x => true); // ['a','b']
// every方法
[,'a'].every(x => x==='a'); // true
// some方法
[,'a'].some(x => x !== 'a'); // false
// map方法
[,'a'].map(x => 1); // [,1]
// join方法
[,'a',undefined,null].join('#'); // "#a##"
// toString方法
[,'a',undefined,null].toString(); // ",a,,"
//ES6 明確將空位轉爲undefined。
Array.from(['a',,'b']);
[ "a", undefined, "b" ];
}
// ES6 參數可以使用默認值
{
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
}
{
function foo({x, y = 5}) {
console.log(x, y);
}
foo({}) // undefined, 5
foo({x: 1}) // 1, 5
foo({x: 1, y: 2}) // 1, 2
//foo() // TypeError: Cannot read property 'x' of undefined
}
//雙重默認值
{
function fetch(url, { method = 'GET' } = {}) {
console.log(method);
}
fetch('http://example.com')
// "GET"
function m1({x = 0, y = 0} = {}) {
return [x, y];
}
m1({x: 3}) // [3, 0]
}
// 作用域
{
let x = 1;
function f(y = x) {
let x = 2;
console.log(y);
}
f() // 1
var z = 1;
function f(z, y = z) {
console.log(y);
}
f(2) // 2
}
// 省略參數,拋出錯誤
{
function throwIfMissing() {
throw new Error('Missing parameter');
}
function foo(mustBeProvided = throwIfMissing()) {
return mustBeProvided;
}
//foo()
// Error: Missing parameter
}
// ES6引入rest參數(形式爲“...變量名”),用於獲取函數的多餘參數,這樣就不需要使用arguments對象了
{
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
// arguments變量的寫法
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort();
}
// rest參數的寫法
const sortNumbers2 = (...numbers) => numbers.sort();
console.log(sortNumbers([2,3,1]))
console.log(sortNumbers2([2,3,1]))
}
// 擴展運算符(spread)是三個點(...)。它好比rest參數的逆運算,將一個數組轉爲用逗號分隔的參數序列。
{
console.log(...[1, 2, 3]);
// 1 2 3
console.log(1, ...[2, 3, 4], 5);
// 1 2 3 4 5
[...document.querySelectorAll('div')];
// [<div>, <div>, <div>]
function push(array, ...items) {
array.push(...items);
}
function add(x, y) {
return x + y;
}
var numbers = [4, 38];
add(...numbers) // 42
}
// 由於擴展運算符可以展開數組,所以不再需要apply方法,將數組轉爲函數的參數了。
{
// ES5的寫法
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES6的寫法
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f(...args);
}
// 簡化求出一個數組最大元素的寫法。
{
// ES5的寫法
Math.max.apply(null, [14, 3, 77])
// ES6的寫法
Math.max(...[14, 3, 77])
// 等同於
Math.max(14, 3, 77);
}
{
// ES5的寫法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
// ES6的寫法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1.push(...arr2);
}
// 合併數組
{
let more = [5];
// ES5
[1, 2].concat(more);
// ES6
[1, 2, ...more];
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
// ES5的合併數組
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6的合併數組
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
}
{
const [first, ...rest] = [1, 2, 3, 4, 5];
first; // 1
rest; // [2, 3, 4, 5]
const [first2, ...rest2] = [];
first2; // undefined
rest2; // []:
const [first3, ...rest3] = ["foo"];
first3; // "foo"
rest3; // []
}
// 如果將擴展運算符用於數組賦值,只能放在參數的最後一位,否則會報錯。
{
//const [...butLast, last] = [1, 2, 3, 4, 5];
// 報錯
//const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 報錯
}
{
[...'hello']
// [ "h", "e", "l", "l", "o" ]
var nodeList = document.querySelectorAll('div');
var array = [...nodeList];
}
//只要函數參數使用了默認值、解構賦值、或者擴展運算符,那麼函數內部就不能顯式設定爲嚴格模式,否則會報錯。
{
// 報錯
/*function doSomething(a, b = a) {
'use strict';
// code
}*/
}
</script>
</head>
<body>
<span class="name">註釋的代碼表示會報錯,或者當前瀏覽器不支持</span>
</body>
</html>