码迷,mamicode.com
首页 > 编程语言 > 详细

JavaScript:Function类型

时间:2016-05-31 01:04:11      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

在JavaScript中,函数实际是对象。每个函数都是Function类型的实例,而且都与其他类型一样具有属性和方法。函数声明方式:

// 第一种:使用函数声明语法定义
function sum (num1, num2) {
    return num1 + num2;
}

// 第二种:使用函数表达式定义函数
var sum = function(num1, num2) {
    return num1 + num2;
};

// 第三种:构造函数
var sum = new Function("num1", "num2", "return num1+num2");

由于函数是对象,因此函数名实际上是一个指向函数的指针,不会与某个函数绑定。函数名与包含对象指针的其他变量没有什么不同,也就是说,一个函数可能有多个名字:

function sum(num1, num2) {
    return num1 + num2; 
}
alert(sum(1,2));    // 3

var anotherSum = sum;
alert(anotherSum(3,4)); // 7

sum = null;
alert(anotherSum(4, 5));    // 9

需要注意的是sum = null将sum变量与函数取消了关系,但是仍然可以正常调用anotherSum()。

没有重载

JavaScript中并没有类似于java语言的重载机制。

function addNum(num) {
    return num + 1;
}

function addNum(num) {
    return num + 2;
}

var result = add(0);    // 2

上面的例子声明了两个函数,而结果显示后面的函数覆盖了前面的函数。上面的代码等价于:

function addNum(num) {
    return num + 1;
}

function addNum(num) {
    return num + 2;
}

var result = add(0);    // 2

函数声明与函数表达式

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

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

上面的代码可以正常执行。这是因为在代码执行之前,解析器就已经通过名为函数声明提升的过程,读取并将函数声明添加到执行环境中。对代码求值时,JavaScript引擎也能把函数声明提升到顶部。

如果把函数声明改为函数表达式的形式,就会在执行期间导致错误。

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

以上代码会运行错误。因为函数位于初始化语句中,在执行到函数所在的语句之前,变量sum中不保存对函数的引用。

作为值的函数

在JavaScript中的函数本身就是变量,所以函数也可以作为值来使用。这就是说,可以把函数当作一个参数传递给另一个变量。

function sum(add1, arg) {
    return add1(arg);
}

sum函数接收两个参数。第一个是参数是一个函数,第二个参数应该是要传递给该函数的一个值。

// add1执行加1操作
function add1(num) {
    return num + 1;
}

var result = sum(add1, 2);
alert(result);  // 3

function sayHello(name) {
    return "hello, " + name;
}
var result1 = sum(sayHello, "world");
alert(result1);     // "hello, world"

注意:这里sum()函数是通用的,无论第一个参数传进来的是什么函数,都返回这个函数的结果。sum(add1, 2);和sum(sayHello, "world");中传递的都是add1()方法和sayHell0()方法,而不是执行它们返回的结果。

可以从一个函数中返回另一个函数。例如前面提到的数组的sort()方法的比较函数,需要传入两个参数。

function createComparisionFunction(propertyName) {
    return function(obj1, obj2) {
        var value1 = obj1[propertyName];
        var value2 = obj2[propertyName];

        if (value1 < value2) {
            return -1;
        } else if (value1 > value2) {
            return 1;
        } else {
            return 0;
        }
    };
}

上面定义了一个函数,这个函数中嵌套了一个函数,内部函数接收到propertyName参数后,会使用方括号表示法来取得给定属性的值,然后根据值来定义排序规则。

var data = [{name:"zhangsan", age:18}, {name:"lisi", age:19}];
data.sort(createComparisionFunction("name"));
alert(data[0].name);    // lisi

data.sort(createComparisionFunction("age"));
alert(data[0].name);    // zhangsan

函数内部属性

在函数内部,有两个特殊对象:arguments和this。

arguments

arguments是一个类数组对象,包含传入函数中的所有参数。arguments主要用于保存函数参数,除此之外还有一个callee属性,callee是一个指向拥有arguments对象的函数。

下面看一个阶乘的例子:

function factorial(num) {
    if (num <= 1) {
        return 1;
    } else {
        return num * factorial(num - 1);
    }
}

