es6入门
所有es6知识点都参照 阮一峰ECMAScript 6 入门
let和const
1、let和const所声明的变量只在let和const命令所在的代码块内有效
2、for循环的计数器,就很适合使用let和const命令
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
上面代码中,变量i是let声明的,当前的i只在本轮循环中有效,所有内一次循环的i其实都是一个新的变量,因为JavaScript引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算
3、不存在变量生命提升
4、暂时性死区
只要在块级作用域内存在let命令,它所声明的变量就会binding这个区域,不再受外部的影响
var a = 123;
if (true) {
a = 'abc'; // ReferenceError
let a;
}
上面代码中,存在全局变量a,但是块级作用域内let又声明了一个局部变量a,导致后者绑定这个块级作用域,所以在let声明变量前,对a赋值会报错。
如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
5、不允许重复声明
块级作用域
1、可以防止内层变量覆盖外层变量
2、可以防止用来计数的循环变量泄露为全局变量
var s = 'hello';
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
块级作用域的出现,实际上使得立即执行函数表达式不在必要了
块级作用域与函数声明
- 允许在块级作用域内声明函数。
- 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
- 同时,函数声明还会提升到所在的块级作用域的头部。
- 要避免在块级作用域内声明函数。如果有需要也应该写成函数表达式,而不是函数声明语句。
// 函数声明语句
{
let a = 'secret';
function f() {
return a;
}
}
// 函数表达式
{
let a = 'secret';
let f = function () {
return a;
};
}
const声明一个只读的常量。一旦声明,常量的值就不能改变。
变量的解构赋值
变量的解构赋值用途有很多
1、交换变量的值
let a = 1;
let b = 3;
[a, b] = [b, a]
上面的代码交换a,b的值
2、从函数中返回多个值
函数只能返回一个值,如果要返回多个值,只能将他们放在数组或对象中返回。
//返回一个数组
function a(){
return [1,2,3];
}
let [l, m, n] = a();
//返回一个对象
function b(){
return {
foo: 1,
bar: 2
}
}
let {foo, bar} = b();
3、函数参数的定义
function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
4、提取json数据
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
5、函数参数的默认值
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};
指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || 'default foo';这样的语句。
6、遍历map结构
const 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
7、输入模块的指定方法
const { SourceMapConsumer, SourceNode } = require("source-map");
字符串的扩展
1、字符的 Unicode 表示法
先来了解一下Unicode是什么
- Unicode源于一个想法:将全世界所有的字符包含在一个集合里,计算机只要支持这一个字符集,就能显示所有的字符,再也不会有乱码
它从0开始,为每个符号指定一个编号,这叫做"码点"(code point)。比如,码点0的符号就是null(表示所有二进制位都是0)。
2、字符串的遍历接口
for (let codePoint of 'foo') {
console.log(codePoint)
}
// "f"
// "o"
// "o"
es5对字符串对象提供了charAt方法,返回字符串给定位置的字符。
'abc'.charAt(0) // "a"
es6提供了at()
'abc'.at(0) // "a"
3、includes(),startsWith(), endsWith()
es5中indexOf方法可以用来确定一个字符是否包含在另一个字符串中。es6又提供了三种新方法
- includes(): 返回布尔值,表示是否找到了参数字符串
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- 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个位置直到字符串结束。
4、repeat()
reat方法返回一个新字符串,表示将原字符串重复n次
参数如果是小数会被取整
如果是负数或者infinity,会报错
但是,如果参数是 0 到-1 之间的小数,则等同于 0,这是因为会先进行取整运算。0 到-1 之间的小数,取整以后等于-0,repeat视同为 0。
参数NaN等同于 0。
如果repeat的参数是字符串,则会先转换成数字。
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
5、padStart(),padEnd()
ES2017 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。padStart和padEnd一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串。如果原字符串的长度,等于或大于指定的最小长度,则返回原字符串。如果用来补全的字符串与原字符串,两者的长度之和超过了指定的最小长度,则会截去超出位数的补全字符串。如果省略第二个参数,默认使用空格补全长度。padStart的常见用途是为数值补全指定位数。下面代码生成 10 位的数值字符串。
'123456'.padStart(10, '0') // "0000123456"
另一个用途是提示字符串格式。
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
6、字符串模板
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
// 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入变量 模板字符串中嵌入变量,需要将变量名写在${}之中。
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
上面代码中的模板字符串,都是用反引号表示。如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
let greeting = `\`Yo\` World!`;
大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。还能调用函数。
let x = 1;
let y = 2;
`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"
let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
// foo Hello World bar
模板字符串的变量之中,又嵌入了另一个模板字符串
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));
// <table>
//
// <tr><td><Jane></td></tr>
// <tr><td>Bond</td></tr>
//
// <tr><td>Lars</td></tr>
// <tr><td><Croft></td></tr>
//
// </table>
如果需要引用模板字符串本身,在需要时执行,可以像下面这样写。
// 写法一
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!"
模板编译待了解。。。。。。。。
7、标签模板
模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。
alert`123`
// 等同于
alert(123)
标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
但是,如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
但是,如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
上面代码中,模板字符串前面有一个标识名tag,它是一个函数。整个表达式的返回值,就是tag函数处理模板字符串后的返回值。
“标签模板”的一个重要应用,就是过滤 HTML 字符串,防止用户输入恶意内容。
标签模板的另一个应用,就是多语言转换(国际化处理)。
(不太理解)
模板处理函数的第一个参数(模板字符串数组),还有一个raw属性。
console.log`123`
// ["123", raw: Array[1]]
上面代码中,console.log接受的参数,实际上是一个数组。该数组有一个raw属性,保存的是转义后的原字符串。
tag`First line\nSecond line`
function tag(strings) {
console.log(strings.raw[0]);
// strings.raw[0] 为 "First line\\nSecond line"
// 打印输出 "First line\nSecond line"
}
上面代码中,tag函数的第一个参数strings,有一个raw属性,也指向一个数组。该数组的成员与strings数组完全一致。比如,strings数组是["First line\nSecond line"],那么strings.raw数组就是["First line\nSecond line"]。两者唯一的区别,就是字符串里面的斜杠都被转义了。比如,strings.raw 数组会将\n视为\和n两个字符,而不是换行符。这是为了方便取得转义之前的原始模板而设计的。
未完。。。。。。。。。。。
待了解正则表达式