资讯专栏INFORMATION COLUMN

JavaScript中的Function类型

derek_334892 / 2646人阅读

摘要:结果为结果为不过,提供了对象,该对象可以模拟函数重载的现象。默认名字的函数被称之为匿名函数。提供专门的读写变量的函数避免全局污染闭包的应用利用闭包保护共享的局部变量,提供专门的读写变量的函数

Function与函数

函数是一段JavaScript代码,它只定义一次,但可能被执行或调用多次
Function类型是JavaScript提供的引用类型之一,通过Function类型创建Function对象
在JavaScript中,函数也是以对象的形式存在的。每个函数都是一个Function对象
函数名,本质就是一个变量名,是指向某个Function对象的引用

function fn(){
    console.log("前端");
}
console.log(fn instanceof Function);//true
构造函数

在JavaScript中,函数除了可以通过函数定义语句或字面量表达式两种方式定义之外,还可以通过Function类型进行定义

var fn=new Function("num1","num2","var sum = num1+num2;return sum");

通过Function类型定义函数的效率远不如通过函数定义语句或字面量表达式两种方式定义
目前,定义函数具有三种方式,这三种方式之间存在一定差别
函数定义语句:函数名被声明提前,不存在效率问题
字面量表达式:函数体固定,无法动态执行,不存在效率问题
Function类型定义:函数体是字符串,可以动态执行,效率低

Function的apply()方法

Function的apply()方法用于调用一个函数,并且接收指定的this值,以及一个数组作为参数,其语法结构如下:

func.apply(thisArg,[argsArray])

thisArg参数:可选项,在func函数运行时使用的this值

argsArray参数:可选项,一个数组或者类数组对象,其中的数组元素将作为多带带的参数传给func函数。也可以使用arguments对象作为该参数

返回值:调用该函数的返回结果

var numbers=[1,2,3,4,5];
//通过apply()方法获取数组中最大值和最小值
var max=Math.max.apply(null,numbers);
var min=Math.min.apply(null,numbers);
Function的call()方法

Function的call()方法用于调用一个函数,并且接收指定的this值作为参数,以及参数列表。其语法结构如下:

func.call(thisArg,arg1,arg2,...)

thisArg参数:在func函数运行时使用的this值

arg1,arg2,...参数:指定的参数列表

返回值:调用该函数的返回结果

apply()与call()非常相似,不同之处在于提供参数的方式

//通过call()方法获取数组中最大值和最小值
var max=Math.max.call(null,5,6,2,3,7);
var min=Math.min.call(null,5,6,2,3,7);
Function的bind()方法

Function的bind()方法用于创建一个新的函数(称为绑定函数),并且接收指定的this值作为参数,以及参数列表,其语法结构如下:

fun.bind(thisArg[,arg1[,arg2[,...]]])

thisArg参数:当绑定函数被调用时,该参数会作为原函数运行时的this指向

arg1,arg2,...参数:当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法

返回值:返回由指定的this值和初始化参数改造的原函数

Function的bind()方法示例如下:

this.x=9;
var module={
    x:81,
    getX:function(){return this.x;}
};

module.getX();//返回81

var retrieveX=module.getX;
retrieveX();//返回9,在这种情况下,"this"指向全局作用域

//创建一个新函数,将"this"绑定到module对象
var boundGetX=retrieveX.bind(module);
boundGetX();//返回 81
没有重载

在其他开发语言中,函数具有一种特性,叫做重载。所谓重载,就是定义多个同名的函数,但每一个函数接收的参数的个数不同,程序会根据调用时传递的实参个数进行判断,具体调用的是哪个函数。如下示例:

function add(a,b){
    return a+b;
}
function add(a,b,c){
    return a+b+c;
}
add(1,2);//结果为3
add(1,2,3);//结果为6

但在JavaScript中,函数是没有重载现象的,也就是说,如果同时定义多个同名的函数,只有最后一个定义的函数是有效的。

function add(a,b){
    return a+b;
}
function add(a,b,c){
    return a+b+c;
}
add(1,2);//结果为NaN
add(1,2,3);//结果为6 

不过,JavaScript提供了arguments对象,该对象可以模拟函数重载的现象。arguments对象是函数内部的本地变量;arguments已经不再是函数的属性了。
arguments对象可以获取函数的所有参数,但arguments对象并不是一个数组,而是一个类数组对象(没有数组特有的方法)
arguments对象的属性如下所示:
callee:表示当前执行的函数
length:表示传递给当前函数的参数数量
利用arguments对象实现模拟函数的重载现象,如下述示例

function doAdd(){
    if(arguments.length==1){
        console.log(arguments[0]+5);
    }else if(arguments.length==2){
        console.log(arguments[0]+arguments[1]);
    }
}

