Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 新旧替换三:参数转换 #36

Open
XXHolic opened this issue Feb 8, 2019 · 0 comments
Open

JavaScript 新旧替换三:参数转换 #36

XXHolic opened this issue Feb 8, 2019 · 0 comments

Comments

@XXHolic
Copy link
Owner

XXHolic commented Feb 8, 2019

目录

引子

在 ES2015 之前,有把函数的 arguments 转变为某种可以当作数组来使用的方法,现在可以摆脱这些方法了。

这是继 JavaScript 新旧替换二:赋值和取值的第三篇。

ES5 方式

主要是使用了 apply() 方法,该方法用途是在特定的作用域中调用函数,实际上等于设置函数体内 this 对象的值。该接受两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是 Array 的实例,也可以是 arguments 对象。

function foo() {
  var args = Array.prototype.slice.apply(arguments);
  console.info(args); // [1,2,3,4,5]
  console.info(args instanceof Array); // true
}
foo(1,2,3,4,5);

ES2015+ 方式

在 ES2015 中引入了一个新的运算符 ...,称为 spreadrest(展开或收集)运算符。不同情况下,会有不同的特性。

function foo(...args) {
  console.info(args); // [1,2,3,4,5]
  console.info(...args); // 1 2 3 4 5
}
foo(1,2,3,4,5);

这里运算符 ... 使用的特性有:

  • foo(...args) 中使用了收集的特性,把一系列值收集到一起成为一个数组。
  • console.info(...args) 中使用了展开的特性,这里把数组 args 展开为一组函数调用的参数。

在 ES2018 中这个运算符引入到了对象。它会取出对象的所有可遍历属性,拷贝到当前对象中。

使用于对象常见的几种情况如下:

一般对象

let obj = {a:1,b:2};
let objCopy = {...obj};
objCopy.a = 2;
console.info(obj); // {a:1,b:2}
console.info(objCopy); // {a:2,b:2}

let complexObj = {a:{b:1},c:2};
let complexObjCopy = {...complexObj};
complexObjCopy.a.b = 2;
console.info(complexObj); // {a:{b:2},b:2}
console.info(complexObjCopy); // {a:{b:2},b:2}

可见只是进行了浅拷贝,等同于使用 Object.assign() 方法。

数组

let objArray = {...['a','b']};
console.info(objArray); // {0: "a", 1: "b"}

let complexObjArray = {...['a',['b'],'c']};
console.info(complexObjArray); // {0: "a", 1: ["b"],2:"c"}

字符串

let objStr = {...'hi'};
console.info(objStr); // {0: "h", 1: "i"}

其它

{...1} // {}

{...true} // {}

{...undefined} // {}

{...null} // {}

{...NaN} // {}

应用

运算符 ... 较常见应用有:

复制对象或数组

let obj = {a:{b:1},c:2};
let objCopy = {...obj};
objCopy.a.b = 2;
console.info(obj); // {a:{b:2},b:2}
console.info(objCopy); // {a:{b:2},b:2}

let arr = ['1',['2']];
let arrCopy = [...arr];
arrCopy[1][0] = '3';
console.info(arr); // ['1',['3']]
console.info(arrCopy); // ['1',['3']]

需要注意都是浅拷贝。

合并对象或数组

let objA = {a:1}, objB = {b:2};
let obj = {...objA,...objB};
console.info(obj); // {a:1,b:2}

let arrA = ['1'], arrB = ['2'];
let arr = [...arrA,...arrB];
console.info(arr); // ['1',2']

与解构结合

与对象解构结合

与对象解构结合需要满足的条件有:

  • 等号右边是一个对象。
  • 解构必需是最后一个参数,否则会报错。
let {a,...b} = undefined; // Uncaught TypeError: Cannot destructure property `a` of 'undefined' or 'null'.

let {...q,k} = {m:1,n:2,k:3}; // Uncaught SyntaxError: Rest element must be last element

let {x,...z} = {x:1,y:2,z:3};
z // {y:2,z:3}

使用了扩展运算符后,把目标对象上所有可遍历但尚未被读取的属性,分配到指定对象上。

与数组解构结合

与数组解构结合需要满足的条件有:

  • 等号右边是一个数组。
  • 解构必需是最后一位,否则会报错。
let [...x] = 123; // 123 is not iterable

let [...q,k] = [1,2,3]; // Uncaught SyntaxError: Rest element must be last element

let [x,...z] = [1,2,3];
z // [2,3]

参考资料

🗑️

看了电影《阳光普照》,里面关于司马光砸缸故事的重新解读,角度很有特点。下面是电影中对话。

场景是在一个公交站。

男:你有听过吗?

女:你是说~司马光把水缸打破,然后把淹在水缸里面的小孩子救出来?

男:没有没有,其实真正的故事是,司马光和一群小朋友在玩捉迷藏,刚开始的时候司马光当鬼,在他把所有小朋友都找到之后,他却突然说,还有一个小朋友没有被找到。大家你看我,我看你地说‘没有啊,都在呀,那里有少?’但司马光就是坚持,还有一个小朋友没有被找到。大家拿他没办法,于是就开始找他那个口中不见的小朋友。找了一阵子,终于在一棵树下,看到一个大水缸,大家看到那个水缸都很兴奋,指着那个水缸说‘一定在里面…一定在里面……’但只有司马光一个人留在原地,然后司马光就捡起一颗…

这时公交车来了,但女生没有乘坐公交。

女:然后呢?

男:然后司马光就捡拿起一颗石头,砸向水缸。水缸破了,但是根本没有水流出来,大家都呆住了,因为他们看到一个小孩,坐在水缸的阴暗处,看着缸外。

男:你知道那个小孩是谁吗?

女生摇摇头看着他。

男:就是司马光自己。

34-waste-poster

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant