javascript的函数
子乌注:一篇相当不错的function入门文章,个人感觉相当经典。
词语翻译列表
function:函数(Function未翻译)
declare:定义
assign:指派,分配
functionbody:函数体(就是函数的内容)
object:对象
property:属性
unnamed:匿名(在这里没翻译成未命名)
object oriented programming:面相对相编程
class:类(比如后面的class data type我翻译成类数据类型)
pointer:指针
reassign:重新分配
nest:嵌套
feature:功能,特性
local/global:局部/全局
blueprint:蓝图(?)
user defined:用户自定义
instance:实例
prototype:原型(除了标题都不翻译)
internal:内部
constructor:构造器
duplication:复制
函数:定义
有以下这些方法可以定义一个函数。所有这些都是有效的,但是它们在后台如何实现的则有一些差别。
常用的写法
一般大家都用这个写法来定义一个函数:
functionName([parameters]){functionBody};
Example D1:
Language:javascript, parsed in: 0.005 seconds, using GeSHi 1.0.7.12
function add( a, b)
{
return a+b;
}
alert ( add( 1 ,2 ) ) ; // 结果 3
运行示例
当我们这么定义函数的时候,函数内容会被编译(但不会立即执行,除非我们去调用它)。而且,也许你不知道,当这个函数创建的时候有一个同名的对象也被创建。就我们的例子来说,我们现在有一个对象叫做“add”(要更深入了解,看底下函数:对象 节。)
匿名函数
我们也可以通过指派一个变量名给匿名 函数的方式来定义它。
Example D2
Language:javascript, parsed in: 0.006 seconds, using GeSHi 1.0.7.12
var add=function ( a, b)
{
return a+b;
}
alert ( add( 1 ,2 ) ) ; // 结果 3
运行示例
这个代码和前一个例子做了同样的事情。也许语法看起来比较奇怪,但它应该更能让你感觉到函数是一个对象,而且我们只是为这个对指派了一个名称。可以把它看做和var myVar=[1,2,3]
一样的语句。以这种方式声明的函数内容也一样会被编译。
当我们指派一个这样的函数的时候,我们并不一定要求必须是匿名 函数。在这里,我作了和ExampleD2 一样的事情,但我加了函数名“theAdd ”,而且我可以通过调用函数名或者是那个变量来引用函数。
Example D2A
Language:javascript, parsed in: 0.008 seconds, using GeSHi 1.0.7.12
var add=function theAdd( a, b)
{
return a+b;
}
alert ( add( 1 ,2 ) ) ; // 结果 3
alert ( theAdd( 1 ,2 ) ) ; // 结果也是 3
运行示例
使用这种方式来定义函数在面向对象编程中是很有用的,因为我们能像底下这样使一个函数成为一个对象 的属性 。
Language:javascript, parsed in: 0.005 seconds, using GeSHi 1.0.7.12
var myObject=new Object( ) ;
myObject.add =function ( a,b) { return a+b} ;
// myObject 现在有一个叫做“add”的属性(或方法)
// 而且我能够象下面这样使用它
myObject.add ( 1 , 2 ) ;
new
我们也能够通过使用运算符new 来定义一个函数。
这是一个最少见的定义函数的方式并且并不推荐使用这种方式除非有特殊的理由(可能的理由见下)。语法如下:
varName=new Function([param1Name, param2Name,...paramNName], functionBody);
Example D3:
Language:javascript, parsed in: 0.004 seconds, using GeSHi 1.0.7.12
var add=new Function ( "a" , "b" , "return a+b;" ) ;
alert ( add( 3 ,4 ) ) ; // 结果 7
运行示例
我在这里有两个参数叫做a 和b ,而函数体 返回a 和b 的和。请注意new Function(...)
使用了大写F ,而不是小写f。 这就告诉javascript,我们将要创建一个类型是Function的对象。 还要注意到,参数名和函数体都是作为字符串而被传递。我们可以随心所欲的增加参数,javascript知道函数体会是右括号前的最后一个字符串(如果没有参数,你能够只写函数体)。你没必要将所有东西都写在一行里(使用\
或者使用字符串连接符+
来分隔长代码)。\
标记告诉JavaScript在下一行查找字符串的其余部分。例子如下:
Example D4
Language:javascript, parsed in: 0.007 seconds, using GeSHi 1.0.7.12
// 注意 "+"
// 和 "\"的不同用法
var add=new Function ( "a" , "b" ,
"alert" +
"('adding '+a+' and ' +b);\
return a+b;" ) ;
alert ( add( 3 ,4 ) ) ; // 结果 7
javascript:exampleD4();
采用这种方式定义函数会导致函数并没被编译,而且它有可能会比用其它方式定义的函数要慢。至于为什么,看一下这个代码:
Example D5
Language:javascript, parsed in: 0.022 seconds, using GeSHi 1.0.7.12
function createMyFunction( myOperator)
{
return new Function ( "a" , "b" , "return a" + myOperator + "b;" ) ;
}
var add=createMyFunction( "+" ) ; // 创建函数 "add"
var subtract=createMyFunction( "-" ) ; // 创建函数 "subtract"
var multiply=createMyFunction( "*" ) ; // 创建函数 "multiply"
// test the functions
alert ( "加的结果=" +add( 10 ,2 ) ) ; // 结果是 12
alert ( "减的结果=" +subtract( 10 ,2 ) ) ; // 结果是 8
alert ( "乘的结果=" +multiply( 10 ,2 ) ) ; // 结果是 20
alert ( add) ;
运行示例
这个有趣的例子创建了三个不同的function ,通过实时传递不同的参数来创建一个新Function 。因为编译器没法知道最终代码会是什么样子的,所以new Function(...)
的内容不会被编译。那这有什么好处呢?嗯,举个例子,如果你需要用户能够创建他们自己的函数的时候这个功能也许很有用,比如在游戏里。我们也许需要允许用户添加“行为”给一个“player”。但是,再说一次,一般情况下,我们应该避免使用这种形式,除非有一个特殊的目的。
函数:对象
函数是javascript中的一种特殊形式的对象。它是第一个类数据类型 。这意味着我们能够给它增加属性。这里有一些需要注意的有趣观点:
对象的创建
就像刚才提及的,当我们定义一个函数时,javascript实际上在后台为你创建了一个对象。这个对象的名称就是函数名本身。这个对象的类型是function。在下面的例子,我们也许不会意识到这一点,但我们实际上已经创建了一个对象:它叫做Ball 。
Example 1
Language:javascript, parsed in: 0.006 seconds, using GeSHi 1.0.7.12
function Ball( ) // 也许看起来有点奇怪,但是这个声明
{ // 创建了一个叫做Ball的对象
i=1 ;
}
alert ( typeof Ball) ; // 结果 "function"
运行示例
我们甚至能将这个对象的内容打印出来而且它会输出这个函数的实际代码,Example 2: 点击 alert(Ball); 来看看Ball 的内容。
属性的添加
我们能够添加给Object 添加属性,包括对象function 。因为定义一个函数的实质是创建一个对象。我们能够“暗地里”给函数添加属性。比如,我们这里定义了函数Ball ,并添加属性callsign 。
Language:javascript, parsed in: 0.007 seconds, using GeSHi 1.0.7.12
function Ball( ) // 也许看起来有点奇怪,但是这个声明
{ // 创建了一个叫做Ball的对象,而且你能够
} // 引用它或者象下面那样给它增加属性
Ball.callsign ="The Ball" ; // 给Ball增加属性
alert ( Ball.callsign ) ; // 输出 "The Ball"
运行示例
指针
因为function 是一个对象,我们能够为一个function 分配一个指针。如下例,变量ptr 指向了对象myFunction 。
Language:javascript, parsed in: 0.005 seconds, using GeSHi 1.0.7.12
function myFunction( message)
{
alert ( message) ;
}
var ptr=myFunction; // ptr指向了myFunction
ptr( "hello" ) ; // 这句会执行myFunction:输出"hello"
运行示例
我们能够运行这个函数,就好像这个函数名已经被指针名代替了一样。所以在上面,这行ptr("hello");
和myFunction("hello");
的意义是一样的。
指向函数的指针在面向对象编程中相当有用。例如:当我们有多个对象指向同一个函数的时候(如下):
Example 4A
Language:javascript, parsed in: 0.017 seconds, using GeSHi 1.0.7.12
function sayName( name )
{
alert ( name ) ;
}
var object1=new Object( ) ; // 创建三个对象
var object2=new Object( ) ;
var object3=new Object( ) ;
object1.sayMyName =sayName; // 将这个函数指派给所有对象
object2.sayMyName =sayName;
object3.sayMyName =sayName;
object1.sayMyName ( "object1" ) ; // 输出 "object1"
object2.sayMyName ( "object2" ) ; // 输出 "object2"
object3.sayMyName ( "object3" ) ; // 输出 "object3"
运行示例
因为只有指针被保存(而不是函数本身),当我们改变函数对象自身的时候,所有指向那个函数的指针都会发生变化。我们能够在底下看到:
Example 5:
Language:javascript, parsed in: 0.016 seconds, using GeSHi 1.0.7.12
function myFunction( )
{
alert ( myFunction.message ) ;
}
myFunction.message ="old" ;
var ptr1=myFunction; // ptr1 指向 myFunction
var ptr2=myFunction; // ptr2 也指向 myFunction
ptr1( ) ; // 输出 "old"
ptr2( ) ; // 输出 "old"
myFunction.message ="new" ;
ptr1( ) ; // 输出 "new"
ptr2( ) ; // 输出 "new"
运行示例
指针的指向
我们能够在一个函数创建之后重新分配它,但是我们需要指向函数对象本身,而不是指向它的指针。在下例中,我将改变myfunction() 的内容。
Example 6:
Language:javascript, parsed in: 0.007 seconds, using GeSHi 1.0.7.12
function myFunction( )
{
alert ( "Old" ) ;
}
myFunction( ) ; // 输出 "Old"
myFunction=function ( )
{
alert ( "New" ) ;
} ;
myFunction( ) ; // 输出 "New"
运行示例
旧函数哪里去了??被抛弃了。
如果我们需要保留它,我们可以在改变它之前给它分配一个指针。
Example 6A:
Language:javascript, parsed in: 0.008 seconds, using GeSHi 1.0.7.12
function myFunction( )
{
alert ( "Old" ) ;
}
var savedFuncion=myFunction;
myFunction=function ( )
{
alert ( "New" ) ;
} ;
myFunction( ) ; // 输出 "New"
savedFuncion( ) ; // 输出 "Old"
运行示例
不过要小心,象下面这样的例子并不会有作用,因为是创建了另一个叫做myFunctionPtr 的函数而不是修改它。
Example 6B:
Language:javascript, parsed in: 0.009 seconds, using GeSHi 1.0.7.12
function myFunction( )
{
alert ( "Old" ) ;
}
var savedFunc=myFunction;
savedFunc=function ( )
{
alert ( "New" ) ;
} ;
myFunction( ) ; // 输出 "Old"
savedFunc( ) ; // 输出 "New"
运行示例
内嵌函数
我们还能够在一个函数 中嵌套一个函数 。下例,我有一个叫做getHalfOf 的函数,而在它里面,我有另一个叫做calculate 的函数。
Example 7
Language:javascript, parsed in: 0.015 seconds, using GeSHi 1.0.7.12
function getHalfOf( num1, num2, num3)
{
function calculate( number)
{
return number/2 ;
}
var result="" ;
result+=calculate( num1) +" " ;
result+=calculate( num2) +" " ;
result+=calculate( num3) ;
return result;
}
var resultString=getHalfOf( 10 ,20 ,30 ) ;
alert ( resultString) ; // 输出 "5 10 15"
运行示例
你只能在内部调用嵌套的函数。就是说,你不能这么调用:getHalfOf.calculate(10)
,因为calculate 只有当外部函数(getHalfOf() )在运行的时候才会存在。这和我们前面的讨论一致(函数会被编译,但只有当你去调用它的时候才会执行)。
调用哪个函数?
你也许正在想命名冲突的问题。比如,下面哪一个叫做calculate 的函数会被调用?
Example 8
Language:javascript, parsed in: 0.017 seconds, using GeSHi 1.0.7.12
function calculate( number)
{
return number/3 ;
}
function getHalfOf( num1, num2, num3)
{
function calculate( number)
{
return number/2 ;
}
var result="" ;
result+=calculate( num1) +" " ;
result+=calculate( num2) +" " ;
result+=calculate( num3) ;
return result;
}
var resultString=getHalfOf( 10 ,20 ,30 ) ;
alert ( resultString) ; // 输出 "5 10 15"
运行示例
在这个例子中,编译器会首先搜索局部内存地址,所以它会使用内嵌的calculate 函数。如果我们删除了这个内嵌(局部)的calculate 函数,这个代码会使用全局的calculate 函数。
函数:数据类型及构造函数
让我们来看看函数 的另一个特殊功能--这让它和其它对象类型截然不同。一个函数能够用来作为一个数据类型的蓝图。这个特性通常被用在面向对象编程中来模拟用户自定义数据类型(user defined data type) 。使用用户自定义数据类型创建的对象通常被成为用户自定义对象(user defined object) 。
数据类型
在定义了一个函数之后,我们也同时创建了一个新的数据类型。这个数据类型能够用来创建一个新对象。下例,我创建了一个叫做Ball 的新数据类型。
Example DT1
Language:javascript, parsed in: 0.004 seconds, using GeSHi 1.0.7.12
function Ball( )
{
}
var ball0=new Ball( ) ; // ball0 现在指向一个新对象
alert ( ball0) ; // 输出 "Object",因为 ball0 现在是一个对象
运行示例
这样看来,ball0=new Ball()
作了什么?new 关键字创建了一个类型是Object 的新对象(叫做ball0 )。然后它会执行Ball()
,并将这个引用传给ball0 (用于调用对象)。下面,你会看到这条消息:“creating new Ball”,如果Ball()
实际上被运行的话。
Example DT2
Language:javascript, parsed in: 0.009 seconds, using GeSHi 1.0.7.12
function Ball( message)
{
alert ( message) ;
}
var ball0=new Ball( "creating new Ball" ) ; // 创建对象并输出消息
ball0.name ="ball-0" ; // ball0现在有一个属性:name
alert ( ball0.name ) ; // 输出 "ball-0"
运行示例
我们可以把上面这段代码的高亮的一行看做是底下的代码高亮处的一个简写:
Language:javascript, parsed in: 0.010 seconds, using GeSHi 1.0.7.12
function Ball( message)
{
alert ( message) ;
}
var ball0=new Object( ) ;
ball0.construct =Ball;
ball0.construct ( "creating new ball" ) ; // 执行 ball0.Ball("creating..");
ball0.name ="ball-0" ;
alert ( ball0.name ) ;
运行示例
这行代码ball0.construct=Ball
和Example 4 中的ptr=myFunction
语法一致。
如果你还是不明白这行的含义那就回过头再复习一下Example 4 。注意:你也许考虑直接运行ball0.Ball("...")
,但是它不会起作用的,因为ball0 并没有一个叫做Ball("...") 的属性,并且它也不知道你究竟想作些什么。
添加属性
当我们象上面那样使用关键字new 创建一个对象的时候,一个新的Object 被创建了。我们可以在创建之后给这个对象添加属性(就好像我在上面那样添加属性name 。而接下来的问题就是如果我们创建了这个对象的另外一个实例,我们得象下面那样再次给这个新对象添加这个属性。)
Example DT3 (creates 3 ball objects)
Language:javascript, parsed in: 0.013 seconds, using GeSHi 1.0.7.12
function Ball( )
{
}
var ball0=new Ball( ) ; // ball0 现在指向了类型Ball的一个新实例
ball0.name ="ball-0" ; // ball0 现在有一个属性"name"
var ball1=new Ball( ) ;
ball1.name ="ball-1" ;
var ball2=new Ball( ) ;
alert ( ball0.name ) ; // 输出 "ball-0"
alert ( ball1.name ) ; // 输出 "ball-1"
alert ( ball2.name ) ; // 哦,我忘记给ball2添加“name”了!
我忘记给ball2 添加属性name 了,如果在正式的程序中这也许会引发问题。有什么好办法可以自动增加属性呢?嗯,有一个:使用this 关键字。this 这个词在function 中有特别的意义。它指向了调用函数的那个对象。让我们看看下面的另一个示例,这时候我们在构造函数中添加上这些属性:
Example DT4
Language:javascript, parsed in: 0.010 seconds, using GeSHi 1.0.7.12
function Ball( message, specifiedName)
{
alert ( message) ;
this .name =specifiedName;
}
var ball0=new Ball( "creating new Ball" , "Soccer Ball" ) ;
alert ( ball0.name ) ; // prints "Soccer Ball"
运行示例
请记住:是new 关键字最终使得构造函数被执行。在这个例子中,它将会运行Ball("creating new Ball", "Soccer Ball");
而关键字this 将指向ball0 。
因此,这行:this.name=specifiedName
变成了ball0.name="Soccer Ball"
。
它主要是说:给ball0 添加属性name ,属性值是Soccer Ball
。
我们现在只是添加了一个name 属性给ball0 ,看起来和上一个例子中所做的很象,但却是一个更好更具扩展性的方法。现在,我们可以随心所欲的创建许多带有属性的ball 而无需我们手动添加它们。而且,人们也希望创建的Ball 对象能够清晰的看懂它的构造函数 并且能够轻松找出Ball 的所有属性。让我们添加更多属性到Ball 里。
Example DT5
Language:javascript, parsed in: 0.026 seconds, using GeSHi 1.0.7.12
function Ball( color, specifiedName, owner, weight)
{
this .name =specifiedName;
this .color =color;
this .owner =owner;
this .weight =weight;
}
var ball0=new Ball( "black/white" , "Soccer Ball" , "John" , 20 ) ;
var ball1=new Ball( "gray" , "Bowling Ball" , "John" , 30 ) ;
var ball2=new Ball( "yellow" , "Golf Ball" , "John" , 55 ) ;
var balloon=new Ball( "red" , "Balloon" , "Pete" , 10 ) ;
alert ( ball0.name ) ; // 输出 "Soccer Ball"
alert ( balloon.name ) ; // 输出 "Balloon"
alert ( ball2.weight ) ; // 输出 "55"
运行示例
嘿!使用面向对象术语,你能够说Ball 是一个拥有如下属性的对象类型:name, color, owner, weight。
将对象赋给属性
我们并没被限制只能添加形如字符串或者数字之类的简单数据类型作为属性。我们也能够将对象赋给属性。下面,supervisor 是Employee 的一个属性.
Example DT6
Language:javascript, parsed in: 0.021 seconds, using GeSHi 1.0.7.12
function Employee( name , salary, mySupervisor)
{
this .name =name ;
this .salary =salary;
this .supervisor =mySupervisor;
}
var boss=new Employee( "John" , 200 ) ;
var manager=new Employee( "Joan" , 50 , boss) ;
var teamLeader=new Employee( "Rose" , 50 , boss) ;
alert ( manager.supervisor .name +" is the supervisor of " +manager.name ) ;
alert ( manager.name +"\' s supervisor is " +manager.supervisor .name ) ;
会输出什么呢?运行示例
就像你在上面这个例子中看到的那样,manager 和teamLeader 都有一个supervisor 属性,而这个属性是类型Employee 的一个对象。
将函数作为属性
任何类型的对象都可以作为一个属性,回忆一下前面的Example 4 (不是Example DT4),函数也是一个对象。所以你可以让一个函数 作为一个对象的一个属性。下面,我将添加两个函数getSalary 和addSalary 。
Example DT7
Language:javascript, parsed in: 0.022 seconds, using GeSHi 1.0.7.12
function Employee( name , salary)
{
this .name =name ;
this .salary =salary;
this .addSalary =addSalaryFunction;
this .getSalary =function ( )
{
return this .salary ;
} ;
}
function addSalaryFunction( addition)
{
this .salary =this .salary +addition;
}
var boss=new Employee( "John" , 200000 ) ;
boss.addSalary ( 10000 ) ; // boss 长了 10K 工资……为什么老板工资可以长这么多:'(
alert ( boss.getSalary ( ) ) ; // 输出 210K……为什么默认工资也那么高……:'(
运行示例
addSalary 和getSalary 演示了几种将函数赋给属性的不同方法。如果你记得我们最开始的讨论;我讨论了三种声明函数的不同方式。所有那些在这里都是适用的,但是上面展示的两个最常用。
让我们看看有什么不同。下面,注意一下9-12行的代码。当这部分代码执行的时候,函数getSalary 被声明。如前面数次提到的,一个函数声明的结果是一个对象被创建。所以这时候boss 被创建(接下来的高亮行),而boss里有一个getSalary 属性。
Language:javascript, parsed in: 0.022 seconds, using GeSHi 1.0.7.12
function Employee( name , salary)
{
this .name =name ;
this .salary =salary;
this .addSalary =addSalaryFunction;
this .getSalary =function ( )
{
return this .salary ;
} ;
}
function addSalaryFunction( addition)
{
this .salary =this .salary +addition;
}
var boss=new Employee( "John" , 200000 ) ;
var boss2=new Employee( "Joan" , 200000 ) ;
var boss3=new Employee( "Kim" , 200000 ) ;
当你创建这个对象的更多实例时(boss2 和boss3 ),每一个实例都有一份getSalary 代码的单独拷贝;而与此相反,addSalary 则指向了同一个地方(即addSalaryFunction )。
看看下面的代码来理解一下上面所描述的内容。
Example DT8
Language:javascript, parsed in: 0.036 seconds, using GeSHi 1.0.7.12
function Employee( name , salary)
{
this .name =name ;
this .salary =salary;
this .addSalary =addSalaryFunction;
this .getSalary =function ( )
{
return this .salary ;
} ;
}
function addSalaryFunction( addition)
{
this .salary =this .salary +addition;
}
var boss1=new Employee( "John" , 200000 ) ;
var boss2=new Employee( "Joan" , 200000 ) ;
// 给getSalary函数对象添加属性
boss1.getSalary .owner ="boss1" ;
boss2.getSalary .owner ="boss2" ;
alert ( boss1.getSalary .owner ) ; // 输出 "boss1"
alert ( boss2.getSalary .owner ) ; // 输出 "boss2"
// 如果两个对象指向同一个函数对象,那么
// 上面两个输出都应该是“boss2”。
// 给addSalary函数对象添加属性
boss1.addSalary .owner ="boss1" ;
boss1.addSalary .owner ="boss2" ;
alert ( boss1.addSalary .owner ) ; // 输出 "boss2"
alert ( boss2.addSalary .owner ) ; // 输出 "boss2"
// 因为两个对象都指向同一个函数,(子
Node.js事件的正确使用方法 这篇文章主要给大家介绍了关于Node.js事件的正确使用方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Node.js具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
评论 0
收藏 0
赞 0
分享
微信小程序自定义导航栏实例代码 这篇文章主要给大家介绍了关于微信小程序自定义导航栏的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用微信小程序具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
评论 0
收藏 0
赞 0
分享
js字符串处理之绝妙的代码 这篇文章主要介绍了js字符串处理之绝妙的代码,包括字符串去重、将字符放在对象中遍历拼接出字符串、把字符串的奇数位和偶数位分别提取到两个数组中、将两个数组按奇数位和偶数位插入拼接为字符串,有时候需要对字符进行处理的时候可以用得到
评论 0
收藏 0
赞 0
分享
vue设计一个倒计时秒杀的组件详解 这篇文章主要介绍了vue设计一个倒计时秒杀的组件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
评论 0
收藏 0
赞 0
分享
详解服务端预渲染之Nuxt(介绍篇) 这篇文章主要介绍了详解服务端预渲染之Nuxt(介绍篇),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
评论 0
收藏 0
赞 0
分享
详解vue中this.$emit()的返回值是什么 这篇文章主要介绍了详解vue中this.$emit()的返回值是什么,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
评论 0
收藏 0
赞 0
分享
vue自定义指令directive的使用方法 这篇文章主要介绍了vue自定义指令directive的使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
评论 0
收藏 0
赞 0
分享
查看更多