函数是代码语句的容器,可以使用括号()运算符调用。调用时可以在括号中传递参数,以便函数中的语句可以在调用函数时访问某些值。
在下面的代码中,我们使用new运算符创建两个版本的addNumbers函数objectone,另一个版本使用更常见的文本模式。两者都需要两个参数。在每种情况下,我们调用函数并传递括号中的参数()运算符。
例如:sample76.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar addNumbersA =新函数(‘num 1’,‘num 2’,‘return num 草根吧VPSnum 2’);console . log(addNumbersA(2,2));//日志4。//也可以用更常见的文字方式编写。var addNumbersB = function(num 1,num 2){ return num 草根吧VPSnum 2;};console . log(addNumbersB(2,2));//日志4。& lt/script & gt;& lt/body & gt;& lt/html & gt;函数可用于返回值、构造对象或作为简单运行代码的机制。JavaScript对函数有许多用途,但在其最基本的形式中,函数只是可执行语句的唯一范围。
function()参数Function()构造函数接受无限多个参数,但Function()构造函数期望的最后一个参数是一个字符串,该字符串包含组成函数体的语句。在最后一个参数之前传递给构造函数的任何参数都可以用于正在创建的函数。您还可以以逗号分隔的字符串形式发送多个参数。
在下面的代码中,我将function()构造函数的用法与实例化Function对象的更常见模式进行了比较。
例如:sample77.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar addFunction =新函数(‘num 1’‘num 2’‘return num 草根吧VPSnum 2’);/*或者,一个带参数的逗号分隔字符串可以作为构造函数的第一个参数,函数体跟在后面。*/var timesFunction =新函数(‘num 1,num 2‘,‘return num 1 * num 2‘);console . log(addFunction(2,2),time function(2,2));//Logs‘4 4“//与实例化函数的更常见模式相比:var addFunction = function(num 1,num 2){ return num 草根吧VPSnum 2;};//Expression form . function add function(num 1,num 2){ return num 草根吧VPSnum 2;} //语句形式。& lt/script & gt;& lt/body & gt;& lt/html & gt;不建议或通常不建议直接使用Function()构造函数,因为JavaScript将使用eval()来解析包含函数逻辑的字符串。很多人认为eval()是不必要的开销。如果你使用它,代码设计可能存在缺陷。
使用function()构造函数而不使用new关键字与使用构造函数创建Function对象(new Function(‘x’,‘return x’)和Function(‘x’,return x’)的效果相同。
直接调用Function()构造函数时不会创建闭包。
Function()属性和方法Function对象具有以下属性(不包括继承的属性和方法):
属性(Function.prototype):
原型函数对象实例属性和方法函数对象实例具有下列属性和方法(不包括继承的属性和方法):
实例属性(var my function = function(x,y,z){ };myFunction.length):
参数构造函数length实例方法(var my function = function(x,y,z){ };my function . tostring();):
apply()call()toString()函数始终返回值。虽然您可以创建一个函数来简单地执行代码语句,但函数返回值也是很常见的。在下面的示例中,我们从sayHi函数返回一个字符串。
例如:sample78.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar say Hi = function(){ return‘Hi‘;};console . log(say hi());//日志& quot嗨& quot。& lt/script & gt;& lt/body & gt;& lt/html & gt;如果函数没有指定返回值,则返回undefined。在下面的示例中,我们调用yelp函数,该函数将字符串“yelp”记录到控制台,而没有显式返回值。
例如:sample79.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar yelp = function(){ console . log(‘我在叫!’);//即使我们不这样做,函数也会返回undefined。}/*记录true,因为总是返回一个值,即使我们没有明确返回一个值。*/console . log(yelp()= = = undefined);& lt/script & gt;& lt/body & gt;& lt/html & gt;这里要记住的概念是,所有函数都将返回值,即使您没有显式提供要返回的值。如果未指定返回值,则返回值未定义。
函数是一等公民(不仅是语法,还有值)。在JavaScript中,函数是对象。这意味着函数可以存储在变量、数组或对象中。此外,函数可以传递给函数或从函数返回。函数具有属性,因为它是一个对象。所有这些因素使函数成为JavaScript中的一等公民。
例如:sample80.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gt//函数可以存储在变量(funcA)、数组(funcB)和对象(funcC)中。var funcA = function(){ };//像这样调用:funcA()var funcB =【function(){ }】;//像这样调用:funcB【0】()var funcC = { method:function(){ } };// too.method()或funcC【‘method‘】()//函数可以发送到Functions . var funcD = function(func){ return func };var runFuncPassedToFuncD = funcD(function(){ console . log(‘Hi‘);});runFuncPassedToFuncD();//函数是对象,这意味着它们可以有properties . var funcE = function(){ };funce . answer =‘Yep‘;//实例property . console . log(funce . answer);//日志“是”。& lt/script & gt;& lt/body & gt;& lt/html & gt;重要的是要认识到函数是一个对象,因此是一个值。它可以像JavaScript中的任何其他表达式一样被传递或增强。
向函数参数传递参数是在调用函数时向函数范围传递值的工具。在下面的示例中,我们调用addFunction()。由于我们已经预定义了它采用两个参数,因此可以在其范围内使用两个附加值。
例如:sample81.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar addFunction = function(number 1,number 2){ var sum = number 草根吧VPSnumber 2;返回总和;} console . log(add function(3,3));//日志6。& lt/script & gt;& lt/body & gt;& lt/html & gt;与其他一些编程语言相比,在JavaScript中省略参数是完全合法的,即使函数已被定义为接受这些参数。缺少的参数仅被赋予未定义的值。当然,如果参数值被省略,函数可能无法正常工作。
如果将意外参数(创建函数时未定义的参数)传递给函数,则不会发生错误。这些参数可以从arguments对象中访问,该对象可用于所有函数。
此参数和参数的值可用于所有函数。在所有函数的范围和主体内,此和参数的值都是可用的。
arguments对象是一个类似数组的对象,包含传递给函数的所有参数。在下面的代码中,即使我们在定义函数时放弃指定参数,我们也可以依靠传递给函数的arguments数组来访问调用时发送的参数。
例如:sample82.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar add = function(){ return arguments【0】+arguments【1】;};console . log(add(4,4));//返回8。& lt/script & gt;& lt/body & gt;& lt/html & gt;传递给所有函数的这个关键字是对包含该函数的对象的引用。如您所料,作为属性(方法)包含在对象中的函数可以使用它来获取对父对象的引用。当函数在全局范围内定义时,该函数的值是一个全局对象。请查看以下代码,并确保您理解该代码返回的内容。
例如:sample83.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar my object 1 = { name:‘my object 1’,my method:function(){ console . log(this);}};my object 1 . my method();//日志“myObject1”。var my object 2 = function(){ console . log(this);};my object 2();//日志窗口。& lt/script & gt;& lt/body & gt;& lt/html & gt;arguments.callee属性arguments对象具有一个名为callee的属性,该属性是对当前正在执行的函数的引用。此属性可用于从函数范围引用函数(arguments.callee)自引用。在下面的代码中,我们使用该属性获取对调用函数的引用。
例如:sample84.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar foo = function foo(){ console . log(arguments . callee);//Logs foo()//被调用方可用于递归调用foo函数(arguments . callee())}();& lt/script & gt;& lt/body & gt;& lt/html & gt;当您需要递归调用函数时,这很有用。
函数实例长度属性和arguments.lengtharguments对象具有唯一的长度属性。虽然您可能认为这个长度属性将为您提供已定义参数的数量,但它实际上提供了调用期间发送给函数的参数数量。
例如:sample85.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar my function = function(z,s,d){ return arguments . length;};console . log(my function());//记录0,因为没有参数传递给函数。& lt/script & gt;& lt/body & gt;& lt/html & gt;使用所有Function()实例的length属性,我们实际上可以获得函数期望的参数总数。
例如:sample86.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar my function = function(z,s,d,e,r,m,q){ return my function . length;};console . log(my function());//日志7。& lt/script & gt;& lt/body & gt;& lt/html & gt;JavaScript 1.4中不推荐使用arguments.length属性,但是可以从function对象的length属性中访问发送给函数的参数数量。接下来,您可以通过使用callee属性首先获取对正在调用的函数(arguments.callee.length)的引用来获取长度值。
重新定义函数参数函数参数可以直接在函数中重新定义,也可以使用arguments数组。看看这段代码:
例如:sample87.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar foo = falsevar bar = falsevar my function = function(foo,bar){ arguments【0】= true;bar = trueconsole.log(参数【0】,bar);//记录true true。} my function();& lt/script & gt;& lt/body & gt;& lt/html & gt;请注意,我可以通过使用arguments index或直接为参数重新分配一个新值来重新定义bar参数的值。
在函数完成之前返回函数(取消函数执行)通过使用带值或不带值的Return关键字,您可以在调用期间随时取消函数。在下面的示例中,如果参数未定义或不是数字,我们将取消add函数。
例如:sample88.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar add = function(x,y){//如果参数不是数字,则返回error . If(type of x!= =‘number‘| | y的类型!= =‘number’){ return‘传入数字’;}返回x+y;} console . log(add(3,3));//Logs 6 . console . log(add(‘2‘,‘2‘);//日志‘传入数字‘。& lt/script & gt;& lt/body & gt;& lt/html & gt;这里的概念是,您可以在函数执行期间的任何时候使用return关键字取消函数的执行。
定义函数(语句、表达式或构造函数)函数有三种不同的定义方式:函数构造函数、函数语句或函数表达式。在下面的例子中,我演示了每个变体。
例如:sample89.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gt/*函数构造器:最后一个参数是函数逻辑,它之前的一切都是参数。*/var addConstructor =新函数(‘x’,‘y’,‘return x+y’);//Function statement . Function add statement(x,y){ return x+y;}//Function expression . var addExpression = Function(x,y){ return x+y;};console . log(add constructor(2,2),add statement(2,2),add expression(2,2));//日志‘4 4‘。& lt/script & gt;& lt/body & gt;& lt/html & gt;有人说函数还有第四种定义,叫“命名函数表达式”。命名函数表达式只是包含名称的函数表达式(例如,VAR ADD = function ADD(X,Y){ RETURN X+Y })。
调用函数(函数、方法、构造函数或call()和apply())使用四种不同的场景或模式来调用函数。
使用apply()或call()作为函数作为方法作为构造函数。在下面的示例中,我们将研究每个调用模式。
例如:sample90.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gt//Function pattern . var my Function = Function(){ return‘foo‘};console . log(my function());//日志“foo”。//Method pattern . var my object = { my function:function(){ return‘bar;} } console . log(my object . my function());//日志‘栏‘。//构造函数pattern . var Cody = function(){ this . living = true;this.age = 33this . gender =‘男‘;this . getgender = function(){ return this . gender;};} var Cody = new Cody();//通过Cody constructor . console . log(Cody)调用;//记录cody对象和属性。// apply()和call()pattern . var greet = { runGreet:function(){ console . log(this . name,arguments【0】,arguments【1】);} } var Cody = { name:‘Cody‘};var Lisa = { name:‘Lisa‘};//像在Cody object . greet . runGreet . call(Cody,foo,bar)内部一样调用run greet函数;//日志“cody foo bar”。//像在Lisa object . greet . runGreet . apply(Lisa,【foo,bar】)内部一样调用run greet函数;//日志“lisa foo bar”。/*请注意call()和apply()在如何将参数发送给被调用的函数方面的区别。*/& lt;/script & gt;& lt/body & gt;& lt/html & gt;请确保您了解所有四种调用模式,因为您将遇到的代码可能包含其中任何一种。
匿名函数匿名函数是没有标识符的函数。匿名函数主要用于将一个函数作为参数传递给另一个函数。
例如:sample91.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gt//function(){ console . log(‘hi‘);};//匿名函数,但无法调用它。//创建一个可以调用我们的匿名函数的函数。var say hi = function(f){ f();//调用匿名函数。}//将匿名函数作为参数传递。say hi(function(){ console。log(‘hi‘);});//日志“嗨”。& lt/script & gt;& lt/body & gt;& lt/html & gt;自调用函数表达式函数表达式(实际上是除了从Function()构造函数创建的函数之外的任何函数)可以在使用括号运算符定义后立即调用。在下面的示例中,我们创建了一个sayWord()函数表达式,然后立即调用该函数。这被认为是一个自调用函数。
例如:sample92.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar say Word = function(){ console . log(‘Word 2 yo mo!‘);} ();//Logs‘Word 2 yomo!‘& lt/script & gt;& lt/body & gt;& lt/html & gt;自调用匿名函数语句可以创建自调用匿名函数语句。这被称为自调用匿名函数。在下面的例子中,我们创建了几个被立即调用的匿名函数。
例如:sample93.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gt//野外最常用/见到的。(function(msg){ console . log(msg);})(‘嗨’);//略有不同,但实现了相同的事情:(function(msg){ console . log(msg)}(‘Hi‘);//最短的可能解决方案。!function say hi(msg){ console . log(msg);}(‘Hi’);//仅供参考,这不起作用!//function say hi(){ console . log(‘hi‘);}();& lt/script & gt;& lt/body & gt;& lt/html & gt;根据ECMAScript标准,如果您想立即调用一个函数,则需要将该函数括起来(或者将该函数转换为表达式中的任何内容)。
函数可以嵌套。函数可以无限地嵌套在其他函数中。在下面的代码示例中,我们将goo函数封装在bar函数中,该函数位于foo函数中。
例如:sample94.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar foo = function(){ var bar = function(){ var goo = function(){ console . log(this);//记录对head window对象的引用。} ();} ();} ();& lt/script & gt;& lt/body & gt;& lt/html & gt;这里的简单概念是函数可以嵌套,并且嵌套深度没有限制。
请记住,这个嵌套函数的值将是JavaScript 1.5和ECMA 262版本3中的header对象(Web浏览器中的window对象)。
将函数传递给函数并从函数返回函数如前所述,函数是JavaScript中的一等公民。由于函数是一个值,并且函数可以传递任何类型的值,因此函数可以传递给函数。接受和/或返回其他函数的函数有时被称为“高阶函数”。
在下面的代码中,我们将一个匿名函数传递给foo函数,然后立即从foo函数返回它。变量bar指向这个匿名函数,因为foo接受并返回匿名函数。
例如:sample95.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gt//函数可以发送到functions,也可以从Functions返回。} var bar = foo(function(){ console . log(‘Hi‘);});bar();//日志“嗨”。& lt/script & gt;& lt/body & gt;& lt/html & gt;因此,在调用bar时,它将调用传递给foo()函数的匿名函数,然后从foo()函数返回并从bar引用变量。所有这些都是为了表明这样一个事实:函数可以像任何其他值一样传递。
在定义函数语句之前调用函数语句(也称为函数提升)在执行过程中,函数语句可以在其实际定义之前调用。这有点奇怪,但你应该意识到这一点,以便你可以利用它,或者至少知道当你遇到它时会发生什么。在下面的示例中,我在定义sayYo()和sum()函数语句之前调用了它们。
例如:sample96.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gt//Example 1 var speak = function(){ sayYo();// sayYo()尚未定义,但仍可调用,日志“Yo”。function sayYo(){ console . log(‘Yo‘);}} ();// Invoke//示例2 console . log(sum(2,2));// Invoke sum(),尚未定义,但仍可调用。function sum(x,y){ return x+y;} & lt/script & gt;& lt/body & gt;& lt/html & gt;发生这种情况是因为函数语句在代码运行之前被解释并添加到执行堆栈/上下文中。使用函数语句时,请务必意识到这一点。
定义为函数表达式的函数不会被提升。仅提升函数语句。
函数可以调用自身(也称为递归)。函数调用自身是完全合法的。事实上,这在众所周知的编码模式中经常使用。在下面的代码中,我们启动了countDownFrom函数,然后该函数通过函数名countDownFrom调用自身。本质上,这创造了一个从5到0的循环。
例如:sample97.html
& lt!DOCTYPE html & gt& lthtml lang = & quoten & quot& gt& ltbody & gt& lt脚本& gtvar countDownFrom =函数count down from(num){ console . log(num);num-;//更改参数值。if(num & lt;0){返回false}//If num & lt;0返回没有递归的函数。//如果是匿名函数,也可以执行arguments . callee(num);};countdowfrom(5);//启动函数,该函数分别记录5,4,3,2,1,0。& lt/script & gt;& lt/body & gt;& lt/html & gt;您应该意识到函数调用自身(也称为递归)或重复执行此操作是很自然的。
结论函数是JavaScript最常用的方面之一。我希望你现在能更好地理解如何使用它们。