这种定义方法是没有问题的,缺点在函数的运行与函数名factorial紧密耦合在一起了,为了解决这个问题,可以使用arguments.callee。

function factorial(num) {
    if (num <= 1) {
        return 1;
    } else {
        return num * factorial(num - 1);
    }
}

这样,无论引用函数时是什么名字都不影响函数的正常运行。例如:

var newfactorial = factorial;
factorial = function () {
    return 0;
}
alert(newfactorial(5)); // 120
alert(factorial(5));    // 0

this

this引用的是函数据以执行的环境对象。

window.color = "red";
var obj = {color: "blue"};

function sayColor() {
    alert(this.color);
}

sayColor();     // "red",this指window对象
obj.sayColor = sayColor;    
obj.sayColor(); // "blue", this指obj对象

在调用函数之前this的值并不确定,this在运行过程中会指代不同对象。在调用sayColor();时,this引用的是全局对象window,this.color相当于window.color;当把sayColor赋值给obj对象并调用obj.sayColor()时,this引用的是obj对象,因此对this.color即obj.color。

caller

ECMAScript5提供了另一个函数对象的属性:caller。它保存着调用当前函数的函数的引用,如果在全局作用域中调用当前函数,值为null。

function outer() {
    inner();
}

function inner() {
    alert(inner.caller);
}

outer();

上面的代码会显示outer()函数的源码。因为outer()调用了inner(),所以inner.caller就执行outer()。

函数属性和方法

前面已经说过,在JavaScript中函数时对象,因此函数也有属性和方法。每个函数。每个函数都包含两个属性:length和prototype。

length属性保存的是调用数组时的参数个数,而不是声明时定义的参数个数。对于JavaScript中的引用类型而言,prototype是保存它们所有实例方法的真正所在。诸如toString()和valueOf()等方法实际上都保存在prototype名下,只不过是通过各自对象的实例访问。在ECMAScript5中,prototype属性是不可枚举的,因此,使用for-in无法发现。

每个函数都包含两个非继承而来的方法:apply()call()。这两个方法都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

apply()方法

apply()方法接收两个参数:第一个参数是在其中运行函数的作用域;另一个是参数数组,它可以是Array的实例,也可以是arguments对象。

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

function callSum1(num1, num2) {
    return sum.apply(this, arguments);  // 传入arguments
}

function callSum2(num1, num2) {
    return sum.apply(this, [num1, num2]);   // 传入数组对象
}

alert(callSum1(1, 2));  // 3
alert(callSum2(1, 2));  // 3

call()方法

call()方法与apply()方法的作用相同,它们的区别仅在于接收的参数不同。第一个参数也是this,其余参数都直接传递。

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

function callSum(num1, num2) {
    return sum.call(this, num1, num2);
}

alert(callSum(1, 2));   // 3

在使用call()方法的情况下,callSum()必须明确传入每一个参数,返回值都一样。

apply()和call()最大的作用在于能够扩充函数赖以运行的作用域。

window.color = "red";
var obj = {color: "blue"};

function sayColor() {
    alert(this.color);
}

sayColor();             // red

sayColor.call(this);    // red
sayColor.call(window);  // red
sayColor.call(obj);     // blue

在上面的例子中,sayColor()方法是定义在全局作用域中的,在全局作用域中this.color会转换为window.color,所以sayColor()的结果为red。而sayColor.call(this)sayColor.call(window)显式地在全局作用域中调用函数,结果必然为热点。当运行sayColor.call(obj)时,函数的运行环境就变成了obj,当执行sayColor()时,this.color会转换为obj.color,因此结果为blue。

bind()方法

bind()方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。

window.color = "red";
var obj = {color: "blue"};

function sayColor() {
    alert(this.color);
}

var objSayColor = sayColor.bind(obj);
objSayColor();  // blue

在上面的例子中,sayColor()调用bind()并传入对象。创建了objSayColor()函数。objSayColor()函数的this值为obj,因此,即使在全局作用域下调用objSayColor(),结果也是blue。

JavaScript:Function类型

标签:

原文地址:http://www.cnblogs.com/xiaoxiaoyihan/p/5544463.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!