javascript应该注意的小case--函数

每个函数都是function类型的实例

首先让我们来理解这句话:每个函数其实是function类型的实例。也就是说我们声明的函数都是对象,有自己的属性和方法,函数名不过是指向该对象的一个指针

看下面这个例子:

?
1
2
3
4
5
6
7
8
9
function myfuc(arg) {
       alert(arg);
   }
 
   var anfuc = myfuc;
 
   myfuc = null ;
 
   anfuc(1);  //  报错,还是弹出1??

 

结果是弹出1,myfuc不过是指向我们函数对象的一个指针,它指向null之后,并不影响anfuc的,因此调用无影响。

 

函数的内部属性

arguments和this:arguments是一个类数组对象,它包含调用函数时传入的所有参数,你在函数里可以用arguments[0]、arguments[1]…来访问传入参数;此外,它还有一个属性callee,它也也是一个指针,指向拥有这个arguments对象的函数,这个属性在我们递归中相当有用,比直接的函数名易维护且健壮。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function myfuc(arg) {
      if (arg <= 1) {
          return 1;
      } else {
          return arg + myfuc(arg - 1);
      }
  }
 
  function anfuc(arg) {
      if (arg <= 1) {
          return 1;
      } else {
          return arg + arguments.callee(arg - 1);
      }
  }

 

这两个函数虽然写法上有点不一样,但是是相同的目的,在这里强烈推荐采用第二种:在任何时候你想修改该函数名,只需要修改声明即可,同时看下边的例子。

?
1
2
3
4
5
6
7
var myfuc2 = myfuc;
var anfuc2 = anfuc;
 
myfuc = null ; anfuc = null ;
 
alert(anfuc2(3));  //  弹出6
alert(myfuc2(3));  // 没弹出,并报错

 

myfuc2的调用中,递归时还去寻找myfuc调用,但是早已“物是人非”了,而anfuc2里arguments.callee始终指向当前调用的函数,也就是anfuc2。

 

this属性,函数执行时,指向其执行所在的作用域,正确的理解它的意义是很重要的。

 

?
1
2
3
4
5
6
7
8
9
10
11
var name = "window" ;
function sayName() {
     alert( this .name);
}
 
var o = new Object();
o.name = "object" ;
o.sayName = sayName;
 
sayName();  //  弹出window
o.sayName();  //弹出 object

 

尽管sayName和o.sayName指向同个对象,但是他们的调用确输出了不一样的结果。我们知道,我们声明的全局变量和函数是属于window的,其实相当于window.name,window.sayName,而这个this动态的指向了拥有该方法的对象。

 

函数的属性和方法

刚刚介绍的是在函数休内才能使用的属性,而既然函数是对象,那么它肯定有可供我们使用的属性和方法。

length属性:函数声明时希望接受到参数的个数。

prototype属性:这个。。这个。。这个是js强大所在,它不仅能让js比较完美的实现“类”、具有一些面向对象语言的一些特性如继承等,更能扩展内置对象所不具备的功能和属性。

apply方法和call方法:这两个方法都是让函数“自己调用自己”的,只不过传参方式不一样而已。

 

没有重载的重载

js是没有重载的,试图重载都会覆盖有前一个的函数声明,不过通过js的特性,我们可以实现类似重载的一些特性。由于函数是对象,声明不过是指向该对象的指针而已,因些js在定位函数时只会根据函数名,根本不会考虑你传的参数,因此我们可以用以下两种方式实现类似重载,这两种方式本质是一样的,只是表现形式上的差别。

1,arguments

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function sayHi() {
      var result = "default" ;
      if (arguments[0]) {
          result = arguments[0];
      }
      if (arguments[1]) {
          result += arguments[1];
      }
      if (arguments[2]) {
          result += arguments[2];
      }
      if (arguments[3]) {
          result += arguments[3];
      }
      // 此处你甚至可以遍历arguments来支持无限的参数
      return result;
  }
 
  alert(sayHi( "a" ));  //  a
  alert(sayHi( "a" , "b" ));  // ab
  alert(sayHi( "a" , "b" , "c" ));  //abc

 

从调用上来看,是不是实现了重载。

2,声明所有参数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function sayHi(a,b,c /*还可以更多*/ ) {
         var result = "default" ;
         if (a) {
             result = a;
         }
         if (b) {
             result += b;
         }
         if (c) {
             result += c;
         }
         // 如果还有可以支持更多
         return result;
     }

 

调用是一样的,结果也是一样的。

 

第一种方式更灵活,第二种则更易读,对调用者来说更友好。推荐一般参数不多的话,使用第二种,如果要支持无限参数,只有采用第一种。极度不推荐两种混用,那会让代码结非常乱,维护和以后扩展都会有不少麻烦。

 

函数的创建方式

一般来说我们有两种方式创建函数:

1,函数声明方式:function func(){}

2,函数表达式:var func = function(){}

 

这两种难道就只是表现形式的差别吗??当然不是,解析器在解析js时,会优先处理函数声明,会在所有任何需要执行的代码之前让函数可用;而函数表达式只有在执行到所有行时,才会被解析执行。

也就是说:

?
1
2
3
4
sayHi();
    function sayHi() {
        alert( "hi" );
    }

 

这样的方式,代码是没问题的,并且会弹出hi.

但是

?
1
2
3
4
sayHi();
     var sayHi = function () {
         alert( "hi" );
     }

 

这种方式,会报错,缺少对象。

 

匿名函数和闭包

匿名函数也称做lambda函数,一般情况下,我们会在以下几种情况下会用到匿名函数:

1,回调函数

2,函数做为返回值

3,插件形式的开发

如我们经常看到的如:

?
1
2
3
4
5
6
7
8
9
10
11
( function (){
  
     //  代码
  
})();
  
( function ($){
  
     //  代码
  
})(jQuery);

 

第二个是jquery推荐的插件开发的方式,这里声明一个匿名函数,然后立即执行。函数内部声明变量和函数,除了绑定给全局变量的一些变量和函数,我们在外部是不能访问,起到隔离性的作用,不会对页面造成影响,内部没有闭包的存在,函数执行完毕后,变量函数就会被回收。

 

很多的匿名函数往往能看到闭包的身影,闭包又是什么?

看一个例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
function createFunc(){
      
     var name = "123" ;
  
     return function (){
         alert(name);
     };
  
}
  
var func = createFunc();
  
func(); //  弹出123

 

这是一个闭包的简单例子,createFunc返回了一个匿名函数,一般情况下,一个函数执行完毕后,其内部变量就会被回收,但是createFunc返回的函数里却保持着对内部变量name的引用,因些我们在外部调用然后执行func,仍然可以使用,只要func存在,我们执行createFunc时所创建的内部变量就会处于内存中的一个位置,直到我们显示的设置func = null,这次createFunc()创建的name才会被回收。

 

闭包就是有权访问另一个函数作用域变量的函数。它会让另一个函数内部的变量仍然处理有效的状态,这有时会为我们带来莫大的方便,但是我们有时可能要考虑闭包的使用:就是因为闭包的存在,函数执行完毕后,其内部所有的变量就不能被立即回收,仍然处于内存中。

 

js的函数即独特又很重要,用其它语言的方式使用js的函数,即不能体现出它的强大,有时还可能陷入困惑。它也使js强大,使得js具备一些封装、继承等高级特性,更有利于我们开发健壮、易维护的应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值