# 一、环境
对于不支持ES6的老版本浏览器,需要转译为ES5,可用webpack、babel等 此处使用babel转译ES6为ES5
# 1. 建立项目并配置环境
mkdir myProject // 新建项目
cd myProject // 进入项目
cnpm init -y // 快速初始化
// cnpm install -g babel-cli // 全局安装babel转译
cnpm i -D @babel/cli @babel/core @babel/preset-env // 使用最新的 babel 7 以及最新 preset-env 环境
touch .babelrc // 新建 .babelrc 文件,或 touch babel.config.js
vim .babelrc // 编辑新建的 .babelrc 文件
2
3
4
5
6
7
// .babelrc
{
"presets":[
"@babel/preset-env",
"@babel/preset-flow",
"@babel/preset-react",
["@babel/preset-typescript", {
isTSX: true,
allExtensions: true,
// jsxPragma:
}]
],
"plugins":[]
}
// babel.config.js
const presets = [
[
"@babel/preset-env"
// {
// targets: {
// edge: "17",
// firefox: "60",
// chrome: "67",
// safari: "11.1",
// }
// // useBuiltIns: "usage",
// },
],
];
module.exports = { presets };
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 2. 开始编写
mkdir src // 创建 src 目录,作为 开发目录
mkdir dist // 创建 dist 目录,作为编译目录
cd src // 进入 src 目录
touch index.js // 创建 index.js 文件
vim index.js // 开始编写含有 es6 的 js 代码
2
3
4
5
6
# 3. 编译
- 命令行方式
// -o => --out-file
// -d => --out-dir
// babel src/index.js -o dist/index.js // 将src目录下的 index.js 转译到dist目录下
// babel src/index.js -o dist/index.js -w // 开启 babel 监听,可实时转译编写的文件
npx babel src/index.js -o dist/index.js // npx babel 相当于执行 ./node_modules/.bin/babel
npx babel src/index.js -o dist/index.js -w // 开启监听编译
npx babel src -d dist -w // 开启监听编译,将src目录整个编译到dist目录
2
3
4
5
6
7
8
- 脚本方式(推荐):
// package.json
"scripts": {
"dev": "babel src/index.js -o dist/index.js -w",
"build": "babel src/index.js -o dist/index.js"
},
2
3
4
5
6
之后执行 npm run dev/build
即可
# 二、变量声明: let
和 const
# 1. var
(原有)
将会声明一个全局变量,全局可用,使用后依然存在,不会被销毁
# 2. let
(新增)
# 建议不再使用var
,全部用let
代替var
let
不允许在相同作用域内,重复声明同一个变量。不存在变量提升,var声明的变量会被提前,值为undefined,let不会,在let前使用直接报错
// 编译前直接运行 console.log(a) // ReferenceError: a is not defined let a = 1
1
2
3
4// 编译后运行 "use strict"; console.log(a); // undefined var a = 1;
1
2
3
4
5
6原有的
var
只在函数中区分作用域,在大括号{}
中无法建立块级作用域,let
声明的变量,只在let
命令所在的代码块{}
内有效。
ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。// 编译前直接运行 { var a = 1 let b = 1 } console.log(a) console.log(b) // ReferenceError: b is not defined
1
2
3
4
5
6
7
8// 编译后运行 "use strict"; { var a = 1; var _b = 1; // 会自动将 let 声明的变量和代码块外使用的变量命名区分 } console.log(a); console.log(b); // ReferenceError: b is not defined
1
2
3
4
5
6
7
8
9
10
11
# 块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了
```js
// IIFE 写法
(function () {
var tmp = ...;
...
}());
// 块级作用域写法
{
let tmp = ...;
...
}
```
# 暂时性死区(temporal dead zone,简称 TDZ)
只要块级作用域内存在 let
或 const
命令, 它所声明的变量就“绑定”(binding)这个区域,不再受外部同名全局变量的影响。不管在 let
前面还是后面。且在let
前使用这个变量会直接报错
var a = 123
if (true) {
a = 'abc' // ReferenceError: a is not defined,无法访问同名全局变量且报错
let a
}
2
3
4
5
6
// 较为隐蔽的死区
function bar(x = y, y = 2) { // (x = 2, y = x) 则不会报错
return [x, y]
}
bar() // ReferenceError: y is not defined, x = y 时 变量 y 还未被声明
2
3
4
5
6
// 不报错
var x = x // undefined,声明提前
// 报错
let y = y // ReferenceError: y is not defined
2
3
4
5
# 3. const (新增)
- 声明一个只读的常量。声明之后不可被修改,否则报错。意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
// const a; // SyntaxError: Missing initializer in const declaration
const PI = 3.14;
PI = 3.1415; //报错
2
3
4
const
实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const
只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
# ES6 声明变量的六种方法
ES5 只有两种声明变量的方法:var
命令和 function
命令。
ES6 除了添加 let
和 const
命令,后面章节还会提到,另外两种声明变量的方法: import
命令和 class
命令。所以,ES6 一共有 6 种声明变量的方法。
# 顶层对象的属性
ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1
let b = 1;
window.b // undefined
2
3
4
5
6
7
# globalThis 对象
JavaScript 语言存在一个顶层对象,它提供全局环境(即全局作用域),所有代码都是在这个环境中运行。但是,顶层对象在各种实现里面是不统一的。
浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。 Node 里面,顶层对象是global,但其他环境都不支持。 同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性。
全局环境中,this会返回顶层对象。但是,Node 模块和 ES6 模块中,this返回的是当前模块。 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。 不管是严格模式,还是普通模式,new Function('return this')(),总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval、new Function这些方法都可能无法使用。 综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。
// 方法一
(typeof window !== 'undefined'
? window
: (typeof process === 'object' &&
typeof require === 'function' &&
typeof global === 'object')
? global
: this);
// 方法二
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ES2020 在语言标准的层面,引入globalThis作为顶层对象。也就是说,任何环境下,globalThis都是存在的,都可以从它拿到顶层对象,指向全局环境下的this。
垫片库global-this模拟了这个提案,可以在所有环境拿到globalThis。
# 三、变量的解构赋值
- 数组的解构赋值
- 对象的解构赋值
- 字符串的解构赋值
- 数值和布尔值的解构赋值
- 函数参数的解构赋值
- 圆括号问题
- 用途
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
# 1. 数组的解构赋值
// 不用解构的写法:
let a = 1
let b = 2
let c = 3
// 解构的写法:
let [a, b, c] = [1, 2, 3]
2
3
4
5
6
7
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 [x, y] = [1, 2, 3];
x // 1
y // 2
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
// 对于 Set 结构,也可以使用数组的解构赋值。
let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值
// Generator 函数实现的斐波拉契数列,
function* fibs() {
let a = 0
let b = 1
while (true) {
yield a; // 分号不能少
[a, b] = [b, a + b]
}
}
// Generator 函数具有 Iterator 接口。解构赋值会依次从这个接口获取值。
let [first, second, third, fourth, fifth, sixth] = fibs()
console.log(first, second, third, fourth, fifth, sixth) // 0 1 1 2 3 5
2
3
4
5
6
7
8
9
10
11
12
13
14
# 数组解构的默认值
变量可设置默认值,若数组中没有足够的值结构出来赋值,则使用默认值,无默认值则为undefined
let [a, [b, c], d, e, f = 'default'] = [1, [2, 3], 4]
console.log(a, b, c, d, e, f) // 1 2 3 4 undefined "default"
2
# 默认值遇到 undefined
和 null
的区别
ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。
let [a, b = 20] = [10, undefined]
console.log(a, b) //10 20,undefined表示无值,则 b 会取默认值。
let [a, b = 20] = [10, null] // null不严格等于undefined
console.log(a, b) //10 null, null表示值为null, 则 b 不用默认值而用null
2
3
4
5
# 默认值为表达式
如果默认值为表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
function f() {
console.log('函数执行')
}
let [x = f()] = [1] // x 能取到值,所以函数f根本不会执行。
// 以上代码等价于:
let x;
if ([1][0] === undefined) {
x = f();
} else {
x = [1][0];
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 默认值可以引用解构赋值的其他变量,但该变量必须已经声明
let [x = 1, y = x] = []; // x=1; y=1
let [x = 1, y = x] = [2]; // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError: y is not defined
2
3
4
5
# 2. 对象的解构赋值
# 对象不按顺序而是按key结构,key相同才能成功结构并赋值
let {z, y, x} = {x: 10, y: 20}
console.log(x, y); // 10 20 undefined
2
# 对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量
// 例一
let { random, round, max } = Math
console.log(random()) // 0.14743980691009595
console.log(round(3.1415)) // 3
console.log(max(1, 4, 7, 8, 5, 2)) // 8
// 例二
const { log } = console
log('hello') // hello
2
3
4
5
6
7
8
9
# 变量名与属性名不一致
let obj = { first: 'hello', last: 'world' }
let { first: f, last: l } = obj // 将对象中取出的 first, last 命名为变量 f, l
console.log(f, l) // hello world
2
3
4
以上例子说明。对象的解构赋值是下面形式的简写:
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
# 嵌套解构
// 例一:
let obj = {
p: [
'Hello',
{ y: 'World' }
]
}
let { p: [x, { y }] } = obj // 此写法 不能访问 p,若要访问须单独取出
let { p, p: [x, { y }] } = obj // 此写法可以访问 p
console.log(x, y) // Hello World
// 例二:
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
let { loc, loc: { start }, loc: { start: { line }} } = node;
line // 1
loc // Object {start: Object}
start // Object {line: 1, column: 5}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 嵌套赋值
// 将 obj2 中的: a 放入 obj,b 放入 arr
let obj2 = {
a: 1,
b: '1'
}
let obj = {}
let arr = []
/*
// 原始写法:
obj.a = obj2.a
arr[0] = obj2.b
console.log(obj) // {a: 1}
console.log(arr) // ["1"]
*/
// 解构写法:
;({a: obj.a, b: arr[0]} = obj2) // 圆括号之前须保证前一句代码结束,以防万一加分号结束前一句。
console.log(obj) // {a: 1}
console.log(arr) // ["1"]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 对象的解构赋值可以取到继承的属性
const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1, obj2);
const { foo } = obj1;
foo // "bar"
2
3
4
5
6
7
对象obj1的原型对象是obj2。foo属性不是obj1自身的属性,而是继承自obj2的属性,解构赋值可以取到这个属性。
# 对象解构的默认值
# 默认值生效的条件是,对象的属性值严格等于(===)undefined
let {x = 3} = {};
x // 3
let {x, y = 5} = {x: 1};
x // 1
y // 5
let {x: y = 3} = {};
y // 3
let {x: y = 3} = {x: 5};
y // 5
let { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"
let {x = 3} = {x: undefined};
x // 3
let {x = 3} = {x: null};
x // null
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 将一个已经声明的变量用于解构赋值
如果在解构之前就定义了变量,再解构会报错。也就是解构时前面没有 let
let a
{a} = {a: 10} // 报错 Declaration or statement expected.
2
因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
要解决报错,只需在解构的语句外边加一个圆括号即可。
let a;
({a} = {a: 10});
console.log(a);
2
3
# 将数组像对象一样解构
let arr = [1, 2, 3]
let {0 : first, [arr.length - 1] : last} = arr // 方括号这种写法,属于“属性名表达式”
console.log(first, last) // 1 3
2
3
4
# 3. 字符串的解构赋值
字符串也可以解构,因为,此时字符串会被转换成一个类数组对象。
let [a, b, c, d, e] = 'hello'
console.log(a, b, c, d, e) // h e l l o
2
类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
let {length : len} = 'hello';
len // 5
2
# 4. 数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
let {toString: s} = 123
s === Number.prototype.toString // true
let {toString: s} = true
s === Boolean.prototype.toString // true
2
3
4
5
上面代码中,数值和布尔值的包装对象都有toString属性,因此变量s都能取到值。
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
let { prop: x } = undefined // TypeError
let { prop: y } = null // TypeError
2
# 5. 函数参数的解构赋值
function add([x, y]){
return x + y
}
add([1, 2]) // 3
function add2({x, y}){
return x + y
}
add2({x: 1, y: 2}) // 3
[[1, 2], [3, 4]].map(([a, b]) => a + b) // [ 3, 7 ]
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用默认值的参数解构
function move({x = 0, y = 0} = {}) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
// 以下写法和上述结果不同:
function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 6. 圆括号问题
解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。
由此带来的问题是,如果模式中出现圆括号怎么处理。ES6 的规则是,只要有可能导致解构的歧义,就不得使用圆括号。
但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置圆括号。
# 不能使用圆括号的情况
# (1)变量声明语句
// 全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
2
3
4
5
6
7
8
9
上面 6 个语句都会报错,因为它们都是变量声明语句,模式不能使用圆括号。
# (2)函数参数
函数参数也属于变量声明,因此不能带有圆括号。
// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }
2
3
4
# (3)赋值语句的模式
// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];
2
3
上面代码将整个模式放在圆括号之中,导致报错。
// 报错
[({ p: a }), { x: c }] = [{}, {}];
2
上面代码将一部分模式放在圆括号之中,导致报错。
# 可以使用圆括号的情况
可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。
[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确
2
3
上面三行语句都可以正确执行,因为首先它们都是赋值语句,而不是声明语句;其次它们的圆括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟圆括号无关;第二行语句中,模式是p,而不是d;第三行语句与第一行语句的性质一致。
# 四、字符串的扩展
- 字符的 Unicode 表示法
- 字符串的遍历器接口
- 直接输入 U+2028 和 U+2029
- JSON.stringify() 的改造
- 模板字符串
- 实例:模板编译
- 标签模板
- 模板字符串的限制
# 1. 字符的 Unicode 表示法
允许采用 \uxxxx
形式表示一个字符,其中xxxx
表示字符的 Unicode 码点。
console.log("\u0061") // a
这种表示法只限于码点在\u0000~\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。
console.log("\uD842\uDFB7") // "𠮷"
console.log("\u20BB7") // "₻7"
2
3
在 \u
后面跟上超过 0xFFFF
的数值(比如 \u20BB7
),JavaScript 会理解成\u20BB
(₻) + 7
。所以打印出 ₻7
ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。
"\u{20BB7}" // "𠮷"
"\u{41}\u{42}\u{43}" // "ABC"
let hello = 123;
hell\u{6F} // 123
'\u{1F680}' === '\uD83D\uDE80' // 大括号表示法与四字节的 UTF-16 编码是等价的。
// true
2
3
4
5
6
7
8
9
10
# 2. 字符串的遍历器接口
ES6 为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历。
for (let codePoint of 'foo') {
console.log(codePoint) // f o o
}
2
3
除了遍历字符串,这个遍历器最大的优点是可以识别大于0xFFFF的码点,传统的for循环无法识别这样的码点。
let text = String.fromCodePoint(0x20BB7);
console.log(text) // 𠮷
console.log(text.length) // 2
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
for (let i of text) {
console.log(i);
}
// "𠮷"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上面代码中,字符串text只有一个字符,但是for循环会认为它包含两个字符(都不可打印),而for...of循环会正确识别出这一个字符。
# 3. 字符串转义字符
JavaScript 字符串允许直接输入字符,以及输入字符的转义形式。
'中' === '\u4e2d' // true
但 JavaScript 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式。
- U+005C:反斜杠(reverse solidus)
- U+000D:回车(carriage return)
- U+2028:行分隔符(line separator)
- U+2029:段分隔符(paragraph separator)
- U+000A:换行符(line feed)
// 反斜杠
console.log('hello\world') // helloworld,反斜杠被忽略
console.log('hello\\world') // hello\world
console.log('hello\u005cworld') // hello\world
// 换行
console.log('hello\nworld')
// hello
// world
console.log('hello\u000aworld')
// hello
// world
2
3
4
5
6
7
8
9
10
11
12
13
# 4. 模板字符串
- 用反引号(`)标识。可当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。将变量名写在
${}
之中,大括号内部可以放入任意的 JavaScript 表达式,如计算,访问对象属性,调用函数等 - 如果大括号中的值不是字符串,将按照一般的规则转为字符串。比如,大括号中是一个对象,将默认调用对象的toString方法。 如果模板字符串中的变量没有声明,将报错。大括号内部是一个字符串,将会原样输出。
- 使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
- 在模板字符串中需要使用反引号,则前面要用反斜杠转义。 \`
- 模板字符串还能嵌套。
// 普通字符串
console.log(`In JavaScript '\n' is a line-feed.`)
// 多行字符串
console.log(`In JavaScript this is
not legal.`)
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入变量
let name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 5. 字符串的新增方法
- String.fromCodePoint()
- String.raw()
- 实例方法:codePointAt()
- 实例方法:normalize()
- 实例方法:includes(), startsWith(), endsWith()
- 实例方法:repeat()
- 实例方法:padStart(),padEnd()
- 实例方法:trimStart(),trimEnd()
- 实例方法:matchAll()
# String.fromCodePoint()
用于替换 String.fromCharCode()
的方法,因为需要识别码点大于0xFFFF的字符。
# String.raw()
可以作为处理模板字符串的基本方法,它会将所有变量替换,而且对斜杠进行转义
String.raw`Hi\n${2+3}!`
作为正常的函数使用
String.raw({ raw: 'test' }, 0, 1, 2);
// 't0e1s2t'
// 等同于
String.raw({ raw: ['t','e','s','t'] }, 0, 1, 2);
2
3
4
5
6
# string.prototype.codePointAt()
能够正确处理 4 个字节储存的字符,返回一个字符的码点。
let s = '𠮷a';
console.log(s.length) // 3 ,长度本应为 2
s.codePointAt(0).toString(16) // "20bb7"
s.codePointAt(2).toString(16) // "61" 第二个字符下标本应传入1,此方法实际需要传入2。
2
3
4
# 实例方法:includes(str, i), startsWith(str, i), endsWith(str, i)
传统用 indexOf
方法来判断一个字符串是否包含在另一个字符串中。新增三个方法。
includes()
是否包含 , startsWith()
是否在开头, endsWith()
是否在结尾
# repeat()
repeat方法返回一个新字符串,表示将原字符串重复n次。n 若为小数,小数部分直接忽略。n 不能为负数或Infinity。n 为 NaN 等同于 0.
# 实例方法:padStart(),padEnd()
字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
'123456'.padStart(10, '0') // "0000123456"
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
2
3
第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。
原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。
如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串。
如果省略第二个参数,默认使用空格补全长度。
# 实例方法:trimStart(),trimEnd()
trimStart()消除字符串头部的空格,trimEnd()消除尾部的空格。 trimLeft()是trimStart()的别名,trimRight()是trimEnd()的别名。
# matchAll()
返回一个正则表达式在当前字符串的所有匹配