IT虾米网

javascript 函数详解

lxf 2021年06月15日 编程语言 231 0

介绍

之前很长一段时间,我对js的函数使用不得法门,归根结底是没抓住函数是对象,函数是变量这一点。
js中的函数跟其他语言的函数基本上一样,注意这里,我用了基本上,也就是说并非完全相同,最大的不同点就是函数是对象,是变量,这一点决定了js函数的特性,比如没有重载、有方法、有属性等。啰嗦了这么一大顿无非是想让你记住函数是变量这一点,好了,开始js 函数之旅吧……

创建函数

创建函数有3种方式,分别为,声明式、表达式、构造方式。

创建方法

//声明式 
function f1(){
    
 
} 
 
//表达式 
f1=function(){
    
 
}; //注意这里有个分号,表示这是一个表达式 
 
//构造函数 
f1=new Function("",""); 
 

调用函数很简单,函数名加上(),如

f1();

声明式与表达式的区别

表达式是一条语句,只有执行到所在行,才会解析;
声明式,在执行语句前,解释器会在提前加载所有的函数到执行环境

f2();//执行到这一行之前,解释器已经预先加载了所有函数,所以不会出错。 
 
function f2(){
    
    console.log("f2"); 
}
f3();//执行到这一行时,f3还没有载入执行环境所以出错 
f3=function(){
    
    console.log("f3"); 
};

函数特点

函数是个对象,所以,也就决定了以下特点。

函数可以传递

因为函数是个值,是个变量,所以可以返回函数、传入函数。

function f1(){
    
    console.log("f1 executed..."); 
} 
 
function call_func(func_name){
    
    func_name(); 
} 
 
call_func(f1);//传入函数名f1,f1就会执行

函数没有重载

因为函数是一个对象,所以函数名就是一个变量,一个指针,变量永远指向某块内存。

function f1(name){
    
    console.log(name); 
} 
 
function f1(){
    
 
    console.log("f1"); 
 
} 
 
f1("myname");//输出结果f1

因为函数就是对象,所以上述代码等同于下边的代码

f1=new Function("name","console.log(name);");  
 
f1 =new Function("console.log(\"f1\")");

可以很清楚的看到f1重新创建了对象,不再指向原来的对象。

函数是没有参数的

这样称呼可能不是很严谨,js函数不像类C语言有方法签名,js中的函数的执行只靠函数名,而没有签名。

function f1(){
    
    console.log(arguments[0]); 
} 
 
f1("myname");//打印myname

通过这个例子可以看出,函数的执行是不关心参数;可以通过函数内部属性arguments获取到传入的参数。
arguments有个callee属性,指向当前函数。所以在阶乘函数中,我们通常,这样写

function factorial(num){
    
    if(num<=1){ 
        return 1; 
    }else{ 
        return num*arguments.callee(num-1);//arguments.callee指向当前函数 
    } 
}

虽然函数可以不声明参数而执行,但是可维护性出发, 函数声明带着参数。
函数还有一个很重要的内部属性就是大名鼎鼎的this,简单来说,this指向调用函数的对象,谁调用函数,谁就是this。比如

function f1(){ 
    console.log(this.x); 
} 
 
x=1; 
f1(); //this指向global,所以x等于1; 
 
var o={}; 
o.method=f1; 
o.x=2; 
o.method();//this指向o,所以x等于2

函数属性

函数有两个属性,length和prototype;length表示函数预期的参数个数。

function f1(){
    
    console.log("f1 executed..."); 
} 
 
function f2(a,b,c){
    
 
} 
 
console.log(f1.length);//输出0 
console.log(f2.length);//输出3

prototype,我还没研究清楚,回头再补。目前的理解程度是,原型就是函数的父类,这么个概念。

call和apply

函数有两个不是继承二来,但是非常著名的方法,call和apply,这两个方法作用相同,都是执行函数。

apply(scope,[arg2,arg3,arg4]) 
call(scope,arg2,arg3,arg4...) 

第一个参数都是作用域;第二个参数略有不同,apply是数组;call是一个个的参数,罗列出来。

function f1(a,b,c){
    
    console.log(a+" "+b+" "+c); 
} 
 
 
f1.apply(this,[1,2,3]);//输出1 2 3 
f1.call(this,1,2,3);//输出1 2 3

你一定纳闷了,直接f1(1,2,3)执行函数就行了,何必搞的这么辛苦用apply/call。问的好!apply和call的最大作用就是改变了执行作用域,也就是改变了函数的内部属性this。

function f1(){
    
    console.log(this.a+" "+this.b+" "+this.c); 
} 
 
var o1={a:1,b:1,c:1} 
var o2={a:2,b:2,c:2} 
 
f1.apply(o1);//输出1 1 1 
f1.call(o2);//2 2 2

看见了吧,this变了,传入o1的时候,this就是o1,;传入o2的时候,this就是o2;

总结

  • 函数是对象,是变量,是指针
  • 内部属性,arguments和this
  • 函数的方法,apply和call

参考

javascript高级程序设计第二版


发布评论
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

javascript escape、encodeURI、encodeURIComponent详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。