深入解析JavaScript函数:指针、直接量、成员与闭包机制

作者:代码拾荒

时间:2026-10-30

浏览:529

本文深入解析JavaScript函数的核心机制,涵盖函数作为可执行对象与指针的本质,辨析函数直接量的语法用法,详解apply、call及原型等内置成员,并重点剖析函数作用域、this指针指向及闭包的形成与访问限制,帮助开发者准确理解函数执行上下文与资源访问边界。

文章目录

函数对象与函数指针

1. 函数对象与函数指针


在JavaScript中,函数本质上是一个可执行的对象,而任何访问该函数对象的方式均通过函数指针实现。


无论采用以下哪种定义方式:


var a=new Function(...);


function a(...){...}


var a=function(...){...}


所生成的函数名a始终是一个指向函数的指针,可以通过var b=a;语句创建另一个指向同一函数的指针。


由于这些指针指向同一段函数代码,且函数名本身即为指针,因此函数可以作为参数进行传递。


当()运算符作用于一个函数指针时,将执行该指针所指向的函数,并传入相应的参数。




函数直接量语法解析

2. 函数直接量(函数文字量)


虽然“函数直接量”这一术语在严格意义上并不准确,但它可以通俗地解释某些特定用法。


数字125和字符串"good"均为直接量,可以在代码中不通过变量名直接使用;函数也存在类似的用法。


function(){...}代表了一个函数指针的值,该指针指向由function(){...}定义的函数。


因此,(function(){...})()执行了这个函数,而a=function(){...}则创建了该指针的一个副本。



函数对象的内置成员与方法

3. 函数对象的成员


函数对象继承自Object对象,同时拥有其自身的属性和方法。


以下信息来源于VS2005的代码提示:


f.apply(thisValue,argArray);//在thisValue对象上执行,参数由数组argArray提供


f.call(thisValue);//在thisValue对象上执行,若无参数则不传参,若有参数需直接跟在thisValue后面


f.prototype; //原型,非常常见,前文已提及,此处不再赘述。


f.length;//参数列表的长度



f.hasOwnProperty(propertyName);//继承自Object的方法,用于检查对象是否包含指定属性


f.propertyIsEnumerable(propertyName);//继承自Object的方法,用于检查指定属性是否可被for in枚举(除Firefox下的prototype外,其他属性均不可被枚举)


f.toLocaleString();//继承自Object的方法,将对象转换为字符串


f.toString();//继承自Object的方法,将对象转换为字符串,在alert、document.write等场景中会自动调用


f.valueOf();//继承自Object的方法,用于求值,对象进行算术运算时会自动调用,若默认行为为toString则返回字符串



函数访问范围与三组参数

3. JavaScript函数能访问的范围


JavaScript函数究竟能访问哪些资源?主要包括三部分:函数的作用域、this指针、参数。除此之外,函数无法访问任何其他资源。


为了更清晰地理解函数,应当将函数想象为拥有三组参数:


第一组是作用域,在定义时确定,由函数定义的位置决定,暂称为外作用域。在函数定义处可以访问的变量和函数,在函数内部也可以访问,无论调用该函数的指针被传递到哪里。


第二组是this,在函数被调用时确定。


如果函数是用()调用的,它默认指向函数所属的对象:如果函数是某个对象的成员,那么this指向这个对象;否则,this指向全局对象(大多数时候是window)。


如果函数是用apply或者call调用的,this指向指定的thisValue。


第三组是参数,在函数被调用时确定。在参数列表中的参数可以直接访问,不在参数列表中的参数可以通过arguments对象访问。



函数作用域生成与闭包机制

4. 函数作用域的生成与访问


函数除了能够访问一个作用域之外,每次执行还会生成一个新的作用域(即闭包)。


此作用域之外的代码无法访问这一作用域内的变量,而此作用域内的代码可以访问这个作用域以及函数定义时的作用域。



跨作用域的访问只能通过指针进行,在JavaScript中,object是指针类型。


想要获得指向某个作用域的指针,必须从该作用域中将指针传递出来:即将此作用域中的指针类型变量的值赋给其他作用域的变量。


前文所述一个函数中能够访问的资源包括this、外作用域、参数,因此可以通过这种方式访问其他作用域中的变量。


一个较为极端的例子:



[[t41]]


最后这个例子过于极端,实际上,虽然JavaScript的function具备这样的能力,但在使用时我们通常会有一个限制:闭包中访问闭包外变量时,不应当采用有“副作用”的表达式,例如++、--或者赋值。也就是说,限制闭包访问外部域的内容仅限于“读”和“表达式计算”,可以修改外部变量实际引用的对象的值,但是不要在闭包内修改外部变量本身的值。所以下面的例子:


function c(a){


return function(x)


    {

return x+a++;


    }
}

通常是合法但不合理的,因为这是一个有副作用的闭包。在程序逻辑复杂的情况下,这很容易导致混乱。因为这个闭包在什么时候调用是完全不确定的。这个闭包的存在使得这个函数每次调用的返回值完全不同,即使采用的是同一个参数。这显然违背了functional“公式化”的基本原则。



不过,实际上上面这种函数倒有一个特殊用途,用来生成某些特殊的计数器。


所以限制也不是绝对的...

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章