深入解析JavaScript函数:指针、直接量、成员与闭包机制
本文深入解析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“公式化”的基本原则。
不过,实际上上面这种函数倒有一个特殊用途,用来生成某些特殊的计数器。
所以限制也不是绝对的...
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
