JavaScript——Function类型

来源:互联网 发布:达梦数据库安装教程 编辑:程序博客网 时间:2024/06/06 09:07
1、基本概念:
函数实际上是对象,每个函数都是Function类型的实例,函数名则是一个指向函数对象的指针,不会与某个函数绑定。
2、函数定义的3种方式:
(1) 使用函数声明语法定义:
function sum ( num1, num2 ) {
return num1 + num2 ;
}
(2) 使用函数表达式定义:
var sum = function ( num1, num2 ) {
return num1 + num2 ;
} ;
以上代码定义了变量sum,并将其初始化为一个函数。在使用函数表达式定义函数时,没有必要使用函数名,通过变量sum即可引用函数。要注意函数末尾有一个分号,就像声明其他变量一样。
(3) 使用Function构造函数(不推荐):
var sum = new Function ( "num1", "num2", "return num1 + num2" ) ;
Function构造函数可以接收任意数量的参数,但最后一个参数被看成函数体,前面的参数为函数的参数。
function sum ( num1, num2 ) {
return num1 + num2 ;
}
alert ( sum ( 10, 10 ) ) ; //20
var anotherSum = sum ; // 使用不带圆括号的函数名是访问函数指针,而非调用函数
alert ( anotherSum ( 10, 10 ) ) ; //20
sum = null ;
alert ( anotherSum ( 10, 10 ) ) ; //20
以上代码声明了anotherSum变量,并将其设置为与sum相等。此时,anotherSum与sum就指向了同一个函数,因此anotherSum()也可以被调用并返回结果。即使将sum设置为null,让它与函数“断绝关系”,但仍可以正常调用anotherSum()。
3、没有重载(深入理解)
function addSomeNumber ( num ) {
return num + 100 ;
}
function addSomeNumber ( num ) {
return num + 200 ;
}
ver result = addSomeNumber (100) ; //300
以上代码声明了两个同名函数,而结果是后面的函数覆盖了前面的函数。
4、作为值的函数:
因为JS中的函数名本身就是变量,所以函数名也可以作为值来使用。也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。
function callSomeFunction ( someFunction, someArgument ) {
return someFunction ( someArgument ) ;
}
function add10(num) {
return num + 10 ;
}
var result = callSomeFunction ( add10, 10 );
alart( result ); //20
callSomeFunction()函数接收两个参数:第一个参数是一个函数,第二个参数是眼传递给该函数的参数。要访问函数的指针而不执行函数的话,必须去掉函数名后的圆括号。
5、函数的内部属性:
在函数内部,有两个特殊对象:arguments 和 this。
(1) argument:
arguments是一个类数组对象,包含着传入函数中的所有参数,主要用途是保存函数参数。
这个对象还有一个名为callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。
用递归算法定义阶乘函数:
function factorial (num) {
if (num <= 1) {
return 1;
} else {
return num*arguments.callee(num-1) ;
}
}
上面代码里的arguments.callee(num-1)等价于factorial(num-1),但这样写能消除直接用函数名造成的紧密耦合现象。没有引用函数名factorial,这样无论引用函数时使用的是什么名字,都可以保证正确完成递归调用。
var trueFactorial = factorial ;
factorial = function() {
return 0 ;
} ;
alert ( trueFactorial(5) ) ; // 120
alert ( factorial(5) ) ; // 0
变量trueFactorial 获得了factorial 的值,实际上是在另一个位置上保存了一个函数的指针。然后又将一个返回0的函数赋值给factorial变量。如果不使用arguments.callee,而是使用factorial(),调用trueFactorial 就会返回0。在解除了函数体内的代码与函数名的紧耦合状态之后,trueFactorial ()仍能正确地计算阶乘。
(2) this:
this引用的是函数执行的环境对象,当在网页的全局作用域中调用函数时,this对象引用的就是window。
window.color = "red" ;
var o = { color: "blue" } ;
function sayColor() {
alert( this.color ) ;
}
sayColor() ; // red
o.sayColor = sayColor ;
o.sayColor() ; // blue
当在全局作用域中调用sayColor()时,this引用的是全局对象window,即对this.color求值会转换成对window.color求值,于是结果为“red”。当把函数赋给对象o并调用o.sayColor()时,this引用的对象是o,因此对this.color求值会转换成对o.color求值,结果就返回“blue”。
注:函数的名字仅仅是一个包含指针的变量。即使是在不同的环境中执行,全局的sayColor()函数与o.sayColor()函数指向的仍然是同一个函数。
(3) 函数对象属性:caller
caller属性中保存着调用当前函数的函数的引用。如果在全局作用域中调用当前函数,它的值为null。
function outer() {
inner() ;
}
function inner() {
alert(inner.caller) ; // 替换为 alert(arguments.callee.caller) ; 可实现松耦合
}
outer() ; // 显示outer()函数的源代码
因为outer()调用了inner(),所以inner.caller就指向outer()。
为了实现更松散的耦合,也可以通过arguments.callee.caller来访问相同的信息。
6、函数属性和方法:
每个函数都包含两个属性:length 和 prototype。
每个函数都包含两个非继承而来的方法:apply() 和 call() 。
(1) length属性:表示函数希望接收的命名参数的个数。
function sayName(name) {
alert (name) ;
}
function sum(num1, num2) {
return num1 + num2 ;
}
function sayHi() {
alert("Hi") ;
}
alert(sayName.length) ; // 1
alert(sum.length) ; // 2
alert(sayHi.length) ; // 0
(2) prototype属性:
对于引用类型而言,prototype是保存他们所有实例方法的真正所在。诸如toString()和valueOf()等方法实际上都保存在prototype名下,只不过通过各自的实例对象访问。
在创建自定义引用类型及实现继承时,prototype属性是即为重要的。
(3) apply() 方法和 call() 方法:
这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this的值。两个方法的作用相同,区别仅在于接收参数的方式不同。
apply() 方法接收两个参数:一个是运行函数的作用域,另一个是参数数组。其中参数数组可以是Array的实例,也可以是auguments对象。
对于call() 方法,接收的参数第一个与apply() 方法相同,不同的是传递给函数的参数必须逐个列举出来。
至于采用哪种方法,完全取决于你采取哪种给函数传递参数的方式最方便。
function sum(num1, num2) {
return num1 + num2 ;
}
function callSum1 ( num1, num2 ) {
return sum.apply ( this, arguments ) ; // 传入arguments对象
}
function callSum2 ( num1, num2 ) {
return sum.apply ( this, [ num1, num2 ] ) ; // 传入数组实例
}
function callSum3 ( num1, num2 ) {
return sum.call ( this, num1, num2 ) ; // 逐个列举传入参数
}
alert( callSum1( 10, 10 ) ) ; // 20
alert( callSum2( 10, 10 ) ) ; // 20
alert( callSum3( 10, 10 ) ) ; // 20
事实上,传递参数并非apply() 和 call() 真正的用武之地,它们真正强大的地方是能够扩充函数赖以运行的作用域。
window.color = "red" ;
var o = { color: "blue" } ;
function sayColor() {
alert( this.color ) ;
}
sayColor() ; // red
sayColor.call ( this ) ; //red
sayColor.call ( window) ; //red
sayColor.call ( o ) ; // blue
sayColor() 是作为全局函数定义的,当在全局作用域中调用它时就会显示“red“;而当运行sayColor.call (o) 时,函数的执行环境就变了,此时函数体内的this对象指向了o,于是结果显示的是"blue"。
使用call() 和 apply() 来扩充作用域的最大好处是对象不需要与方法有任何耦合关系。
(4) bind() 方法:
该方法会创建一个函数的实例,其this值会被绑定到传给bind() 函数的值。
window.color = "red" ;
var o = { color: "blue" } ;
function sayColor() {
alert( this.color ) ;
}
var objectSayColor = sayColor.bind(o) ;
objectSayColor () ; // blue
sayColor() 调用bind() 并传入对象o,创建了objectSayColor () 函数。

原创粉丝点击