不管你承不承认,任何人在社会环境中都会被潜在的分为三六九等,而JavaScript中的函数就是一等公民。
什么是函数
函数是以function关键字定义的一组用来执行特定功能的语句。定义函数有三种方式:函数声明,函数表达式和构造函数。
函数声明
function sum(num1,num2){
return num1+num2;
}
函数表达式
var sum=function(num1,num2){
return num1+num2;
}
构造函数
var sum = new Function('num1', 'num2', 'console.log( num1 + num2)');
sum(2, 6);
构造函数的第三个参数是一个包括JavaScript语句的字符串。
函数没有重载
function addNumber(num){
return num+10;
}
function addNumber(count){
return count+20;
}
addNumber(10);//30
上面两个函数名一样,但是参数及计算方式不一样,结果却是执行第二个函数,因为后面的函数覆盖了前面的函数。实际上与下面的代码没有区别:
var addNumber=function(num){
return num+10;
};
addNumber=function(count){
return count+20;
}
addNumber(10);//30
可以把函数名理解为指针,同一个函数名指向同一个指针。
函数声明与函数表达式的区别
1、函数声明是函数名跟在function后面,函数表达式是把一个函数赋值给一个变量;
2、函数声明可以在代码的任何位置,调用不受限制(可访问作用域),函数表达式必须在调用前定义。
console.log(addNumber(10));//20
function addNumber(num){
return num+10;
}
console.log(addNumber(10));//Uncaught TypeError: addNumber is not a function
var addNumber=function(num){
return num+10;
};
再看一段代码
function addNumber(num){
return num+10;
}
var addAnotherNumber=function addNumber(count){
return count+20;
}
console.log(addAnotherNumber.name);//addNumber
函数表达式不一定是匿名函数,定以后函数表达式的函数名是function后面的函数名。
重点注意:所有函数的参数都是按值传递
也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传递,则如同引用类型变量的复制一样。
要理解上面这段话有点费劲。既然是复制,不是基本类型复制后互不影响,引用类型复制后会互相影响吗,为什么是按值传递不是按引用传递?
在函数传递一个基本类型参数时,被传递的值会复制给函数内一个局部变量(arguments中的一个),传递一个引用类型的值时,会把该引用类型的指针地址复制给函数内一个局部变量,当局部变量发生变化时会反映在函数的外部。举个例子:
函数参数传递一个数字,函数内部修改后
function addNumber(num){
num=num+10;
console.log(num);//20
}
var num=10;
addNumber(num);
console.log(num);//10
如果传递的是一个object,在函数内部修改对象属性时,外部对象也发生变化了。
function setName(obj){
obj.name="李四"
console.log(obj.name);//李四
}
var obj={
name:"张三"
};
setName(obj);
console.log(obj);//obj.name="李四"
这不是与上面说的还值传递自相矛盾?我们修改几行代码再看:
function setName(obj){
obj.name="李四"
obj=new Object();
obj.name="王麻子";
console.log(obj.name);//王麻子
}
var obj={
name:"张三"
};
setName(obj);
console.log(obj);//obj.name="李四"
这段代码与上面的区别是obj传递给函数后,其属性name被重新赋值,创建一个新对象赋值给obj,再修改obj.name。如果obj是按引用传递,那么修改obj后应该也反映到函数外部,但原始引用并没有发生变化。原因是在函数内部重写obj后实际上创建了一个新的对象引用,该变量引用是局部变量,函数执行完后即被销毁。
总之,函数参数都是局部变量。
回到主题,JavaScript函数为什么是一等公民?
在编程语言中,一等公民有几个条件:可以作为函数参数,可以作为函数返回值,可以赋值给变量。
按照上面的条件,其实JavaScript中的数据都可以认为是一等公民~
无论是基础数据类型还是引用类型都是满足上面条件的。一般说JavaScript函数是一等公民实际上是相对其它编程语言而言,因为并不是所有的编程语言中函数都能满足上述条件。
下面具体介绍下JavaScript中函数是如何满足上述三个条件的。
函数作为参数
实际上就是我们经常说的函数回调。举个例子:
element.addEventListener(event,eventHandler,useCapture)
其中eventHandler就是作为函数参数,元素监听到对应事件后进行调用。这种情况在JavaScript中非常常见。比如ajax,promise等等。
函数作为返回值
比如闭包:
function getName(){
var name="jack";
return function(){
return name;
}
}
var getNameFun=getName();
var name=getNameFun();
console.log(name);//'jack'
正常情况下函数外部是无法访问函数内部变量的,但是通过返回一个引用函数内部变量的函数就可以实现,也就是我们常说的闭包。
函数作为变量
var getTime=function(){
console.log(new Date().getTime());
}
setInterval(getTime,1000);
将函数作为变量赋值给变量getTime,然后作为参数传递给setTimeInterval。
函数作为一等公民是函数式编程的基础。高阶函数就是将函数作为参数的函数,React中的高阶组件也可以理解是高阶函数。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。