2
2
3
3
## 函数参数的默认值
4
4
5
+ ### 基本用法
6
+
5
7
在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
6
8
7
9
``` javascript
@@ -52,10 +54,37 @@ function Point(x = 0, y = 0) {
52
54
}
53
55
54
56
var p = new Point ();
55
- // p = { x:0, y:0 }
57
+ p // { x: 0, y: 0 }
58
+ ```
59
+
60
+ 除了简洁,ES6的写法还有两个好处:首先,阅读代码的人,可以立刻意识到哪些参数是可以省略的,不用查看函数体或文档;其次,有利于将来的代码优化,即使未来的版本彻底拿掉这个参数,也不会导致以前的代码无法运行。
61
+
62
+ 参数默认值可以与解构赋值,联合起来使用。
63
+
64
+ ``` javascript
65
+ function foo ({x, y = 5 }) {
66
+ console .log (x, y);
67
+ }
68
+
69
+ foo ({}) // undefined, 5
70
+ foo ({x: 1 }) // 1, 5
71
+ foo ({x: 1 , y: 2 }) // 1, 2
72
+ ```
73
+
74
+ 上面代码中,` foo ` 函数的参数是一个对象,变量` x ` 和` y ` 用于解构赋值,` y ` 有默认值5。
75
+
76
+ 另外,参数变量是默认声明的,所以不能用let或const再次声明。
77
+
78
+ ``` javascript
79
+ function foo (x = 5 ) {
80
+ let x = 1 ; // error
81
+ const x = 2 ; // error
82
+ }
56
83
```
57
84
58
- 除了简洁,ES6的写法还有两个好处:首先,阅读代码的人,可以立刻意识到哪些参数是可以省略的,不用查看函数体或文档;其次,有利于将来的代码优化,即使未来的版本彻底拿到这个参数,也不会导致以前的代码无法运行。
85
+ 上面代码中,参数变量` x ` 是默认声明的,在函数体中,不能用let或const再次声明,否则会报错。
86
+
87
+ ### 双重默认值
59
88
60
89
默认值的写法非常灵活,下面是一个为对象属性设置默认值的例子。
61
90
@@ -86,7 +115,7 @@ fetch('http://example.com')
86
115
87
116
上面代码中,调用函数` fetch ` 时,第二个参数默认为一个空对象,而只要有第二个参数,` method ` 参数就默认为` GET ` 。
88
117
89
- 请问下面两种写法有什么差别 ?
118
+ 再请问下面两种写法有什么差别 ?
90
119
91
120
``` javascript
92
121
// 写法一
@@ -123,7 +152,9 @@ m1({z: 3}) // [0, 0]
123
152
m2 ({z: 3 }) // [undefined, undefined]
124
153
```
125
154
126
- 通常情况下,定义了默认值的参数,都是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。但是,非尾部的参数,也是可以设置默认值的。
155
+ ### 参数默认值的位置
156
+
157
+ 通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。
127
158
128
159
``` javascript
129
160
// 例一
@@ -149,7 +180,7 @@ f(1, undefined, 2) // [1, 5, 2]
149
180
150
181
上面代码中,有默认值的参数都不是尾参数。这时,无法只省略该参数,而不省略它后面的参数,除非显式输入` undefined ` 。
151
182
152
- 如果传入` undefined ` ,将触发该参数等于默认值,null则没有这个效果 。
183
+ 如果传入` undefined ` ,将触发该参数等于默认值,` null ` 则没有这个效果 。
153
184
154
185
``` javascript
155
186
function foo (x = 5 , y = 6 ){
@@ -162,6 +193,8 @@ foo(undefined, null)
162
193
163
194
上面代码中,` x ` 参数对应` undefined ` ,结果触发了默认值,` y ` 参数等于` null ` ,就没有触发默认值。
164
195
196
+ ### 函数的length属性
197
+
165
198
指定了默认值以后,函数的` length ` 属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,` length ` 属性将失真。
166
199
167
200
``` javascript
@@ -172,63 +205,106 @@ foo(undefined, null)
172
205
173
206
上面代码中,` length ` 属性的返回值,等于函数的参数个数减去指定了默认值的参数个数。
174
207
175
- 利用参数默认值,可以指定某一个参数不得省略,如果省略就抛出一个错误。
208
+ ### 作用域
209
+
210
+ 一个需要注意的地方是,如果参数默认值是一个变量,则该变量所处的作用域,与其他变量的作用域规则是一样的,即先是当前函数的作用域,然后才是全局作用域。
176
211
177
212
``` javascript
178
- function throwIfMissing () {
179
- throw new Error (' Missing parameter' );
213
+ var x = 1 ;
214
+
215
+ function f (x , y = x ) {
216
+ console .log (y);
180
217
}
181
218
182
- function foo (mustBeProvided = throwIfMissing ()) {
183
- return mustBeProvided;
219
+ f (2 ) // 2
220
+ ```
221
+
222
+ 上面代码中,参数` y ` 的默认值等于` x ` 。调用时,由于函数作用域内部的变量` x ` 已经生成,所以` y ` 等于参数` x ` ,而不是全局变量` x ` 。
223
+
224
+ 如果调用时,函数作用域内部的变量` x ` 没有生成,结果就会不一样。
225
+
226
+ ``` javascript
227
+ let x = 1 ;
228
+
229
+ function f (y = x ) {
230
+ let x = 2 ;
231
+ console .log (y);
184
232
}
185
233
186
- foo ()
187
- // Error: Missing parameter
234
+ f () // 1
188
235
```
189
236
190
- 上面代码的 ` foo ` 函数,如果调用的时候没有参数,就会调用默认值 ` throwIfMissing ` 函数,从而抛出一个错误 。
237
+ 上面代码中,函数调用时, ` y ` 的默认值变量 ` x ` 尚未在函数内部生成,所以 ` x ` 指向全局变量,结果又不一样 。
191
238
192
- 从上面代码还可以看到,参数 ` mustBeProvided ` 的默认值等于 ` throwIfMissing ` 函数的运行结果(即函数名之后有一对圆括号),这表明参数的默认值不是在定义时执行,而是在运行时执行(即如果参数已经赋值,默认值中的函数就不会运行),这与python语言不一样 。
239
+ 如果此时,全局变量 ` x ` 不存在,就会报错 。
193
240
194
- 另一个需要注意的地方是,参数默认值所处的作用域,不是全局作用域,而是函数作用域。
241
+ ``` javascript
242
+ function f (y = x ) {
243
+ let x = 2 ;
244
+ console .log (y);
245
+ }
246
+
247
+ f () // ReferenceError: x is not defined
248
+ ```
249
+
250
+ 如果函数` A ` 的参数默认值是函数` B ` ,由于函数的作用域是其声明时所在的作用域,那么函数` B ` 的作用域不是函数` A ` ,而是全局作用域。请看下面的例子。
195
251
196
252
``` javascript
197
- var x = 1 ;
253
+ let foo = ' outer ' ;
198
254
199
- function foo (x , y = x ) {
200
- console .log (y);
255
+ function bar (func = x => foo ) {
256
+ let foo = ' inner' ;
257
+ console .log (func ()); // outer
201
258
}
202
259
203
- foo ( 2 ) // 2
260
+ bar ();
204
261
```
205
262
206
- 上面代码中,参数y的默认值等于x,由于处在函数作用域,所以y等于参数x,而不是全局变量x 。
263
+ 上面代码中,函数 ` bar ` 的参数 ` func ` ,默认是一个匿名函数,返回值为变量 ` foo ` 。这个匿名函数的作用域就不是 ` bar ` 。这个匿名函数声明时,是处在外层作用域,所以内部的 ` foo ` 指向函数体外的声明,输出 ` outer ` 。它实际上等同于下面的代码 。
207
264
208
- 参数变量是默认声明的,所以不能用let或const再次声明。
265
+ ``` javascript
266
+ let foo = ' outer' ;
267
+ let f = x => foo;
268
+
269
+ function bar (func = f ) {
270
+ let foo = ' inner' ;
271
+ console .log (func ()); // outer
272
+ }
273
+
274
+ bar ();
275
+ ```
276
+
277
+ 如果写成下面这样,就会报错。
209
278
210
279
``` javascript
211
- function foo ( x = 5 ) {
212
- let x = 1 ; // error
213
- const x = 2 ; // error
280
+ function bar ( func = () => foo ) {
281
+ let foo = ' inner ' ;
282
+ console . log ( func ());
214
283
}
284
+
285
+ bar () // ReferenceError: foo is not defined
215
286
```
216
287
217
- 上面代码中,参数变量x是默认声明的,在函数体中,不能用let或const再次声明,否则会报错。
288
+ ### 应用
218
289
219
- 参数默认值可以与解构赋值,联合起来使用 。
290
+ 利用参数默认值,可以指定某一个参数不得省略,如果省略就抛出一个错误 。
220
291
221
292
``` javascript
222
- function foo ({x, y = 5 } ) {
223
- console . log (x, y );
293
+ function throwIfMissing ( ) {
294
+ throw new Error ( ' Missing parameter ' );
224
295
}
225
296
226
- foo ({}) // undefined, 5
227
- foo ({x: 1 }) // 1, 5
228
- foo ({x: 1 , y: 2 }) // 1, 2
297
+ function foo (mustBeProvided = throwIfMissing ()) {
298
+ return mustBeProvided;
299
+ }
300
+
301
+ foo ()
302
+ // Error: Missing parameter
229
303
```
230
304
231
- 上面代码中,foo函数的参数是一个对象,变量x和y用于解构赋值,y有默认值5。
305
+ 上面代码的` foo ` 函数,如果调用的时候没有参数,就会调用默认值` throwIfMissing ` 函数,从而抛出一个错误。
306
+
307
+ 从上面代码还可以看到,参数` mustBeProvided ` 的默认值等于` throwIfMissing ` 函数的运行结果(即函数名之后有一对圆括号),这表明参数的默认值不是在定义时执行,而是在运行时执行(即如果参数已经赋值,默认值中的函数就不会运行),这与python语言不一样。
232
308
233
309
## rest参数
234
310
@@ -544,6 +620,13 @@ var go = function*(){
544
620
545
621
上面代码中,变量` go ` 是一个Generator函数,执行后返回的是一个遍历器对象,对这个遍历器对象执行扩展运算符,就会将内部遍历得到的值,转为一个数组。
546
622
623
+ 如果对没有` iterator ` 接口的对象,使用扩展运算符,将会报错。
624
+
625
+ ``` javascript
626
+ var obj = {a: 1 , b: 2 };
627
+ let arr = [... obj]; // TypeError: Cannot spread non-iterable object
628
+ ```
629
+
547
630
## name属性
548
631
549
632
函数的` name ` 属性,返回该函数的函数名。
0 commit comments