Javascript学习---1、函数

it2022-05-09  36

    在很多语言中,函数(Java里面成为方法)和对象时截然不同的两种东西。函数被定义为对象的动作。但是在JavaScript中,函数实际上也是对象,与其他的引用类型一样,可以具有属性和方法。

1、函数的声明

函数的声明比较简单,可以通过2种方式进行声明:函数声明式和函数表达式(其实还有第三种Function构造函数方式,但是我们基本不用,所以不提也罢)

      1.1  函数声明式。最常用的方式了,如下所示的例子:

1: function sum(num1,num2) 2: { 3: return num1 + num2; 4: }

注意:函数名实际上也是一个指向函数对象的指针,而不会与某个函数绑定。

      1.2  函数表达式。和函数声明式基本相同。如下所示:

1: var sum = function(num1,num2) { 2: return num1 + num2; 3: ;

   上述代码定义了变量sum,并将其初始化为1个函数。当然,此处函数的定义采用了匿名函数的方式。另外注意语句的最后还有个分号,就像声明其他变量时一样;

    由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同。如下代码所示:

1: function sum(num1,num2) 2: { 3: return num1+num2; 4: } 5: alert(sum(10,10)); //20 6: var anotherSum=sum; //anotherSum和sum指向了同一个函数 7: alert(another(10,10)); //20 8: sum =null; //sum设为null,并不会影响anotherSum 9: alert(another(10,10)); //20

注意:在第6行中,使用不带括号的函数名是访问函数指针,而带括号则是调用函数!

 

      1.3 函数声明与函数表达式的区别

解析器在向执行环境加载数据时,对函数声明和函数表达式并非一视同仁。其主要差别在于: 解析器会率先读取函数声明,并使其在执行代码前可用,至于函数表达式则必须等到解析器执行到它所在的代码行,才会被真正执行。 1: alert(sum(10,10)); 2: function sum(num1,num2){ 3: return num1+num2; 4: }   以上代码,完全可以正常运行。因为在代码开始执行alert之前,解析器已经已经完全读取了函数声明,并将其添加到执行环境里去了。而如果如下,把函数声明改为函数表达式方式,就会出现错误。   1: alert(sum(10,10)); 2: var sum=function(num1,num2) 3: { 4: return num1+num2; 5: }; 上述代码之所以会出现问题,原因就在于使用了函数表达式声明了函数。在代码执行到第2行函数表达式之前,变量sum不会保存对函数的引用。而且由于第一行就运行出错,实际上也不会运行到第2行了。 2、理解函数的一些要点 2.1  函数没有重载 函数没有重载的主要原因,就如上曾经提到的函数名其实是一个指向函数对象的指针。如下所示的例子: 1: function add(num){ 2: return num+100; 3: } 4: function add(num){ 5: return num+200; 6: } 7: var result=add(100); 8: alert(result); 显然,例子中定义了2个同名函数,最后起作用的将是最后一个,后面的函数覆盖了前面的函数。(Javascript并非完全的按顺序解释执行,而是在解释之前会对Javascript进行一次“预编译”)   2.2 函数的内部属性 在函数内部,定义了2个特殊的对象arguments和this. 1、arguments:数组类型的对象,存放着传入函数中的所有参数;同时,该函数还有1个属性callee,该属性为一个指针,指向拥有该arguments对象的函数; 如下所示的一个经典的阶乘函数: 1: function factorial(num){ 2: if(num<=1) 3: return 1; 4: else 5: return num*factorial(num-1); 6: }

      该阶乘函数执行起来是没有问题的,但是它也存在一个问题:函数的执行和函数名factorial(第5行所用)紧紧耦合在一起。此时,可以使用arguments.callee属性进行改善,如下所示:

1: function factorial(num) 2: { 3: if(num<=1) 4: return 1; 5: else 6: return num*arguments.callee(num-1); 7: }

       改善的代码提高了代码的可复用性了。

      2、this:this是Javascript中非常有用的一个特殊对象,其作用大致和java、c#中的this类似。this引用的是函数据以执行操作的对象-或者可以说,this是函数在执行时所处的作用域。(当在网页的全局作用域中调用时,this对象引用的window)

1: window.color="red"; 2: var o ={color:"blue";} 3: function sayColor(){ 4: alert(this.color); 5: } 6: sayColor(); //“red”,在全局作用域中调用,this指向window 7: o.sayColor=sayColor; 8: o.sayColor(); //“blue”   此时this指的当然就是o了

      注意:

函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的执行环境中,全局的sayColor函数与o.sayColor指向的仍然是同一个函数!
  2.3 函数属性和方法   之前提到过,函数也是对象,因此函数也具有属性和方法。 每个函数都有2个属性:length和prototype属性。 1、length:表示函数希望接收的命名参数的个数;如下代码所示: 1: function sayName(name){ 2: alert(name) 3: } 4: function sum(n1,n2){ 5: return n1+n2; 6: } 7: alert(sayName.length);//output :1 8: alert(sum.length); //output:2   2、prototype:prototype属性是ECMAScript核心所定义的全部属性中可以说最耐人寻味的属性了。它是实现javascript面向对象编程的核心和基础,用于创建自定义引用类型和实现继承。后续单独介绍。 每个函数也包含2个方法:apply和call方法。 这2个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值。只是二者的调用方法稍有不同。语法格式如下所示。 call方法:

call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 参数 thisObj:可选项。将被用作当前对象的对象。 arg1, arg2,  , argN:可选项。将被传递方法参数序列。

apply方法

apply([thisObj[,argArray]]) 参数 thisObj:可选项。将被用作当前对象的对象。 argArray:可选项。将被传递给该函数的参数数组。

  对于这2个方法,《javascript高级程序设计II》上列举如下例子: 1: function sum(n1,n2){ 2: return n1+ n2; 3: } 4: function callsum(n1,n2){ 5: return sum.call(this,n1,n2); 6: } 7: alert(callsum(10,20)); //output 30 感觉这个例子举得不是很好,在第5行sum.call时,由于该行位于callsum内,因此此时的this指的是callsum,所以如果sum函数体内有this的应用的话,相应的this即被替换成callsum。然而在代码中,sum函数内并没有使用this,因此也就没有了应用call方法的意义了。 代码更改一下,以体验call方法的作用(即设置函数体内的this的值或者说更改函数赖以运行的作用域)。   1: var number =10; 2: function sum(n1,n2){ 3: return this.number + n1+ n2; 4:  5: function callsum(n1,n2){ 6: this.number =20; 7: return sum.call(this,n1,n2); 8:  9: alert(sum(10,20)); //output 40 10: alert(callsum(10,20)); //output 50

  上述代码中,为什么sum(10,20)会输出40呢?由于sum函数处于全局作用域中,因为在执行sum时,this指向的对象即为window,而var number=10,其实等价于var window.number=10,因此输出40。而在调用callsum时,在callsum函数内部先定义了一个它的属性this.number=20,而后,在执行sum.call语句时,那个this所指的自然是目前所在的函数callsum,因此在执行sum函数时,sum函数内的this所指的就是callsum,而callsum.number=20,因此最终结果为50了。

     不好意思,,《javascript高级程序设计II》中也列举了相应的示例用来说明call和apply的主要用途的例子。代码如下:

1: window.color="red" ; 2: var o={color:"blue"}; 3: function sayColor(){ 4: alert(this.color); 5: } 6: sayColor(); //outpu: red 7: sayColor.call(this);//output:red 8: sayColor.call(window);//output:red 9: sayColor.call(o);//output:blue

这个虽然比较简单,但是对于call的用法其实展示的比较清楚了。

第6行直接调用sayColor()时,因为此时是在全局作用域中进行调用的,因此函数体内的this指向的就是window这个全局对象,所以输出的其实是window.color;

第7,8行其实是等同的。因为在全局作用域中的this就是window;

第9行则是最具代表性的。在执行sayColor.call(o)时,sayColor函数体内的this对象指向了o,因此输出blue.

 

 

主要参考:《javascript高级程序设计第二版》

               

转载于:https://www.cnblogs.com/lzm525/archive/2010/12/09/1901588.html


最新回复(0)