数组解构
// 两边相同模式。即可实现解构
// 按照一定顺序解构
const [a, b, [c]] = [1, 2, [3]];
console.log(a, b, c); // 1, 2, 3
// 解构不成功,变量值为 undefined;
const [s, d, w] = [1, 2];
console.log(s, d, w); // 1 2 undefined
// 只要变量具备 迭代器(Iterator)接口,就可以实现数据解构
const [x, y, z] = new Set([4, 5, 6]);
console.log(x, y, z); // 4, 5, 6
// 解构赋值允许指定默认值
const [name = "zhangsan"] = [];
console.log("name:", name); // zhangsan
const [name2 = "zhangsan"] = ["李四"];
console.log("name2:", name2); // 李四
对象解构
// 没有顺序,必须与属性同名,才能取到正确的值
// 变量没有对应属性名,不影响取值,取值结果为 undefined
let { foo, bar, baz } = { foo: "aaa", bar: "bbb" };
console.log("bar", bar); // bbb
console.log("foo", foo); // aaa
console.log("baz", baz); // undefined
// 变量名和属性名不一致,必须写成
// 内部机制:先找到同名属性,再赋给对应变量
const { foo: fooName } = { foo: "aaa", bar: "bbb" };
console.log("fooName:", fooName); // aaa
const { name: n, age: a } = { name: "张三", age: 16 };
console.log("名字:", n); // 张三
console.log("年龄:", a); // 16
// 指定默认值
var { x = 3 } = {};
console.log(x); // 3
var { x: y = 3 } = { x: 5 };
console.log(y); // 5
// 注意点
// 1、已经声明的变量用于解构,会报错
let x;
{ x } = { x: 1 } // error
({ x } = { x :1 })
console.log(x); // 1
// 2、解构赋值,允许等号左边的模式之中,不放置任何变量名。因此,可以写出下面的赋值表达式
({} = [true, false])
({} = "abc")
({} = [])
// 3、由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构
let arr = [1, 2, 3]
let { 0: first, [arr.length - 1]: last } = arr
console.log(first) // 1
console.log(last) // 3
模版字符串
// 普通字符串
const name = "张三";
// es5
console.log("我的名字叫:" + name); // 我的名字叫张三
// es6
console.log(`我的名字叫:${name}`); // 我的名字叫张三
// es6 换行
console.log(`我的名字叫:
${name}`);
// 我的名字叫:
// 张三
函数参数的默认值
基本用法
- 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
- es6 允许为函数的参数设置默认值,即直接写在参数定义的后面
function log(x, y = "world") {
console.log(x, y);
}
log("Hello"); // Hello World
log("Hello", "China"); // Hello China
log("Hello", ""); // Hello
- es6 写法的好处
- 可读性:直观的看出哪些参数是缺省的
- 健壮性:利于将来代码优化,即使未来版本在对外接口中,彻底拿掉换个参数,也不会导致以前代码无法运行
函数 - rest 参数(...变量名)
- 用户获取函数的多余参数,就不需要使用 arguments 对象了
- rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中
function add(...values) {
let sum = 0;
console.log(values); // [1, 2, 3]
for (var val of values) {
sum += val;
}
return sum;
}
console.log(add(1, 2, 3)); // 6
- arguments 写法
function add() {
let sum = 0;
console.log(arguments); // Arguments(3) [1, 2, 3, callee: (...), Symbol(Symbol.iterator): ƒ]
console.log(Array.prototype.slice.call(arguments).sort()); // [1, 2, 3]
const values = Array.prototype.slice.call(arguments).sort();
for (var val of values) {
sum += val;
}
return sum;
}
console.log(add(1, 2, 3)); // 6
-
对比
- arguments 对象是一个类似数组的对象,使用 Array.prototype.slice.call 先将其转为数组。
- rest 参数不存在这个问题,得到的参数就是一个真正的数组,数组特有的方法都可以使用
- rest 参数后面不能有其他参数(只能是最后一个参数),否则会报错
- 函数 length 属性,不包括 rest 参数
function test(a) {} console.log("-----", test.length); // 1 function test1(...a) {} console.log("-----", test1.length); // 0 function test2(a, ...b) {} console.log("-----", test2.length); // 1
箭头函数
- 定义函数用 箭头
// es5
function foo() {}
// es6
const foo = () => {};
const f = (v) => v;
// 等同于===
const f = function (v) {
return v;
};
- 如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分
var f = () => 5;
// 等同于
var f = function () {
return 5;
};
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function (num1, num2) {
return num1 + num2;
};
-
使用注意
- 不可以作为构造函数使用,不能使用
new命令 - 没有原型
- 不可以使用 arguments,要用
rest参数代替 - 不可以使用 yield 关键字
- 不可以作为构造函数使用,不能使用
const test = (...rest) => {
console.log(rest); // [1, 2, 3]
};
test(1, 2, 3);
const test = () => {};
const t = new test();
console.log(t); // TypeError: test is not a constructor
const test = () => {};
console.log(test.prototype); // undefined
function Test() {}
console.log("Test:", Test.prototype); // {constructor: ...}
-
this
- 箭头函数没有 this
- 箭头函数的 this 对象,就是定义时所在的对象,而不是使用时所在的对象
- this 对象是固定的,父级作用域
function foo() { setTimeout(() => { // 箭头函数的定义生消灾 foo 函数生成时 // 在100毫秒之后真正执行 console.log("id:", this); // { id: 42 } console.log("id:", this.id); // 42 }, 100); } var id = 21; foo.call({ id: 42 }); // 给定this的值为 { id: 42 } // id: 42function foo() { // 普通函数,this指向window setTimeout(function () { console.log("id:", this); // Window console.log("id:", this.id); // 21 }, 100); } var id = 21; foo.call({ id: 42 });
对象新增方法
- Object.is() 比较两个值是否严格相等,与
===的行为基本一致
console.log(Object.is("", "")); // true
console.log(Object.is("name", "name")); // true
console.log(Object.is(1, 3)); // false
console.log(Object.is({}, {})); // false
console.log(Object.is([], [])); // false
console.log(Object.is(+0, -0)); // false
console.log(Object.is(NaN, NaN)); // true
// es5 实现 Object.is()
Object.defineProperty(Object, "is", {
value: function (x, y) {
if (x === y) {
// 针对 +0 不等于 -0 的情况
return x != 0 || 1 / x === 1 / y;
}
// 针对 NaN 的情况
return x !== x && y !== y;
},
configurable: true,
enumerable: false,
writable: true,
});
- Object.assign() 用于对象的合并,将源对象的所有可枚举属性,复制到目标对象;
- 实现浅拷贝
- 同名属性,后面合并的属性替换掉先合并的属性
- 若是处理数组,数组会被视为对象
- 如果要复制的值是一个取值函数,那么将求值后再复制
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: { x: 1 } };
Object.assign(target, source1, source2);
console.log(target); // {a: 1, b: 2, c: { x:1 }}}
target.c.x = 6;
console.log("target", target); // {a: 1, b: 2, c: { x:6 }}}
console.log("source2", source2); // {x: {x: 6 }}
const arr1 = [1, 2, 3];
const arr2 = [4, 5];
Object.assign(arr1, arr2);
console.log(arr1); // [4, 5, 3] 把索引0由1替换成4,索引1由2替换成5
const source = {
get foo() {
return 1;
},
};
const target = {};
Object.assign(target, source);
console.log(target); // {foo: 1}
// source 对象的 foo 属性是一个取值函数,Object.assign 不会复制这个取值函数,只会拿到值以后,将这个值复制过去
-
Object.getOwnPropertyDescriptors() 返回指定对象所有自身属性(非继承属性)的描述对象
- es5 的 Object.getOwnPropertyDescriptor() 返回某个对象属性的描述对象
-
Object.keys()、 Object.values()、Object.entries()
- Object.keys() ES5 引入方法,返回一个数组,成员时参数对象自身的所有可遍历属性的键名
- Object.values() ES2017 引入 返回一个数组,可遍历属性的键值
- Object.entries() ES2017 引入 返回一个数组,成员是参数对象自身所有可遍历属性的键值对数组
let { keys, values, entries } = Object;
let obj = { a: 1, b: 2, c: 3 };
console.log(keys(obj)); // ["a", "b", "c"]
console.log(values(obj)); // [1, 2, 3]
console.log(entries(obj)); // [ [a, 1], [b, 2], [c, 3]]
- Object.fromEntries() 将一个键值对数组转为对象
const obj = Object.fromEntries([
["foo", "bar"],
["baz", 42],
]);
console.log("obj:", obj); // {foo: 'bar', baz: 42}
// 该方法主要目的是将键值对的数据解构还原为对象,因此特别适合将 Map 结构转为对象
const map1 = new Map([
["foo", "bar"],
["baz", 42],
]);
console.log("map1:", Object.fromEntries(map1)); // {foo: 'bar', baz: 42}
const map2 = new Map().set("foo", true).set("bar", false);
console.log("map2:", Object.fromEntries(map2)); // {foo: true, bar: false}
// 配合 URLSearchParams 对象,将查询字符串转为对象
const params = Object.fromEntries(new URLSearchParams("foo=bar&baz=qux"));
console.log("params:", params); // {foo: 'bar', baz: 'qux'}