doAdd(10);//输出"15"
doAdd(40,20);//输出"60"
递归

在一个函数的函数体内,如果想调用自身函数的话,有如下两种方式:

通过使用自身函数名实现

通过使用arguments对象的callee属性实现

调用自身的函数被称之为递归函数,在某种意义上说,递归近似于循环。两者都重复执行相同的代码,并且两者都需要一个终止条件以避免无限循环或者无限递归。

function loop(x){
    if(x>=10){return;}
    loop(x+1);
}
loop(0);

上述代码是一个经典的递归函数。虽然这个函数表面看起来并没有什么问题,如果执行下述代码可能会导致出错。

var anotherLoop=loop;
loop=null;
anotherLoop(0);//出错

上述代码将函数loop()保存到另一个变量anotherLoop中,然后将loop设置为null值。当执行anotherLoop时,一定会执行函数loop(),而loop已经不再是一个函数,最终导致出错
要想解决上述递归函数的问题,可以使用arguments对象的callee属性替换具体的函数名

function loop(x){
    if(x>=10){
        return;
    }
    arguments.callee(x+1);
}
匿名函数

JavaScript可以将函数作为数据使用,作为函数本体,它像普通的数据一样,不一定要有名字。默认名字的函数被称之为匿名函数。如下示例:

function(a){return a}

匿名函数的两种方法:

可以将匿名函数作为参数传递给其他函数。这样,接收方函数就能利用所传递的函数来完成某些事情

可以定义某个匿名函数来执行某些一次性任务

回调函数

当一个函数作为参数传递给另一个函数时,作为参数的函数被称之为回调函数

function add(a,b){
    return a()+b();
}

var one=function(){return 1;}
var two=function(){return 2;}

console.log(add(one,two));//output 3
//可以直接使用匿名函数来替代one()和two(),以作为目标函数的参数
console.log(add(function(){return 1;},function(){return 2;}));

上述代码中,函数one()和two()都作为函数add()的参数传递。所以函数one()和two()都是回调函数。当将函数A传递给函数B,并由B来执行A时,A就成了一个回调函数,如果A还是一个无名函数,就称之为匿名回调函数
回调函数优点如下:

它可以在不做命名的情况下传递函数(这意味着可以节省全局变量)

可以将一个函数调用操作委托给另一个函数(这意味着可以节省一些代码编写工作)

回调函数也有助于提升性能

自调函数

所谓自调函数就是在定义函数后自行调用。如下示例:

(function(){
    console.log("javascript");
})();

上述代码的含义如下:

第一对括号的作用,放置的是一个匿名函数。

第二对括号的作用,是"立即调用"

自调函数只需将匿名函数的定义放进一对括号中,然后外面再跟一对括号即可
自调函数也可以在调用时接收参数,如下示例:

(function(name){
    console.log("hello"+name+"!");
})("javascript");//hello javascript

上述代码的含义如下:

第一个括号中的匿名函数接受一个参数

第二个括号,在调用时,向匿名函数传递参数内容

作为值的函数

将一个函数作为另一个函数的结果进行返回,作为结果返回的函数称之为作为值得函数

function fn(f,args){
    return f(args);
}
function add(num){//作为值的函数
    return num+10;
}

var result=fn(add,10);
console.log(result);//20

上述代码还可以编写成如下方式:

function fn(args){
    return function add(){
        return args+10;
    }
}

上述两段代码的区别在于

var f=fn(10);//function add(){return 10+10}
var result=f();//20
作用域链

很多开发语言中都具有块级作用域,但ECMAScript5版本中并没有跨级作用域,这经常会导致理解上的困惑。如下示例:

if(true){
    var color="blue";
}
console.log(color);//blue

上述代码在if语句中定义了变量color。但该变量的作用域是全局域,原因是ECMAScript5版本中没有块级作用域
虽然ECMAScript5版本没有块级作用域,但具有函数作用域。在某个函数内部定义的变量的作用域就是该函数作用域。

function fun(){
    var v="this is function";
}
console.log(v);//输出报错

上述代码在函数fun内部定义了变量v,该变量的作用域是fun函数作用域。所以在全局域访问该变量时会出错
每一段JavaScript(全局代码或函数)都有一个与之关联的作用域链。这个作用域链是一个对象列表或链表,这组对象定义了这段代码"作用域中"的变量。如下示例:

var a=1;
//在全局域中只能访问变量a
function f(){
    //在f函数作用域中可以访问变量a和b
    var b=2;
}
闭包

