JavaScript function 类型的使用说明

JSON 2016-08-22 18:25:16 3466

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 加密、混淆、解密、美化等安全说明
Javascript模块化编程,本站使用 require.js 优化JS加载, require.js下载
Javascript不可逆加密,JS加密工具sojson.v5 版本更新说明
Linux Centos 使用 Redis service 启动,Redis service 脚本编写
如何使用canvas转换图片类型
如何使用canvas转换图片类型
Elasticsearch Date类型,时间存储相关说明
JS解密,JavaScript 解密,任何JS加密都能100%解密,以及JS 加密讲解
JS加密,JS在线混淆加密,JavaScript在线加密
javascript核心知识点
最新文章
文件上传漏洞与防御 4058
前端构建工具选型指南:Webpack、Vite、Rollup、esbuild 深度对比 1444
物联网时代2026年时序数据库选型指南 1151
SaaS行业面临AI挑战:从“无限复用”到“灵活适应” 1269
神经网络:从构造到模型训练全链路解析 1168
一文吃透 Redis 核心存储结构:ziplist、listpack 与哈希表扩容 / 并发查询 1593
Linux sudo提权完整指南:从基础用法到生产级安全配置 691
XSS 和 CSRF 的本质区别及开发防御全解析 772
JVM垃圾回收(GC)全维度解析:从原理到调优实战 813
Linux动静态库与ELF加载全解析:从实操制作到底层原理 912
最热文章
免费天气API,天气JSON API,不限次数获取十五天的天气预报 783114
最新MyEclipse8.5注册码,有效期到2020年 (已经更新) 711464
苹果电脑Mac怎么恢复出厂系统?苹果系统怎么重装系统? 679993
Jackson 时间格式化,时间注解 @JsonFormat 用法、时差问题说明 562673
我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比 512621
Elasticsearch教程(四) elasticsearch head 插件安装和使用 484794
Jackson 美化输出JSON,优雅的输出JSON数据,格式化输出JSON数据... ... 302947
Java 信任所有SSL证书,HTTPS请求抛错,忽略证书请求完美解决 247433
Elasticsearch教程(一),全程直播(小白级别) 233097
谈谈斐讯路由器劫持,你用斐讯路由器,你需要知道的事情 228329
支付扫码

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

查看我的收藏

正在加载... ...