简介
今天我读了javascript高级程序第三版的第5章,5.5Function类型
函数实际上是个对象,每个函数都是Function类型的实例,
由于函数是是对象,因此函数名实际上也是一个指向函数对象的指针
函数的声明与函数表达式
什么是函数的声明?什么是函数的表达式?
-
如下例子就是
函数的声明
来定义函数-
function sum (num1,num2){ return num1 +num2 }
- 调用也非常简单 sum(1,2)
-
-
如下例子就是
函数的表达式
定义函数-
var sum = function (num1,num2){ return num1 +num2 }
- 通过sum变量,来引用我们的函数 就像这样
sum(1,2)
- 通过sum变量,来引用我们的函数 就像这样
-
-
当然我们也可以这样子来定义函数
-
var sun = new Function('num1','num2','return num1 + num2') //但是我们是不推荐这样子写的
- 只是这种语法便于我们理解
函数是对象, 函数名时指针
- 只是这种语法便于我们理解
-
大概这样吧
函数仅仅只是指向函数的指针,函数名与包含其他对象指针的其他变量没有什么不同
-
如下例子
-
function sum(num1,num2){ return num1 + num2; } console.log(sum(10,10)) //20 var anotherSum = sum; console.log(anotherSum(10,10)); //20 sum = null; console.log(anotherSum(10,10)); //20 console.log(sum()) //sum is not a function
- 第10行代码的sum 重新指向了 null ,所以sum为null了
-
大概是这样吧
函数声明和函数表达式的区别
红宝书这样解释道
实际上,解析器在向执行环境加载数据时,对函数的命名和函数的表达式并非一视同仁的.解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问)
,至于表达式,则必须等到解析器执行到它所在的代码行,才会真正的被解释执行
//函数声明
console.log(sum(1,2)); //3
function sum(num1,num2){
return num1 + num2;
}
//函数表达式
console.log(sum(1,2)); //sum is not function
var sum = function (num1,num2){
return num1 + num2;
}
//console.log(sum(1,2)); //这样才会执行
我的理解就是函数声明 Javascript 引擎会把声明函数提升 到顶部,而函数表达式 则不会,只有执行到了所在代码才会被解析执行
作为值传入的函数
红宝书这样解释道
函数名本身就是变量
,所以函数也可以作为值来使用,也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回
-
函数名本身就是一个变量,可以作为值来使用
-
function fn(num){ return num + 100 } console.log(fn.toString()); /* 输出 function fn(num){ return num + 100 } */
-
-
可以像传递参数一样把一个函数传递给另一个函数
-
function fn(num){ return num + 100 } function handle(SomeFunction,value){ console.log(SomeFunction); //[Function: fn] }
-
-
可以将一个函数作为另一个函数的结果返回
-
function fn(num){ return num + 100 } function handle(SomeFunction,value){ return SomeFunction(value) /* 感觉应该是相当于这样子吧 (function (num){ return num + 100 })(value) */ } console.log(handle(fn,10));
-
函数内部的属性
红宝书这样解释道
在函数的内部有两个特殊的对象:arguments
和this
.虽然arguments 的主要用途是保存函数的参数
,但是这个对象还有一个名叫callee的属性
,该属性是一个指针
,指向拥有这个arguments对象的函数
我们来看一个例子
function sum(num){
if(num <= 1){
return 1
}else{
return num*sum(num-1)
}
}
var fn = sum
sum = function(){ //sum重新指向了一个函数 return 0
return 0
}
console.log(sum(5)); //0
console.log(fn(5)); //0
在此.变量fn获取到了sum,实际上是在另一个位置上保存了一个函数的指针,然后sum又重新赋值了return 0 ,因此我们定义的递归函数 内部调用的还是 sum 所以 fn() 也会返回0,如果我们递归函数 内部调用的是递归自己本身 而不是sum 函数 ,就可以解除函数执行和函数名 紧密耦合的现象
如果我们使用了arguments的属性callee
function sum(num){
if(num <= 1){
return 1
}else{
return num*arguments.callee(num-1)
}
}
var fn = sum
sum = function(){
return 0
}
console.log(sum(5)); //0
console.log(fn(5));//120
总之,我们一定要记住,函数的名字仅仅只是一个包含指针的变量而已
红宝书给的解释 ECMAScript也规范了另一个函数对象的属性:caller。这个属性保存着调用当前函数的引用,如果是在全局作用域中调用当前函数,它的值为null。为了实现更松散的耦合,也可以通过argument.callee.caller来访问相同的信息