6.1函數定義和函數調用
6.1.1 函數的定義
6.1.1.1聲明式函數定義與函數表達式及其例子
function f2(){alert()};//命名方式
var f1 = function(){alert()};//匿名方式
聲明式函數定義與函數表達式.html
<html>
<head>
<title>Example-6.1(1)聲明式函數定義與函數表達式</title>
</head>
<body>
<script>
<!--
function dwn(s){
document.write(s + "<br/>");
}
function t1(){//聲明式函數
dwn("t1");
}
t1();
function t1(){//重新聲明瞭一個新的t1
dwn("new t1");
}
t1();
t1 = function(){//用函數表達式給t1重新複製
dwn("new new t1");
}
t1();
-->
</script>
</body>
</html>
運行結果:
new t1
new new t1
function step(a){
return function(x){
return x + a++;//返回的閉包中引用了函數step調用對象域的屬性a
//所以它不會被銷燬
}
}
return語句後的表達式如果默認,或者程序執行到函數體的末尾,那麼函數的返回值就爲undefined
<html>
<head>
<title>Example-6.8 利用arguments實現的函數重載機制</title>
</head>
<body>
<script>
<!--
function dwn(s){
document.write(s + "<br/>");
}
//$overload用來匹配參數類型和參數值,自動調用符合條件的重載函數
function $overload(func,argMaps,owner){
//owner是函數的所有者,即調用對象
owner = owner || null;
var args = [];
for(var i = 0; i < argMaps.length;i++){
//判斷argMaps中存放的參數類型聲明是否同實際的參數類型相匹配
if(argMaps[i].type != typeof(argMaps[i].arg) && !(argMaps[i].arg
instanceof argMaps[i].type)){
throw new Error("參數不匹配");//不匹配則拋出異常
}
args.push(argMaps[i].arg); //否則將參數放入args數組準備調用
}
return func.apply(owner,args);
}
function Point(x,y){
this.x = x;
this.y = y;
}
function Vector(x,y){
//私有方法,簡單封裝一個argMaps的結構
function $t(type,arg){
return {type:type,arg:arg};
}
//用向量構造向量
function vector_vector(v){
this.x = v.x;
this.y = v.y;
}
//用點構造向量
function point_vector(p){
this.x = p.x;
this.y = p.y;
}
//用x,y座標構造向量
function number_number_vector(x,y){
this.x = x;
this.y = y;
}
//用兩個點所構成的線段構造向量
function point_point_vector(p1,p2){
this.x = p2.x - p1.x;
this.y = p2.y - p1.y;
}
//參數類型對應表,根據這個表指派正確的函數進行調用
var funcs = [
[number_number_vector,[$t("number",x),$t("number",y)]],
[point_point_vector,[$t(Point,x),$t(Point,y)]],
[vector_vector,[$t(Vector,x)]],
[point_vector,[$t(Point,x)]],
];
//如果不帶參數調用,默認調用Vector(0,0);
if(arguments.length == 0){
Vector.call(this,0,0);
}
for(var i = 0;i < funcs.length; i++){
try{
//嘗試選擇合適的funcs進行調用
return $overload(funcs[i][0],funcs[i][1],this);
} catch(ex){
}
}
//如果參數類型和上面列表中的任何一個都不匹配,則拋出異常
throw new Error("參數不匹配!");
}
//重載toString()方法,便於顯示
Vector.prototype.toString = function(){
return "[" + this.x + "," + this.y + "]";
}
try{
var v1 = new Vector(1,2); //用x,y形式構造Vector
dwn(v1);
var p1 = new Point(0,3);
var p2 = new Point(2,4);
var v2 = new Vector(p1); //用單點形式構造Vector
var v3 = new Vector(p1,p2); //用兩點確定的線段的形式構造Vector
dwn(v2);
dwn(v3);
var v4 = new Vector("str"); //用字符串構造,類型都不匹配,拋出異常
}catch(ex){
dwn(ex.message);
}
-->
</script>
</body>
</html>
6.3函數的調用者和所有者
6.3.1函數的調用者
6.3.2函數的所有者——一個爲函數指定所有者的例子
<script>
var outVar = 1;
function out(){
this.outVar = 2;
console.log(this.outVar);
console.log(this.constructor);
}
function test(){
out();
console.log(this.constructor);
}
new test();
</script>
<script>
var varTmp = 3;
function test(){
var varTmp = 1;
this.temp = 5;
function inner(){ //這個函數只能在test裏面訪問,在外面是訪問不了的
console.log("訪問包含這個函數的函數的屬性:" + varTmp); //可以訪問
// console.log("訪問包含這個函數的公開屬性" + temp); //報錯
console.log("訪問包含這個函數的公開屬性" + this.temp); //undefined
console.log(this.varTmp); //但是這個函數裏面的this指向的既然是window
}
console.log(inner()+ " " +this.constructor);
}
new test();
// inner(); //在這裏是訪問不了test()函數中的inner()方法
</script>
<html>
<head>
<title>Example-6.10 用call和apply調用函數</title>
</head>
<body>
<script>
<!--
function dwn(s){
document.write(s + "<br/>");
}
//定義一個Point類型
function Point(x,y){
this.x = x;
this.y = y;
this.toString = function(){
return "(" + [x,y] + ")";
}
}
//定義一個Vector類型
function Vector(x,y){
this.x = x;
this.y = y;
this.toString = function(){
return "[" + [x,y] + "]";
}
}
//這個函數將傳入的參數累加到對象的x、y屬性上
function add(x,y){
return new this.constructor(this.x + x,this.y + y);
}
var p = new Point(1,2);
var v = new Vector(-1,2);
var p1 = add.call(p,3,4); //把add函數作爲p的方法調用
var v1 = add.apply(v,[3,4]); //把add函數作爲v的方法調用
dwn(p1);
dwn(v1);
-->
</script>
</body>
</html>
javascript可以將函數作爲數據對象使用,作爲函數本體,它像普通的數據對象一樣,不一定要有名字。默認名字的函數被稱爲“匿名函數”。<script>
(function(){
var defaultX = 0; //局部域
var defaultY = 0; //局部域
Point = function(x,y){ //全局域
this.x = x || defaultX;
this.y = y || defaultY;
}
})();
</script>
作爲動態腳本語言,JavaScript擁有解析和執行自身數據的能力,這是通過兩個操作實現的,第一個是前面見過的eval函數,它將字符串作爲代碼來解析執行,另一個就是Function函數。
<script>
new Function("alert('abc')")();//彈出abc
//相當於
a = function(){
alert('abc');
};
a();
</script>
作爲函數:
<script>
Function("alert('abc')")();
</script>
函數工廠是一種模板,它用來創建一組具有某類功能的函數。
<script>
//count定義骰子的數量,side定義每個骰子的面數,each爲骰子修正數
function dice(count,side,ench){
var ench = ench || Math.floor(Math.random() * 6); //+0~+5的骰子隨機變數修正
//返回一個閉包,這個閉包負責"擲"骰子
return function(){
var score = 0;
for(var i = 0; i < count; i++){
score += Math.floor(Math.random() * side) + 1;
}
return score + ench;
}
}
var d1 = dice(2,6); //生成一組2d6+n的骰子,其中的n爲0~5的隨機數
var d2 = dice(1,20); //生成一顆20面的骰子,帶有0~6的隨機點數修正
for(var i = 0; i < 100; i++){
console.log(d1());
}
console.log("============================================");
console.log("============================================");
for(var i = 0; i < 100; i++){
console.log(d2());
}
</script>
<html>
<head>
<title>Example-6.16</title>
</head>
<body>
<script>
<!--
function dwn(s){
document.write(s + "<br/>");
}
function ListTemplate(type){//一個集合模板,可以用來構造任何一種類型的"集合"
var members = [];
var list = function(){ //定義一個list構造函數
this.append.apply(this,arguments);
}
list.prototype.append = function(){//list.append()方法,這個方法的作用是往集合中添加元素
for(var i = 0;i < arguments.length; i++){
if(typeof(arguments[i]) == type ||
(typeof(type) == 'function' && arguments[i] instanceof(type))){
members.push(arguments[i]);
}else{
throw new TypeError('元素類型與集合聲明不符合');
//當添加的元素與集合聲明的類型不匹配時,將會拋出TypeError異常
}
}
list.prototype.toArray = function(){//toArray方法將集合轉換爲數組
console.log(members);
return members.slice(0);
}
}
return list;
}
NumberList = new ListTemplate("number");
//構建一個數值集合,要求集合中的每一個元素都必須是數值
var a = new NumberList(1,2,3);
dwn(a.toArray());
a.append(4,5,6);
dwn(a.toArray());
ObjectList = new ListTemplate(Object);
//構建一個Object集合,要求集合中的每一個元素都必須是Object元素
var b = new ObjectList({x:1,y:2},{x:3,y:4});
dwn(b.toArray());
function Point(x,y){
this.x = x;
this.y = y;
}
Point.prototype.toString = function(){
return "(" + this.x + "," + this.y + ")";
}
PointList = new ListTemplate(Point);
//構建一個集合,要求集合中的每一個元素都是一個Object
var c = new PointList();
c.append(new Point(1,3),new Point(2,4));
dwn(c.toArray());
-->
</script>
</body>
</html>
對於JavaScript來說,函數是“第一型”。