Function类型(4.1)

本文深入探讨JavaScript中的函数特性,包括函数声明与表达式的区别、特殊对象arguments与this的应用、caller属性的功能,以及如何利用apply和call方法改变函数的执行上下文。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       说起来ECMAScript中什么最有意思,我想那莫过于函数了——而有意思的根源,则在于函数实际上是对象。每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。函数通常是使用函数声明语法定义的,如下面例子所示:

a.使用函数声明语法定义函数

 

function sum(num1, num2){
   return num1+num2;
}

 

b.使用函数表达式定义函数

var sum = function(num1, num2){
  return num1+num2;
};

     以上代码定义了变量sum并将其初始化为一个函数。有读者可能会注意到,function关键字后面没有函数名。这是因为在使用函数表达式定义函数时,没有必要使用函数名——通过变量sum即可以引用函数。另外,还要注意函数末尾有一个分号,就像声明其他变量时一样。

 

 c.最后一种定义函数的方式是使用Function构造函数。Function构造函数可以接受任意数量的参数,但最后一个参数始终都被看成是函数体,而前面的参数则枚举除了新函数的参数

      var sum = new Function(“num1”, “num2”, “return num1+num2”);//为什会解析2次呢?

      从技术角度讲,这是一个函数表达式。但是,我们不推荐读者使用这种方式定义函数,因为这种语法会导致解析两次代码(第一次是解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能。

 

函数声明与函数表达式

1.  解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行任何代码之前可用;至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

 

2.  在函数内部,有两个特殊的对象:arguments和this。其中,arguments是一个类数组对象,包含着传入函数中的所有参数。虽然arguments的主要用途是保存函数参数,但这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。

 

3.  函数内部的另外一个特殊对象是this,this引用的是函数据以执行的环境对象(当在网页的全局作用域中调用函数时,this对象引用的就是window)

 

<script type="text/javascript">
         function add(){
              if(window == this){//函数内部的另外一个特殊对象是this,在这里this指向的是全局执行环境
                    alert("window is this");
              }
         }
         add();
 </script>
 
<script type="text/javascript">
        var color = "red";
        function sayColor(){
             return this.color;
        }
        alert(sayColor());
        var obj = {nane : "高伟刚", age : 25, color : "blue"};//这里如果删除了color,会返回undefined。对象中没有属性,会返回undefined
        obj.say = sayColor;
        alert(obj.say());
</script>
 

 

3.caller这个属性中保存着调用当前函数的函数的引用

<script type="text/javascript">
        function say(args){
             sayColor(args);
        }
        function sayColor(args){
             alert(sayColor.caller);
        }
        say();//会弹出调用sayColor函数的函数
        sayColor();//null,全局作用域调用了sayColor函数,所以sayColor.caller == null
</script>

 

函数属性和方法

ECMAScript中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length和prototype。其中,length属性表示函数希望接收的命名参数的个数。

 

1.   在ECMAScript核心所定义的全部属性中,最耐人寻味的就要数prototype属性了。对于ECMAScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。换句话说,诸如toString()和valueof()等方法实际上都保存在prototype名下,只不过是通过各自对象的实例访问罢了。在创建自定义引用类型以及实现继承时,prototype属性的作用是极为重要的。

 

每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。首先,apply()方法接受两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是Array的实例,也可以是arguments对象

 

Call()方法与apply()方法的作用相同,它们的区别仅在于接受参数的方式不同

 

重点:事实上,传递参数并非apply()和call()真正的用武之地;它们正真强大的地方是能够扩充函数赖以运行的作用域。来看下面一个例子。

 <script type="text/javascript">
       function sum(num1, num2){
                alert(num1);//12
                alert(num2);//20
                alert(this.num3);//60
                return num1+num2;
        }
        var obj = {num3 : 60};
        function callSum(obj){
                return sum.apply(obj, arguments);//设置函数体sum中this对象的值为obj,apply和call用途都在特定的作用域中调用函数,实际上等级设置函数体内this对象的值
        }
        var count = callSum(12, 20);
</script>

 

每个函数继承的toLocaleString()和toString()方法始终都返回函数代码。返回函数代码的格式则因浏览器而异——有的返回的代码与源代码中的函数代码一样,而有的则返回函数代码的内部表示,即由解析器删除了注释并对某些代码作了改动后的代码。由于与源代码存在差异,我们无法根据这两个方法返回的结果来实现任何重要功能。另外一个继承的valueOf()方法同样也只能返回函数代码

 

Problem:

Javascript预编译

<script type="text/javascript"> 
	/*1.JavaScript"预编译"会先将变量x进行声明,但不会进行赋值。并且在进行所有操作之前,将函数add会进行预定义
	 *2."预编译"是一段一段的JavaScript代码来进行的
	 */
	alert(x);//undefined,在所有代码执行之前,x已经进行的"预编译"
	add(); //弹出undefined
	var x = 333;/*虽然在所有代码执行之前已经进行的"预编译"(即声明了x)了,但是并有对x赋值。当执行到这行时,才对x赋值,所以下一行调用add()函数时
				  会弹出333。而本上之上调用add(),由于并没有对x赋值,所以会弹出undefined
				*/
	add();//弹出333
	function add(){
	  alert(x);
	}
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值