函数介绍
1.什么是函数
函数就是一次封装,四处调用的代码。
函数分为命名函数和匿名函数
2.js中的函数传参和其他语言的区别?
js中传的实参个数,和函数期望的参数个数可以不一致。
3.函数调用时发生了什么?
每一次调用函数都会创建一个全新的局部作用域。
4.为什么使用函数呢?
除了代码的复用,我觉得最大的好处就是减少了代码细节的暴露,增强了代码的可读性。
举个例子
//按照季节做事
function doSomethings(month){
if(3<=month && month<=5){
//春天
//春游
}else if(6<=month && month<=8){
//夏天
//避暑
}else if(9<=month && month<=11){
//秋天
//秋游
}else{
//冬天
}
}
上面的代码可读性不是太好,时间长了后再看需要反应一会。
但是修改后。
function isSpring(month){
return 3<=month && month<=5;
}
function isSummer(month){
return 6<=month && month<=8;
}
function isAutumn(month){
return 9<=month && month<=11;
}
function doSomethings(month){
if(isSpring(month)){
//春天
//春游
}else if(isSummer(month)){
//夏天
//避暑
}else if(isAutumn(month)){
//秋天
//秋游
}else{
//冬天
}
}
虽然代码量增加了,但是代码的可读性变好了,一读函数名就知道要干什么。所以适当的封装函数是有助于代码的可读性的。
5.什么时候使用函数?
- 当程序有太多相同的代码的时候。
- 当程序暴露了过多的细节,使可读性变差,就应该使用函数将细节分装起来。
一、函数的本质(重点)
- 函数的本质就是对象。
- 函数可以作为数据值来赋值
- 函数作为参数
- 函数作为返回值
- 函数可以添加属性和方法
1.1 函数的本质是对象
我们都知道对象是保存在堆内存当中的,在栈内存当中开辟一个房间,房间中保存了指向对象的指针(地址),房间名就是变量名。而函数的本质是对象,函数名 本身保存的就是函数所在 堆内存的地址,也就是那个房间名。
function fn(){
} fn保存的是地址
所以。。。可以将 函数 保存在变量中,变量里存储的就是这个 函数 (对象)的在堆内存的地址。
var add = function fn(){
} 这样写是可以,下面4.3.3会讲
上面的那种写法也可以,只不过函数名fn
就变成了局部变量了,只能在函数内部调用,一般情况下没什么用,所以我们都会舍弃函数名,对外访问使用变量名。如下:
var add = function(){
}
add(); 我们可以正常调用函数
console.log(add) 也可以直接获取函数的本体:function(){
}
ps:使用var定义函数有一个缺点:函数调用只能在函数声明的后面,这就涉及到js预解析的知识。
js预解析的相关知识
错误示例
add();
var add = function(){
}
在预解析阶段会先 函数声明 提升 再 变量声明 提升 ,赋值操作原地等待。所以就相当于
var add; 这里只有add这个变量,该变量的值为underfined
add(); 这里却要调用add这个方法,而上面只有add变量,所以会报错
add = function(){
} 到这一步才将变量的地址赋给add
1.2 函数作为数据值来赋值
函数的本质是对象。
函数要调用就必须加上(),不加()只是把函数当做数据值。
在1.1说过函数的本质是对象,
所以函数可以这样玩:
var person = {
name: 'poorpenguin',
speak: function(){
alert('hello world!');
}
}
调用函数
person.speak();
也可以这样玩:
var arr = [
'abc',
function(){
console.log(1);
}
]
arr[1]();
1.3 函数作为参数
函数的本质是对象。
函数要调用就必须加上(),不加()只是把函数当做数据值。
函数作为参数的例子我们很常见,就是定时器这一类的。
setTimeout(fn,1000); 将fn这个函数作为数据值传入定时器,1秒后将传入的数据值作为函数执行
function fn(){
console.log(1)};
或者
setTimeout(function(){
},1000)
但是一旦在函数名后加上()就表示立即调用了。
错误事例
setTimeout(fn(),1000); 立即调用fn函数
function fn(){
}
1.4 函数作为返回值
函数的本质是对象。
直接上案例
function fn(){
return function(){
console.log(1);
}
}
var newFn = fn(); 变量newFn会得到return后面返回的函数体。
newFn(); 调用新函数,控制台打印1
或者
function fn(){
return function(){
console.log(1);
}
}
fn()(); 这样也可以
1.5 函数添加属性和方法
函数的本质是对象。
所以函数是可以添加属性和方法。 万物皆对象。
function add(num1,num2){
return num1+num2;
}
add.name = 'poorpenguin';
add.sex = 'nan';
add.setSex = function(sex){
this.sex = sex;
return this.sex;
}
console.log(add.sex); 输出nan
console.log(add.setSex('male')); 输出male
console.log(add.sex); 输出male
console.log(add(1,2)); 3
总结:所以想要深入的了解函数,玩转函数,除了知道函数的本质是对象这一特性外,还要了解JS的解析机制、作用域。
js预解析的相关知识
二、函数的定义
函数有三种定义方式
- 函数声明
- 构造函数
- 赋值表达式
函数定义类型: | 函数声明 | 构造函数 | 赋值表达式 |
---|---|---|---|
例子: | function fn(){}; | var fn = new Function(){}; | var fn = function(){}; |
- | 函数声明 | 赋值语句 | 赋值语句 |
特点: | 简洁,直观 | 多此一举,效率低下 | 简洁,直观 |
定义位置 | js解析阶段会进行函数提升,所以在哪定义都可以 | 必须在调用语句之前 | 必须在调用语句之前 |
2.1 函数声明
function add(num1,num2){
return num1+num2;
}
fn();
2.2 构造函数(建议不要使用)
注意:形参和语句都是字符串。
var add = new Function('num1','num2','return num1+num2;');
add();
计算21 * 32 + 24 / 3 - 5