三、js函数特性
1、参数可边长函数
function main(arg1,arg2) {
alert(arg1);
}
// 可以传递任意多个参数
main(1);
main(1,2);
main(1,2,3);
...
- 也可以不给函数定义形参,直接用
arguments
属性来接受实际传入的参数数组。
function main(){
var args = arguments;
// 4
alert(args.length);
// 1
alert(args[0]);
}
main(1,2,3,7);
2、函数不能重载
- 后面的函数会覆盖掉前面的函数
js中不会像java中,根据传入的参数来判断选择哪个函数,因为在js中,所有的方法都是可变长度的
此外,javascript是一种解释执行的语言,在浏览器的脚本引擎开始载入你的js代码时,必然会进行“扫描”,然后再开始解释执行,在这个过程中,“标识符解析”是一个必不可少的重要操作,它要求同一命名空间中不允许有同名的变量存在,函数也是。
function myFunc(){
alert("func1");
}
function myFunc(arg){
alert("func2");
}
function myFunc(){
alert("func3");
}
// func3
myFunc();
// func3
myFunc(3);
3、函数嵌套
3.1 内部函数
当外部函数 outerFunc调用结束之后,innerFunc函数也会从内存中消失,不会留下任何的痕迹。而且,对于outerFunc函数外部的代码来说,innerFunc函数是不存在的,不可见。
function outerFunc(){
function innerFunc(){
alert("innerFunc");
}
innerFunc();
alert("outerFunc");
}
outerFunc();
- 如何让外部代码调用内部函数
词法作用域:对于innerFunc来说,outerFunc函数大括号里面的“封闭区域”就叫做innerFunc的词法作用域。
function outerFunc() {
function innerFunc() {
alert("innerFunc");
}
// 返回一个函数指针
return innerFunc;
}
var cache = outerFunc();
cache();
-
当执行
cache()
的时候,按道理,变量name
应该随着var cache = outerFunc();
中outerFunc函数的执行完毕而不存在,但是依然能够获取到name的属性值,说明- innerFunc 在实际执行的时候,一定还在它的词法作用域中,即outerFunc函数的内部,否则它不可能访问到name
- 说明name还没有被内存回收,或者name被存储在某个地方(后续具体介绍)。
var outerName = "outerName";
function outerFunc() {
var name = "name";
function innerFunc() {
alert("outerName = " + outerName + ", " + "name = " + name);
}
// 返回一个函数指针
return innerFunc;
}
var cache = outerFunc();
// "outerName = outerName, name = name
cache();
4、call/apply/自执行
会看到两次输出的
this.name
的值是不一样的,这就是javascript的动态性(javascript是一门动态语言)
java中的
this
总是指向当前对象,而javascript中的this
并不一定指向特定的对象,它是可变的。
function myFunc() {
alert(this.name);
}
// 小明
myFunc.call({name:"小明"});
// 小三
myFunc.apply({name:"小三"});
-
call()、apply()的比较
-
call 和 apply 都可以接收两个参数,第一个参数为函数中
this
需要绑定的对象,因此对于第一个参数的处理,call与apply是一致的。 -
但对于第二个参数就不同了,call的第二个参数使用的是可变长度参数,但apply 的第二个参数是一个数组。
-
myfunc.call({},var1,var2,var3...);
myFunc.apply({},[var1,var2,var3]);
5、函数也是数据,也是对象
5.1 函数是数据
- 1
function myFunc() {
alert("this is my funcion");
}
// 输出
//
// function myFunc() {
// alert("this is my funcion");
// }
alert(myFunc);
- 2
var myFunc = function() {
alert("this is my funcion");
}
// 输出
//
// function myFunc() {
// alert("this is my funcion");
// }
alert(myFunc);
-
1 和 2 的比较
-
效果完全相同
-
构造时机不同:1 和 2 两个例子的运行结果虽然是相同的,但是他们的运行细节确实不相同的,1 中直接声明了一个函数,这个函数会在脚本引擎解析期间创建,而 2 中的方式其实是定义了一个变量,而不是函数,所以,只有在脚本真正被执行的时候,函数才会真正的被创建出来。
-
5.2 函数是对象
- 1 利用内置构造器 Function 创建一个函数
var fn = new Function('x', 'y', 'alert("Just coding!")');
// true
alert(fn instanceof Object);
// Just coding!
fn();
- 2
var fn = = function() {
alert("Just coding!");
}
// true
alert(fn instanceof Object);
// Just coding!
fn();
Function 的构造器可以接受任意多个参数,最后一个参数会被当作“函数体”,之前的所有参数都会被当作“函数的参数”。
-
1 和 2 的比较
-
效果完全相同
-
构造时机不同:1 和 2 两个例子的运行结果虽然是相同的,但是他们的运行细节确实不相同的,1 中直接声明了一个函数,这个函数会在脚本引擎解析期间创建,而 2 中的方式其实是定义了一个变量,而不是函数,所以,只有在脚本真正被执行的时候,函数才会真正的被创建出来。
-
作用域不同:new Function() 创造出来的函数,其作用域指向“顶级作用域”,即 Window
-
6、函数实例的属性
6.1 length
获取函数定义的形参个数
- 注意: javascript 函数的参数个数是可变的,但是,那指的是函数在操作时的实际参数(实参),而这里指的是 形参。
function myFunc(arg1,arg2){
}
// 2
alert(myFunc.length);
6.2 arguments
尅获取到所有的 实参,类似于数组,以为它只有一个
length
属性,而没有数组拥有的其他属性
但可以将它转化为一个真正的数组
function myFunc(){
var s = "";
var len = arguments.length;
for(var i=0; i < len; i++) {
s+= arguments[i];
}
alert(s);
}
// 1234
myFunc(1,2,3,4);
- 将
arguments
转换为数组
var args = Array.prototype.slice.call(arguments);
6.3 callee
callee是在arguments属性中定义的。
(
function test() {
alert(arguments.callee);
}
)();
// 结果:
// function test() {
// alert(arguments.callee);
// }
- **通过 callee 可以实现递归
...
fact(n) {
if() {
return 1;
} else {
return n * arguments.callee(n-1);
}
}
...
6.4 caller
它指向调用者,因此可以通过这个属性知道谁在调用自己
- 注意: 因为caller指向调用者,所以,它在函数运行时,才会被定义,如果在顶级作用域Window直接调用 code() 函数,那么caller值为undefined,在IE中为null;
function code() {
alert(code.caller);
}
function beatHim() {
code();
}
beatHim();
// 结果:
// function beatHim() {
// code();
// }
网友评论