您可以通过左右滑屏查看更多笔记内容。。
<1>解构:ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构;
模式匹配:只要等号两边的模式相同,左边的变量就会被赋予对应的值
如果解构不成功,变量的值就等于undefined
。
数组的元素是按次序排列的,变量的取值由它的位置决定;
案例:
function* fibs() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
let [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
<2>默认值
ES6 内部使用严格相等运算符(===
),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined
,默认值才会生效;
案例:
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null null不严格等于undefined,所以默认值无效
如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值;
默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
对象的解构:对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
如果解构失败,变量的值等于undefined
;
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
------------------------------------------------
let {foo} = {bar: 'baz'};
foo // undefined
如果变量名与属性名不一致时:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
//foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。
Object.setPrototypeOf() 方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null
。
Object.setPrototypeOf(obj, prototype)
* obj --要设置其原型的对象。.
* prototype --该对象的新原型(一个对象 或 null).
对象的解构赋值可以取到继承的属性:
案例:
const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1, obj2);
const { foo } = obj1;
foo // "bar"
//对象obj1的原型对象是obj2。foo属性不是obj1自身的属性,而是继承自obj2的属性,解构赋值可以取到这个属性
注意:
案例:
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
console.log(first) // 1
console.log(last) // 3
此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
可以对length
属性解构赋值。
let {length : len} = 'hello';
len // 5
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象;
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
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]
上面代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。
以下三种解构赋值不得使用圆括号:
(1)变量声明语句;
(2)函数参数;
(3)赋值语句的模式;
### 可以使用圆括号的情况:赋值语句的非模式部分,可以使用圆括号。
交换变量的值(不需要引入第三个值)
let x = 1;
let y = 2;
[x, y] = [y, x];
从函数返回多个值:
函数参数的定义:方便地将一组参数与变量名对应起来;
提取 JSON 数据;
指定参数的默认值;
遍历 Map 结构;
输入模块的指定方法;
console.log("\u0061");// "a"
console.log("\uD842\uDFB7");//𠮷
console.log("\u{20BB7}");//𠮷
console.log("\u{41}\u{42}\u{43}");//ABC
let hello = 123;
console.log(hell\u{6F}) // 123
console.log('\u{1F680}' === '\uD83D\uDE80')//true
for…of:可以识别大于0xFFFF
的码点
JavaScript 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式:
\u005C
:反斜杠(reverse solidus)\u000D
:回车(carriage return)\u2028
:行分隔符(line separator)\u2029
:段分隔符(paragraph separator)\u000A
:换行符(line feed)如果遇到0xD800
到0xDFFF
之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。
SON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
let a=10;
let b=23;
console.log(`和是 ${a+b}
不是 ${2*a+b}`);
//和是 33
不是 43 进行了换行
<script>
let basket={count:1000,onSale:100}
let a=10;
let b=20;
function fn() {
return "Hello World";
}
$(function(){
$('#result').append(`
哈哈哈<h1>${basket.count}</h1>
嘿嘿嘿<h2>${basket.onSale}</h2>
哦哦哦<h3>${a+b}</h3>
eee<h3>${fn()}</h3>`
)
$('#list').html(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`.trim());
})
</script>
模板字符串,都是用反引号表示。如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
模板字符串中嵌入变量,需要将变量名写在${}
之中。basket.count
大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
模板字符串之中还能调用函数。
模板字符串甚至还能嵌套.
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>
可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。
alert`123`
// 等同于
alert(123)
“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
let a = 5;
let b = 10;
function tag(s, v1, v2) {
console.log(s[0]);
console.log(s[1]);
console.log(s[2]);
console.log(v1);
console.log(v2);
return "OK";
}
tag`Hello ${ a + b } world ${ a * b}`;
//结果:
Hello
World
15
50
tag函数:
function tag(stringArr, value1, value2){
// ...
}
// 等同于
function tag(stringArr, ...values){
// ...
}
---------------------------
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
---------------------------
tag
函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分,tag
函数的其他参数,都是模板字符串各个变量被替换后的值。案例1:如何将各个参数按照原来的位置拼合回去。
let total = 30;
let msg1 =`The total is ${total} (${total*1.05} with tax)`;
let msg = passthru`The total is ${total} (${total*1.05} with tax)`;
function passthru(literals) {
let result = '';
let i = 0;
while (i < literals.length) {
result += literals[i++];
if (i < arguments.length) {
result += arguments[i];
}
}
return result;
}
console.log(msg); //The total is 30 (31.5 with tax)
console.log(msg1); //The total is 30 (31.5 with tax)
“标签模板”的一个重要应用,就是过滤 HTML 字符串,防止用户输入恶意内容。
let sender = '<script>alert("abc")</script>'; // 恶意代码
let message =
SaferHTML`<p>${sender} has sent you a message.</p>`;
function SaferHTML(templateData) {
let s = templateData[0];
for (let i = 1; i < arguments.length; i++) {
let 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);
//<p><script>alert("abc")</script> has sent you a message.</p>