0%

ES6函数扩展和解构复制理清

先从阮老师ES6教程的一个事例说起

1
2
3
4
5
6
7
8
9
// 写法一
function m1({x = 0, y = 0} = {}) {
return [x, y];
}

// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
return [x, y];
}

请问这两个的写的有什么区别?一开始看到这个我是蒙的?因为这里将函数的默认值的ES6写法和ES6写法的解构赋值放在了一起。

解释与理清

在这里,函数的参数都变成了对象,而ES6的解构复制就是将利用两个对象的对比来进行赋值进而简化代码

而阮老师给出的答案是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 函数没有参数的情况
m1() // [0, 0]
m2() // [0, 0]

// x和y都有值的情况
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]

// x有值,y无值的情况
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]

// x和y都无值的情况
m1({}) // [0, 0];
m2({}) // [undefined, undefined]

m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]

解决问题的思路

我们解决问题都是从大到小,从简单到复杂,在函数的参数传值比较复杂的情况下也是利用从外到里的看

首先我们看写法一 {x = 0, y = 0} = {}

  • 我们从外到里的看,首先是 调用 传入参数,接着才是判断 是否有参数 如果 ,那么默认值 即最右边 = 右边的 {} 不会生效 进入下一步 如果 没有 那么就默认值 即最右边 = 右边的 {} 就会成为函数参数的默认值

  • 如果外层的默认值不生效 接着看传入的参数对象内部 { } 是否 符合参数对象 内部默认的 x y两个参数 如果不符合 就会启用内层x y 的默认值 ,要是符合,就利用传入的原值

调用 m1() ,首先看外层,没有参数,所以启用默认值 即最右边 = 右边的 {},那么再看内层,这里面没有符合 x y的参数 所以就会启用内层x y的默认值 所以结果 为[0,0]

调用 m1({x: 3, y: 8}) ,内层外层都不会启用默认值所以 为[3,8]

调用 m1({x: 3}),外层有 {}的对象不启用外层默认值,但是内层没有参数y 所以y启用内层默认值结果为[3,0]

调用 m1({}) 外层有 {}的对象不启用外层默认值,内层无x y,所以启用x y默认值 结果为 [0,0]

调用 m1({z: 3}) 同上

接着我们看写法二 {x, y} = { x: 0, y: 0 }

  • 我们从外到里的看,首先 调用 ,判断 是否有参数 ,没用有就用默认值 { x: 0, y: 0 }

  • 如果外层的默认值不生效 接着看传入的参数对象内部 { } 是否 符合参数对象 内部有 x y两个参数 但是这两个参数没有默认值

调用 m2() ,首先看外层,没有参数,所以启用默认值 即最右边 = 右边的 { x: 0, y: 0 },那么结果为[0,0]

调用 m2({x: 3, y: 8}) ,内层外层都不会启用默认值所以 为[3,8]

调用 m2({x: 3}),外层有 {}的对象不启用外层默认值 内层y没有默认值,所以就结果为[3, undefined]

调用 m2({}) 外层有 {}的对象不启用外层默认值,内层无x y 且x y 无默认值,结果为[undefined, undefined]

调用 m1({z: 3}) 同上

从一个小题目谈谈js函数闭包

先来看一个问题

题目

1
2
3
4
5
var str1 = str2 = "web";
(function () {
var str1 = str2 = "前端";
})();
console.log(str2);

当然这里输出的是结果是:

前端

如果现在将console.log(str2)变成consloe.log(str1),那么输出的结果就会变成

web

解答

其实这题并不是很难,第一句 var str1 = str2 = "web"; 其实是定义了两个全局的变量,在利用function的闭包内用 var 重新定义了 str1 而没有重新定义 str2

我们知道在默认情况下 如果不用 var 定义的变量都会变成全局变量,所以此时在function闭包内的str2就是引用了全局变量,所以赋值操作当然也就能赋予全局变量 str2 所以输出 str2 结果是 “前端”

str1 用了 var 定义,就是在function闭包内的变量,闭包外自然不可以改变,所以输出的结果是 “web”

脑洞大开

其实每一次看到这种形式的代码

1
2
(function(){
})()

都觉得非常的新鲜,觉得这里有很多东西可以专研,所以在这里也总结一下这种形式的闭包。

解释前先看看

首先这种形式的闭包是人为的加上去,并不是说可以有什么神奇的 duangduang 的特效,而是可以避免很多本来是局部变量可以搞定的比较 low 的变量去污染全局的变量

其次在js中,是 没有块作用域 这种说法
首先我们回到C++,如果有一段代码是这样

1
2
3
4
5
int number1=10;
if(true){
int number1 = 5;
}
cout<<number1;

这里的结果还是

10

而在js代码之中

1
2
3
4
5
var str1= "web";
if(true){
var str1="前端";
};
console.log(str1);

这里的结果就是

前端

因为 if{} 没有块作用域,所以内部的str1直接就重定义了外部全局的str1,所以输出的结果就只是”前端”了,而且这也污染了全局变量(那个等于”web”的str1已经不见了踪影)

而大 js 只有 函数作用域

所以我们要利用函数闭包

利用函数闭包能有效的封装局部的变量,而不污染全局作用域

1
2
3
4
5
6
7
str1 = "web";
(function () {
var str1 = "前端";

//str1剩下的功能
)();
console.log(str1);

此时输出的还是

web

所以我们利用了一个匿名函数 function(){} 并且让他自己调用自己执行函数内部的操作 并且 str1 也没有污染到外部的全局作用域


我是何方猿

老实说,我不擅长表达。
开这个个人的Hexo博客也是想自己写点东西,记录自己程序员发展的点点滴滴。

叫我小俊吧,这样比较亲切一点。

我在哪?

我现在是大三,就读于华南理工大学软件学院。
目前从事的是Web前端方向,断断续续有学一年多吧,可以自己写点小东西出来,只不过也是一个初级的不能再初级的前端工程师了。

关于前端我想说

前端发展实在是超级超级快,目前正在狂学react.jsangular.js
也想成为一名全栈工程师,所以也在努力的学习node.js
自己同时也会从事原型设计工作

目标

当然啦。作为一名超级心怀“理想”的猿,还是想去好的公司打码啦。毕竟猿也要成为一名成精的猿嘛。hhh

来这里干嘛

来这里的首要目的就要虚心学习学习,交流交流,知识无尽嘛!
当然来这里BB也是可以的。来者不拒,我是话唠嘿嘿嘿。