-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfunction.txt
More file actions
275 lines (231 loc) · 7.83 KB
/
function.txt
File metadata and controls
275 lines (231 loc) · 7.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
//定义
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
//1
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
//2
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
abs(10, 'blablabla'); // 返回10
abs(-9, 'haha', 'hehe', null); // 返回9
传入的参数比定义的少也没有问题:
abs(); // 返回NaN
JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,
并且永远指向当前函数的调用者传入的所有参数。
function foo(x) {
console.log('x = ' + x); // 10
for (var i=0; i<arguments.length; i++) {
console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
}
}
foo(10, 20, 30);
x = 10
arg 0 = 10
arg 1 = 20
arg 2 = 30
//利用arguments拿到参数,无论是否定义了参数
function abs() {
if (arguments.length === 0) {
return 0;
}
var x = arguments[0];
return x >= 0 ? x : -x;
}
abs(); // 0
abs(10); // 10
abs(-9); // 9
// foo(a[, b], c)
// 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:
function foo(a, b, c) {
if (arguments.length === 2) {
// 实际拿到的参数是a和b,c为undefined
c = b; // 把b赋给c
b = null; // b变为默认值
}
// ...
}
要把中间的参数b变为“可选”参数,就只能通过arguments判断,然后重新调整参数并赋值。
//rest参数
function foo(a, b) {
var i, rest = [];
if (arguments.length > 2) {
for (i = 2; i<arguments.length; i++) {
rest.push(arguments[i]);
}
}
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1,2,3,4);
a = 1
b = 2
[3, 4]
//rest
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
这说明JavaScript实际上只有一个全局作用域。任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找,最后如果在全局作用域中也没有找到,则报ReferenceError错误。
减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。例如
// 唯一的全局变量MYAPP:
var MYAPP = {};
// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 其他函数:
MYAPP.foo = function () {
return 'foo';
};
由于JavaScript的变量作用域实际上是函数内部,我们在for循环等语句块中是无法定义具有局部作用域的变量的:
'use strict';
function foo() {
for (var i=0; i<100; i++) {
//
}
i += 100; // 仍然可以引用变量i
}
为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:
'use strict';
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
// SyntaxError:
i += 1;
}
由于var和let申明的是变量,如果要申明一个常量,在ES6之前是不行的,我们通常用全部大写的变量来表示“这是一个常量,不要修改它的值”:
var PI = 3.14;
ES6标准引入了新的关键字const来定义常量,const与let都具有块级作用域:
'use strict';
const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
PI; // 3.14
从ES6开始,JavaScript引入了解构赋值,可以同时对一组变量进行赋值。
现在,在ES6中,可以使用解构赋值,直接对多个变量同时赋值:
'use strict';
// 如果浏览器支持解构赋值就不会报错:
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
// x, y, z分别被赋值为数组对应元素:
console.log('x = ' + x + ', y = ' + y + ', z = ' + z);
注意,对数组元素进行解构赋值时,多个变量要用[...]括起来。
如果数组本身还有嵌套,也可以通过下面的形式进行解构赋值,注意嵌套层次和位置要保持一致:
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
x; // 'hello'
y; // 'JavaScript'
z; // 'ES6'
解构赋值还可以忽略某些元素:
let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
z; // 'ES6'
如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性:
'use strict';
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
var {name, age, passport} = person;
// name, age, passport分别被赋值为对应属性:
console.log('name = ' + name + ', age = ' + age + ', passport = ' + passport);
name = 小明, age = 20, passport = G-12345678
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school',
address: {
city: 'Beijing',
street: 'No.1 Road',
zipcode: '100001'
}
};
var {name, address: {city, zip}} = person;
name; // '小明'
city; // 'Beijing'
zip; // undefined, 因为属性名是zipcode而不是zip
// 注意: address不是变量,而是为了让city和zip获得嵌套的address对象的属性:
address; // Uncaught ReferenceError: address is not defined
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
如果要使用的变量名和属性名不一致,可以用下面的语法获取:
// 把passport属性赋值给变量id:
let {name, passport:id} = person;
name; // '小明'
id; // 'G-12345678'
// 注意: passport不是变量,而是为了让变量id获得passport属性:
passport; // Uncaught ReferenceError: passport is not defined
解构赋值还可以使用默认值,这样就避免了不存在的属性返回undefined的问题:
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678'
};
// 如果person对象没有single属性,默认赋值为true:
var {name, single=true} = person;
name; // '小明'
single; // true
有些时候,如果变量已经被声明了,再次赋值的时候,正确的写法也会报语法错误:
// 声明变量:
var x, y;
// 解构赋值:
{x, y} = { name: '小明', x: 100, y: 200};
// 语法错误: Uncaught SyntaxError: Unexpected token =
这是因为JavaScript引擎把{开头的语句当作了块处理,于是=不再合法。解决方法是用小括号括起来:
({x, y} = { name: '小明', x: 100, y: 200});
//使用场景
解构赋值在很多时候可以大大简化代码。例如,交换两个变量x和y的值,可以这么写,不再需要临时变量:
var x=1, y=2;
[x, y] = [y, x]
快速获取当前页面的域名和路径:
var {hostname:domain, pathname:path} = location;
如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。例如,下面的函数可以快速创建一个Date对象:
function buildDate({year, month, day, hour=0, minute=0, second=0}) {
return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}
它的方便之处在于传入的对象只需要year、month和day这三个属性:
buildDate({ year: 2017, month: 1, day: 1 });
// Sun Jan 01 2017 00:00:00 GMT+0800 (CST)
也可以传入hour、minute和second属性:
buildDate({ year: 2017, month: 1, day: 1, hour: 20, minute: 15 });
// Sun Jan 01 2017 20:15:00 GMT+0800 (CST)
JavaScript的函数内部如果调用了this,那么这个this到底指向谁?
答案是,视情况而定!
如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的对象,也就是xiaoming,这是符合我们预期的。
如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window。