JavaScript function 类型的使用说明

soゝso 2016-08-22 18:25:16 753

Function 类型

每个函数都是Function 类型的实例。函数名实际上就是一个指向函数对象的指针,不会与某个函数绑定。

函数声明方式创建Function,语法如下:

function sum(x,y){
    return x + y;
}

函数表达式定义Function,用var 如下:

var sum = function(x,y){
    return x + y;
};

第二种方法不要忘记在结尾加上分号

另外还可以使用Function 构造函数。如:

var sum = new function("x","y","return x + y");

非常不推荐使用这种形式。

如何证明函数名仅仅是指向函数的指针呢:

var sum = function(x,y){
    return x + y;
};
console.log(sum(1,2)); //3

var anotherSum = sum;
console.log(anotherSum(1,1)); //2

sum = null;
console.log(anotherSum(10,10)); //20

没有重载

同名的后面的函数将会覆盖前面的函数。如:


function add(num){
    return num + 100;
}
function add(num){
    return num + 200;
}
console.log(add(100)); //300

用另外一种写法就可以很清楚的看出原因。如:

var add = function(num){
    return num + 100;
}
add = function(num){
    return num + 200;
}
console.log(add(100)); //300

函数的声明与函数表达式(以及函数声明提升)

解析器会率先读取函数声明,并使其在执行任何代码之前可用(可访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。如:

console.log(sum(1,1)); //2
function sum(x,y){
    return x + y;
}

以上代码可行,是因为在代码开始值钱,解析器就已经通过一个名为函数声明提升(function declaration hoisting)的过程,读取并将函数声明添加到执行环境中去。即使声明函数的代码在调用它的代码后面,JavaScript 引擎也能把函数声明提升到顶部。

但是,如果把函数声明改成函数表达式,则会导致错误。如:

console.log(sum(1,1)); 
var sum = function(x,y){
    return x + y;
}; //TypeError: undefined is not a function (evaluating 'sum(1,1)')

失败的原因就在于函数位于初始化语句中,而不是一个函数声明。

也可同时使用函数声明和函数表达式,但在safari 浏览器中会出错。

作为值的函数

函数也可以作为值来使用,也就是可以将一个函数作为另一个函数的结果返回。如

function callFunction(someFunction,someArgument){
    console.log(someFunction(someArgument));
}
function addNum(x){
    return x + 100;
}
callFunction(addNum,100); //200

要访问函数的指针而不执行函数的话,必须去掉函数名后面的括号。

function compare(func,x,y){
    var num1 = func(x);
    var num2 = func(y);
    var array = [num1,num2];
    
    var result = array.sort(sortFunc);
    console.log(result.toString());
    document.write(result.join(" then "));
    
    
    function sortFunc(value1,value2){
        if (value1 > value2){
            return 1;
        }else if(value2 > value1){
            return -1;
        }else{
            return 0;
        }
    }
}

function add10(num){
        return num + 10;
    }

compare(add10,10000,999100); //10010 then 999110

函数内部属性

这里主要说一下callee属性、this属性以及caller属性。

callee属性的功能就是消除函数名的耦合问题。如:

function min(num){
    if(num == 1){
        return 1;
    }else if(num < 1){
        return 0;
    }else{
        return min(num - 1);
    }
}

var result = min(100);
document.write(result);

上面这个min()函数如果改了函数名,函数里面也相应的需要修改函数名。但添加了callee属性,就不需要修改。如:

function mins(num){
    if(num == 1){
        return 1;
    }else if(num < 1){
        return 0;
    }else{
        return arguments.callee(num - 1);
    }
}

var result = mins(100);
document.write(result);

着就解决了耦合现象所带来的问题。

this这个特殊对象的作用与Java 和C# 中的this 类似。this引用的是函数据以执行的环境对象——或者this值。如:

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

function show(){
    document.write(this.color);
}

show(); //red

obj.show = show;
obj.show(); //yellow

caller用来调用当前函数的函数的引用(源代码)。如:

function sum(x,y){
    plus(x,y);
}

function plus(x,y){
    console.log(x + y);
    document.write("<pre>" + plus.caller + "</pre>");
}

sum(10,20);

如:


(
    function a(){
        document.write("function a");
        b();
        function b(){
            document.write("function b");
            alert(arguments.callee.caller);
        }
    }
)()

用arguments.callee 可能在某些浏览器中会导致错误:

function sum(x,y){
    plus(x,y);
}

function plus(x,y){
    console.log(x + y);
    document.write("<pre>" + arguments.callee.caller + "</pre>");
}

sum(10,20);

函数属性和方法

每个函数都包含两个属性lengthprototype

length属性中,将返回参数的个数。如:

function colors(color1,color2){
    var array = [color1,color2];
    document.write(array.join("/"))
}
colors("red","blue");
document.write(" " + colors.length + "个参数"); //red/blue 2个参数

又如:

function toStr(){
        var result = "";
        for (var i = 0; i < arguments.length; i ++){
            result += arguments[i].toString() + " ";
        }
        document.write(result);
        document.write(" " + arguments.length + "个参数" + "<br/>");
        document.write(" " + arguments.callee.length + "个函数期望参数");
}
toStr(321,32,43243,432,3213);
    
/*
321 32 43243 432 3213 5个参数
0个函数期望参数    
*/

prototype属性。这个属性是保存它们所有实例方法的真正所在。在创建自定义引用类型以及实现继承时,这个属性是非常重要的(以后再单独讨论)。另外,在ECMAScript 5 中,这个属性不可枚举(不能用for-in)。主要的两个非继承方法有apply()call();这两个方法的用途都是在特定的作用域中调用函数。

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

function sum(x,y){
    document.write(x.toString() + y.toString());
}

function plus(){
    return sum.apply(this,arguments);
}

plus(321,"fff");

下面这个则是Array 的实例:

function sum(x,y){
    document.write(x.toString() + y.toString());
}

function plus(a,b){
    return sum.apply(this,[a,b]);
}

plus(321,"fff"); 

call()方法与前者的作用相同,区别在于接收参数的方式不同。第二个参数必须一个个列举出来。如下:

function sum(x,y){
    document.write(x.toString() + y.toString());
}

function plus(a,b){
    return sum.call(this,a,b);
}

plus(321,"fff");

上面例子中plus(a,b) 不能写成plus();call(this,a,b)不能写成call(this,arguments)call(this,[a,b])

高能!!!

高能!!!

事实上,apply()call()真正有价值的用途是扩充函数的作用域。如:

var child = {
    name: "Oliver",
    age: 18
}
var adult = {
    name: "Troy",
    age: 24
}

function showName(){
    document.write(this.name);
}

showName.call(adult); //Troy
showName.call(child); //Oliver

使用上面这两个方法来扩充作用域的最大好处就是对象不需要与方法又任何耦合关系。

ECMAScript 5 还定义了一个方法:bind()。this 的值会被绑定到传给bind()函数的值。如:

var child = {
    name: "Oliver",
    age: 18
}
var adult = {
    name: "Troy",
    age: 24
}

function showName(){
    document.write(this.name);
}

var newFunc = showName.bind(child);
newFunc(); //Oliver

版权所属:SO JSON在线解析

原文地址:https://www.sojson.com/blog/38.html

转载时必须以链接形式注明原始出处及本声明。

本文主题:

如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。

相关文章
JavaScript function 类型使用说明
Javascript模块化编程,本站使用 require.js 优化JS加载, require.js下载
Elasticsearch Date类型,时间存储相关说明
怎么合理管理、提高Javascript的性能
Javascript 生成UUID,Java生成UUID
JS中 “is not defined” 如何判断defined,defined和undefined 的区别
js html5 canvas制作多个小球碰撞的动画效果
JSON.stringify 函数 (JavaScript)讲解
一些Node.js开发工具、开发包、框架等总结
详解JavaScript中splice()方法,有Demo详细介绍
最新文章
阿里云和腾讯云哪个好? 69
2019年9月16日新浪短链API已经恢复使用,新浪短链服务官方已经宣布停用。本站已经攻克 1173
2019年 中秋节、国庆节放假通知来了,拼假攻略 180
记一次小失误导致的大事件,Mysql SQL Error: 0, SQLState: null 排查过程 314
Springboot Maven 增加本地依赖包,Springboot Maven打包本地包 172
Java 获取图片属性、获取图片EXIF属性操作方法[metadata-extractor] 87
又拍云(Upyun)CDN、云存储刷新链接缓存,API实例讲解 119
Linux Centos 使用 Redis service 启动,Redis service 脚本编写 177
恭喜SOJSON获得阿里云618“上云接力赛”第一名,获得代金券6.18万 416
Springboot 集成Freemarker 自定义标签解决方案 1251
最热文章
免费天气API,全国天气 JSON API接口,可以获取五天的天气预报 183941
我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比 161806
Elasticsearch教程(四) elasticsearch head 插件安装和使用 142530
苹果电脑Mac怎么恢复出厂系统?苹果系统怎么重装系统? 100409
Elasticsearch教程(六) elasticsearch Client创建 83021
Elasticsearch教程(一),全程直播(小白级别) 80411
Elasticsearch教程(二),IK分词器安装 78351
Elasticsearch教程(八) elasticsearch delete 删除数据(Java) 77550
Elasticsearch教程(五) elasticsearch Mapping的创建 71899
免费天气API,天气JSON API,不限次数获取十五天的天气预报 71424

骚码加入我们 / 千人QQ群:259217951

入群需要5元,如果没有QQ钱包,可以先Alipay、微信,赞助然后加群主拉进。

二维码生成 来自 >> 二维码生成器

支付扫码

所有赞助/开支都讲公开明细,用于网站维护:赞助名单查看

正在加载... ...