函数

JavaScript中的函数(一些基础知识)

关于JS函数

函数是对象,函数名是指针

函数声明与函数表达式

1
2
3
4
5
6
7
8
//函数声明
function sum(a, b){
return a + b;
}
//函数表达式
var sum = function(a, b){
return a + b
}

两者的区别:在解析过程中,解析器优先解析函数声明,而函数表达式需要当代码执行到它所在的行才会执行

1
2
3
4
5
6
7
sum(1, 2)
function sum(a, b){...}
//正确

sum(1, 2)
var sum = function(a, b){...}
//错误

注意:尽量不要在块级作用域中使用函数声明,而用函数表达式代替

1
2
3
4
5
6
7
8
9
if(p)
function a(){...}
else
function b(){...}
//不要这样做,而用一下代替
if(p)
var a = function(){...}
else
var b = function(){...}

函数的内部属性

在函数的内部,有两个特殊的对象:arguments,this
arguments对象有一个 callee 的属性,他是一个指针,指向拥有这个arguments的一个函数

1
2
3
4
function j(num){
if(num <= 1) return num
else return j(num - 1)
}

这是一个简单的递归,他的缺点是函数内部的递归语句与函数名紧紧地耦合在一起,不利于维护,此时可以利用callee进行修改

1
2
3
4
function j(num){
if(num <= 1) return num
else return arguments.callee(num - 1)
}

this:引用函数的执行环境对象
caller:保存着调用当前函数的函数的引用,如果是全局调用,则该值为null

函数的自带属性

1、length:函数希望接收的参数个数

1
2
function sum(a, b){...}
sum.length//2

2、apply,call,bind
这三者的用法与区别,移步另一篇博客

关于匿名函数

1
var say = function(){...}

这种情况下创建的函数叫做匿名函数,匿名函数的一些使用场景是把它当做值来使用
红宝书上的经典例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function createComparisonFunction(propertyName){
return function(obj1, obj2){
var val1 = obj1[propertyName]
var val2 = obj2[propertyName]
//接下来是一些比较规则,自定义
if(val1 < val2) return -1
else if(val1 > val2) return 1
else return 0
}
}

var data = [{name:'c', age: 20}, {name: 'a', age: 30}]
data.sort(createComparisonFunction('name'))
data[0].name //a

还记得之前所说,sort方法会调用每个对象的toString()方法来进行排序,因此得到的结果往往都不符合预期,而sort可以提供一个函数作为参数,用来定义排序规则。这里就是将createComparisonFunction内部的匿名函数作为值返回之后,再当做参数传递给sort以规定排序的方法。

关于this

移步另一篇文章,深入理解this对象

模仿块级作用域

JS中并没有块级作用域的概念,例如

1
2
3
4
5
6
function a(count){
for(var i = 0; i < count; i++){
...
}
console.log(i)
}

不同于大多数其他语言,for循环内部定义的变量i, 并不会随着循环结束而被销毁,闭包的知识可以说明这一点,因为这里的i变量保存在了函数a的活动对象内,因此从函数创建开始,就可以在函数内部任意访问它。
而匿名函数则可以模仿块级作用域,修改上述代码

1
2
3
4
5
6
7
8
function a(count){
(function(){
for(var i = 0; i < count; i++){
...
}
})()
console.log(i)//报错
}

这里定义了一个立即执行的匿名函数,因此匿名函数执行完毕之后i就会被销毁,达到块级作用域的效果

作用:这个技巧通常在全局作用域中被用在函数外部,从而避免向全局作用域添加过多的变量与函数,一般来说,我们都应该尽量少向全局作用域添加变量和函数

ES6对函数的扩展

函数参数默认值

es5中,并没与提供直接的函数默认参数值的方法,而在es6中,可以这样使用

1
2
3
4
5
6
function a(x, y = 'world'){
console.log(x, y)
}
a('hello') //hello world
a('hello', 'javascript')//hello javascript
a('hello', '')//hello

参数的变量是默认声明的,所以不能使用let和const再次声明

1
2
3
4
function a(x = 5){
let x = 1//报错
const x = 2//报错
}

使用参数默认值时,函数不能有同名参数

1
2
3
4
function a(x, x, y = 1){
...
}
//SyntaxError

参数默认值不是传值的,而是每次都要重新计算默认表达式的值,也就是说,参数默认值时惰性求值

1
2
3
4
5
6
7
let x = 99
function a(p = x + 1){
console.log(p)
}
a()//100
x = 100
a()//101

与解构赋值默认值结合使用

1
2
3
4
5
6
7
function a({x, y = 5}){
console.log(x, y)
}
a({})//undefine, 5
a({x:1})//1,5
a({x:1, y:2})//1, 2
a()//报错

上述代码中使用对象的解构赋值设置函数的默认值,只有当函数的参数是一个对象时,变量x和y才会通过解构赋值生成,否则就会报错,以下代码也是这样

1
2
3
4
5
function a(m, {x = 1}){
console.log(x)
}
a(6,{})//1
a(6)//报错

也可以通过设置双重默认值来解决这个问题

1
2
3
4
5
function a(m, {x = 1} = {}){
console.log(x)
}
a(6,{})//1
a(6)//1

默认参数的位置

一般情况下,默认参数应该是函数的尾参数,因为在非尾参数设置默认值,实际上这个参数是无法省略的

1
2
3
4
5
6
function a(x = 1, y){
console.log(x, y)
}
a()//1,undefine
a(2)//2, undefine
a(,2)//报错

注意此时的length属性

指定了默认值后,函数的length属性将返回没有默认值的参数个数

1
(function(a, b = 5){}).length  //1

作用域

一旦设置了默认值,函数进行声明和初始化时就会形成一个单独的作用域,等到初始化结束,作用域就会消失

1
2
3
4
5
6
let x = 1
function a(y = x){
let x = 2;
console.log(y)
}
a()//1

上面的代码中, 函数f调用时,参数y = x形成了一个单独的作用域,在这个作用域内变量x本身并没有定义,所以指向外层的全局变量x,函数调用时,内部的局部变量影响不到默认变量x

rest参数

es6引入了rest参数,用于获取函数的多余参数

1
2
3
4
5
6
7
8
function add(x, ...y){
let sum = 0
for(var i of y){
sum += i
}
return sum
}
add(1, 2, 3)//6

注意:rest参数后面不可以再跟其他参数,否则会报错

1
2
3
4
function add(x, ...y, z){
...
}
//报错

name属性

函数的name属性返回函数名,这一属性直到es6才被写入标准
需要注意的是,es6对这一属性进行了一些修改,如果将一个匿名函数赋值给变量,es5中name返回空串,而es6返回实际的函数名

1
2
3
4
5
var f = function(){};
//es5
f.name // ''
//es6
f.name // 'f'

箭头函数 && 尾调用优化

移步另一篇博客

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2015-2021 AURORA_ZXH
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信