関数はいつでもどこでも実行できるステートメントのセットです。関数は ECMAScript の中核として非常に重要です。関数は、呼び出されたときに実行されるイベント駆動型または再利用可能なコードのブロックです。つまり、関数は 1 回定義される JavaScript コードであり、何度でも呼び出しまたは実行できます。関数にはパラメータがある場合があります。これは、関数の呼び出し時に値が割り当てられるローカル変数です。関数は多くの場合、これらのパラメーターを使用して戻り値を計算します。この値は関数呼び出し式の値にもなります。
1. 関数宣言
関数は、あらゆる言語にとって中心的な概念です。関数を通じて任意の数のステートメントをカプセル化でき、いつでもどこでも呼び出して実行できます。 JS の関数は、function キーワードを使用して宣言され、その後にパラメーターのセットと関数本体が続きます。
関数の基本的な構文は次のとおりです:
<span style="font-size:18px;">function functionName(arg0, arg1, ... argN) { statements }</span>
ECMAScript で指定された関数を宣言するには 3 つの方法があります。
(1) 通常の関数宣言
<span style="font-size:18px;">function box(num1,num2){ return num1+num2; }</span>
(2) 変数の初期化または関数宣言を使用する
<span style="font-size:18px;">var box=function(num1,num2){ return num1+num2; }</span>
(3) Function コンストラクターを使用して
を宣言します
function box(){ document.write("我是中国人!"); } box();//函数调用
手術の結果、私は中国人です!
(2) パラメータ付き関数: パラメータ変数は関数の宣言と同時に定義され、パラメータは複数指定できます。
function box(name,age) { document.write("你的姓名是:"+name+"你的年龄是:"+age); } box("张三","24");//函数调用
操作の結果は次のとおりです: あなたの名前は: 張三です
あなたの年齢: 24
(3) 戻り値付き関数
パラメーターの有無にかかわらず、関数には戻り値が定義されていませんが、実際には、どの関数も return ステートメントとその後に返される値によって戻り値を実現できます。
1)、パラメーターなしの関数
function box(){ return "我是中国人!"; } document.write(box());
上記と同じ出力: 私は中国人です!
2)、パラメータ付き関数
function box(name,age){ return "你的姓名是:"+name+"<br/>"+"你的年龄是:"+age; } document.write(box("张三","24"));//函数调用 document.write("<hr/>"); var demo=box("李四","23");//也可以重新赋值新的函数 document.write(demo);
実行の結果は次のとおりです:
(4) 値の関数として (より特殊)
まず、通常の変数としての関数の例を見てみましょう:
function box(sum,num){ return sum+num;//这里传递的是函数的返回值和普通的变量一样 } function sum(num){ return num+10; } var result=box(sum(10),10); document.write("result="+result);
ページの出力結果は次のとおりです: result=30
以下に渡されるのは関数です。上記の関数と慎重に区別してください:
function box(sum,num){ return sum(num);//这里传递的是函数 } function sum(num){ return num+10; } var result=box(sum,10); document.write("result="+result);
ページの出力結果は次のとおりです: result=20
3. 関数の内部属性
? 2 つの特別なオブジェクトがあります: argument オブジェクトと this オブジェクトです。引数オブジェクトは、関数に渡されるすべてのパラメータを含む配列のようなオブジェクトです。その主な目的は、関数のパラメータの数を動的に決定するために使用されます。ただし、このオブジェクトには callee と呼ばれる属性もあり、これは引数オブジェクトを所有する関数へのポインタです。
(1)引数オブジェクトの長さ属性
JS 関数は渡されるパラメーターの数を気にせず、パラメーターの不一致によるエラーは発生しません。実際、関数本体には引数オブジェクト
を通じてアクセスできます。
渡されたパラメータを受け取ります。
まず、関数にパラメータを渡すときに遭遇する問題を見てみましょう。関数が宣言されるとき、定義するパラメータの数はわかりませんが、関数を呼び出すときには
が多すぎます。
問題や欠陥。
function box(){ return arguments[0]+"|"+arguments[1]; } document.write(box(1,2,3,4,5,6));
输出的结果为:1|2。因此输出的显然与我们想要做的不符,那么怎么解决呢?
有了arguments对象的length属性我们就能可以得到参数的数量,避免上面的错误出现。
function box(){ return arguments.length; } document.write(box(1,2,3,4,5,6));
输出:6
我们还可以利用length属性来智能的判断有多少参数,然后把参数进行合理的应用,比如,实现一个加法运算,将所有传进来的数字累加,而数字的个数又不确定。
function box(){ var sum=0; if(arguments.length==0) { return sum; } for(var i=0;i<arguments.length;i++) { sum=sum+arguments[i]; } return sum;//返回累加结果 } document.write(box(1,2,3,4,5,6));
输出:21
(2)arguments对象的callee属性
还是来说问题:对于递归的问题我们很熟悉了,JS中也不例外
function box(num){ if(num<=1) { return 1; } else { return num*box(num-1);//递归 } } document.write(box(4));
输出:24
对于阶乘函数一般要用到递归算法,所以函数内部一定对调用自身,如果函数名不改变是没有问题的,但一旦改变函数名,内部的自身调用需要逐一修改。为了解决这个问题,可以使用arguments.callee来代替。
function box(num){ if(num<=1) { return 1; } else { return num*arguments.callee(num-1)//递归 } } document.write(box(4));
输出:24
(3)this对象
函数内部另一个特殊的对象时this,其行为与Java和C#中的this大致相似,换句话说,this引用的是函数据以行操作的对象,或者说函数调用语句所处的那个作用域。当在全局作用域中调用函数时,this对象引用的就是window(window是一个对象,是JavaScript中最大的对象,是最外围的对象)。
var color="红色";//这里的color是全局变量,并且这个变量是window的属性 document.write(window.color+"<br/>"); document.write(this.color+"<br/>"); var box={ color:"蓝色",//这里的color是box下的属性,是局部变量 sayColor:function(){ return this.color;//此时的this只能是box中的color } }; document.write(box.sayColor()+"<br/>");//局部的 document.write(this.color);//全局的
运行的结果为:
四、函数属性和方法
(1)JavaScript中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length和prototype。其中,length属性表示函数希望接受的命名参数的个数。
function box(num1,num2){ return num1+num2; } document.write(box.length);
输出的结果;2
对于prototype属性,它是保存所有实例方法的真正所在,也就是原型。这个属性我们先不做过多的介绍。prototype属性下有两个方法:apply()和call(),每个函数都包含这两个非继承而来的方法。这两个方法的用途都在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
function box(num1,num2){ return num1+num2; } function sayBox(num1,num2){ return box.apply(this,[num1,num2]);//this表示作用域,这里是window,[]表示box所需的参数 } function sayBox2(num1,num2){ return box.apply(this,arguments);//arguments对象表示box所需的参数 } document.write(sayBox(10,10)+"<br/>"); document.write(sayBox2(10,10));
输出的结果为:20
20
(2)call()方法和apply()方法延伸
call()方法和apply()方法相同,它们的区别仅仅在于接收参数的方式不同。对于call()方法而言,第一个参数作用域,没有变化,变化的只是其余参数都是直接传递给函数的。
function box(num1,num2){ return num1+num2; } function callBox(num1,num2){ return box.call(this,num1,num2);//区别apply()方法 } document.write(callBox(10,10));
输出的结果为:20
call()方法和apply()方法真正的作用是扩展函数赖以运行的作用域
var color="红色";//全局变量 var box={ color:"蓝色",//局部变量 }; function sayColor(){ return this.color; } document.write(sayColor()+"<br/>");//作用域在Window document.write(sayColor.call(this)+"<br/>");//作用域在Window下 document.write(sayColor.call(window)+"<br/>");//作用域在Window下 document.write(sayColor.call(box));//作用域在box下,对象冒充
输出的结果为:
使用call()方法或者apply()方法来扩充作用域的最大好处就是对象不需要与方法发生任何耦合关系。也就是说,box对象和sayColor()方法之间不会有多余的关联操作,比如;box.sayColor=sayColor;
五、ECMAScript闭包
ECMAScrip最易让人误解的一点是,它支持闭包。闭包,指的是词法表示包括不被计算的变量的函数,就是说,函数可以使用函数之外定义的变量。
其实我在前面的博文已经使用到了闭包,比如在轻松学习JavaScript七:JavaScript的流程控制语句中使用的变量time就是全局变量,函数myFunction()使用这个全局变量,并不是函数本身定义的。还是看一下那个实例吧:
var time=new Date().getHours(); document.write("当前北京时间:"+time); function myFunction() { var x=""; if (time<20) { x="Good day"; } document.getElementById("demo").innerHTML=x; }
(1)简单的闭包实例
在ECMAScript中使用全局变量是一个简单的闭包实例。请思考下面这段代码输出的结果是什么:
var sMessage = "hello world"; function sayHelloWorld() { document.write(sMessage); } sayHelloWorld();
在上面这段代码中,脚本被载入内存后,并没有为函数sayHelloWorld()计算变量sMessage的值。该数捕 sMessage的值只是为了以后的使用,也就是说,解释程序知道在调用该函数时要检查sMessage的值。sMessage将在函数调用sayHelloWorld()是在(最后一行)被赋值,显示消息"hello world"。
(2)复杂的闭包实例
在一个函数中定义另一个会使闭包变得更加复杂。例如:
var iBaseNum = 10;//全局变量 function addNum(iNum1, iNum2) { function doAdd() { return iNum1 + iNum2 + iBaseNum; } return doAdd(); } document.write(addNum(10,10));
这里,函数addNum()包括函数doAdd()(闭包)。内部函数是一个闭包,因为它将获取外部函数的参iNum1和iNum2以及全局变量iBaseNum的值。 addNum()的最后一步调用了doAdd(),把两个参数和全局变量相加,并返回它们的和。这里要掌握的重要概念是,doAdd()函数根本不接受参数,它使用的值是从执行环境中获取的,因此输出的结果为:30。
可以看到,闭包是 ECMAScript 中非常强大多用的一部分,可用于执行复杂的计算。就像使用任何高级函数一样,使用闭包要小心,因为它们可能会变得非常复杂。
以上就是本文的全部内容,希望对大家的学习有所帮助。