js函数特性

| 上一章 |目录| 下一章 |

三、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();
// }

|上一章 |目录| 下一章|

你可能感兴趣的:(js函数特性)