JavaScript允许函数嵌套,并且内部函数可以访问定义在外部函数中的所有变量和函数,以及外部函数能访问的所有变量和函数。但是,外部函数却不能够访问定义在内部函数中的变量和函数。
当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了
闭包就是该函数能使用函数外定义的变量
如下代码就是一个最简单形式的闭包结构:

var b;
function f(){
    var a="a";
    b=function(){
        return a+"b";
    }
    return a;
}
//测试
console.log(f());//a
console.log(b());//ab

闭包的特点与作用
闭包的特点:

局部变量:在函数中定义有共享意义(如:缓存、计数器等)的局部变量。(注意:定义成全局变量会对外造成污染)

内部函数:在函数(f)中声明有内嵌函数,内嵌函数(g)对函数(f)中的局部变量进行访问

外部使用:函数(f)向外返回此内嵌函数(g),外部可以通过此内嵌函数持有并访问声明在函数(f)中的局部变量,而此变量在外部是通过其他途径无法访问的

闭包的作用

提供可共享的局部变量

保护共享的局部变量。提供专门的读写变量的函数

避免全局污染

闭包的应用
利用闭包保护共享的局部变量,提供专门的读写变量的函数

var getValue,setValue;
(function(){
    var secret=0;
    getValue=function(){
        return secret;
    };
    setValue=function(v){
        secret=v;
    }
})();

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108202.html

相关文章

  • JavaScript 面向对象开发知识总结基础篇

    摘要:字面形式允许你在不需要使用操作符和构造函数显式创建对象的情况下生成引用值。操作符以一个对象和一个构造函数作为参数鉴别数组有前一小结可以知道鉴别数组类型可以使用。属性是函数独有的,表明该对象可以被执行。这种函数被称为匿名函数。 引子: 1.JavaScript 中的变量类型和类型检测 1.1原始类型 1.2引用类型 1.3內建类型的实例化 1.4函数的字面形式 1.5正则表达式的字...

    Kross 评论0 收藏0
  • JavaScript中的数据类型及其检测

    摘要:中的数据类型及其检测数据类型基本类型引用类型类型检测只能检测基本数据类型,对于还有一个用于检测某个对象的原型链是否包含某个构造函数的属性适用于检测对象,它是基于原型链运作的属性返回一个指向创建了该对象原型的函数引用,该属性的值是哪个函数本身 JavaScript中的数据类型及其检测 1. 数据类型 1.1 基本类型 Number String Boolean Null Undefin...

    Bryan 评论0 收藏0
  • JavaScript面向对象中的Function类型个人分享

    摘要:类型与函数的概念函数这样的一段代码它只定义一次但是可能被执行或调用多次类型是提供的引用类型之一通过类型创建对象在中函数也是对象的形式存在注意每个函数都是以个对象与函数函数声明方式示例代码一笑一人生字面量方式示例代码一花一世界判断函数是否为类 Function类型 Function与函数的概念 函数这样的一段JavaScript代码,它只定义一次,但是可能被执行或调用多次 Functi...

    LeviDing 评论0 收藏0
  • JavaScript基础知识

    摘要:用和包裹的内容,称为字符串。关系运算符用于进行比较的运算符。强制依赖于,非强制依赖于。使用场合全局环境构造函数对象的方法闭包闭包是指有权访问另一个函数作用域中的变量的函数。所有全局对象函数以及变量均自动成为对象的成员。 1 什么是JavaScript JavaScript一种直译式脚本语言,一种基于对象和事件驱动并具有安全性的客户端脚本语言;也是一种广泛应用客户端web开发的脚本语言。...

    Code4App 评论0 收藏0
  • 前端基础入门四(JavaScript基础)

    摘要:学习目标掌握编程的基本思维掌握编程的基本语法我们先来学习基础,后续会讲解高级。语句基本语法当循环条件为时,执行循环体,当循环条件为时,结束循环。基础语法循环体循环条件代码示例初始化变量循环体自增循环条件语句和一般用来解决无法确认次数的循环。 学习目标: 掌握编程的基本思维 掌握编程的基本语法 我们先来学习JavaScript基础,后续会讲解JavaScript高级。 重点内容 变...

    王军 评论0 收藏0
  • 前端基础入门四(JavaScript基础)

    摘要:学习目标掌握编程的基本思维掌握编程的基本语法我们先来学习基础,后续会讲解高级。语句基本语法当循环条件为时,执行循环体,当循环条件为时,结束循环。基础语法循环体循环条件代码示例初始化变量循环体自增循环条件语句和一般用来解决无法确认次数的循环。 学习目标: 掌握编程的基本思维 掌握编程的基本语法 我们先来学习JavaScript基础,后续会讲解JavaScript高级。 重点内容 变...

    SnaiLiu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<