javascript function
javascript函数是用function定义,也可称为类定义。
函数的声明:
1.
function sum(a, b) {
return a + b;
}
var c = sum(1, 2); // 直接调用函数,sum为函数名。
2.
var sum = function(a, b) {
return a + b;
}; // 注意,此处要以;结束
var c = sum(1, 2); // 声明变量sum,并指向该函数的指针
js里只有函数名代表对函数的指针(可当作变量来使用),而函数名带有()表示对函数的调用。
再看下面例子:
var tempA = sum;
alert(tempA(1, 2)); // 可调用,返回为3
sum = null;
alert(tempA(1, 3)); // 可调用,返回4
虽然sum断了函数的引用,但tempA依然保留了指针,所以能调用。
函数没有重载:
js的函数不同于其他高级语言,没有重载方法,因为函数名代表着对其本身函数的引用指针,如果重载了函数名,则最后下载的函数会覆盖之前所有的函数,例如下:
function sum(a) {
}
function sum(a, b) {
}
sum(1); // 此处虽然只有1个参数,但实质调用的是sum(a, b)函数。
函数的内部属性:
js函数有2个重要的属性,arguments和this,这2个属性每个函数都具有的。arguments表示传入的参数数组,如果空参数则长度为0。
arguments:
function sum(a, b) {
alert(arguments.length);
}
sum(); // 输出0
sum(undefined, undefined); // 输出2
sum(undefined, 1, 2, 'a'); // 输出4
另外arguments有一个方法callee,它是调用函数本身,通常用在递归上。具体事例如下图:
function sum(num) {
if (sum < 0) {
return;
}
sum(--num); // 调用递归
}
sum(10);
此处递归在不改变函数名情况下是没有问题,但如果需要将sum改为sum2,则函数体也要相应改,代码结构变为紧耦合。JS提供方便的方法callee,可以永远调用自己本身,如下:
function sum(num) {
if (sum < 0) {
return;
}
arguments.callee(--num);
}
这样无论sum改变什么名称,函数体都不用改变,变为松耦合。
this:
js的this关键字代表当前执行环境下的本身对象,事例如下:
function ball() {
alert(this.color);
}
var color = "red";
ball(); // 输出red
因为调用ball是在全局执行环境里,所以即使在ball函数体里this也代表着全局执行环境,相当于window.color。再看下面事例:
var color = "red";
var o = new ball(); // 输出undefined
因为new一个ball,里面函数执行环境变为对象o,再因为o的color未定义,所以输出undefined; 如果要确保在函数体里访问全局执行环境变量,则可用window对象,如下:
function ball() {
alert(window.color); // 使用window,无论什么情况都代表访问全局执行环境
}
函数的预定义参数:
如果要获取函数定义的参数个数,可以用函数名.length,如果空参数,则返回0.如下:
function sum(a, b) {
}
alert(sum.length); // 输出为2
函数属性和方法:
JS函数有2个属性是必备的,length和prototype。length表示函数希望接受的参数个数,prototype是函数里所有方法都保存在里面,包括自带的valueOf和toString,只不过是通过各个实例进行访问。
函数里有2个方法是非继承而来,分别是apply和call,它们的作用都是通过特定的作用域执行函数。
apply: apply有2个参数,第1个参数是作用域对象,第2个参数是需要传入的参数数组对象,可以传入arguments(也是数组),也可以传入自定义数组
function sum(a, b) {
return a + b;
}
function callSum1(a, b) {
return sum.apply(this, arguments);
}
function callSum2(a, b) [
return sum.apply(this, [a, b]);
}
alert(callSum1(1, 2)); // 输出3
alert(callSum2(3, 4)); // 输出7
call:跟apply作用一样,唯一的区别是传入的参数略有不同,call传入的是具体每个参数(不是打包成数组)。
function sum(a, b) {
return a + b;
}
function callSum1(a, b) {
return sum.call(this, a, b);
}
alert(callSum1(2, 3)) ; // 输出5
apply和call比较:功能完全一样,只是传入参数不同,具体用哪个,看场景,如果传入的参数是已经定义好的数组或者是不可确定的参数个数,当然是apply合适,反之call合适。
对于call还有一个强大的地方,就是扩充作用域,可以指定不同作用域而形成不同的形态。具体看如下代码。
事例1:
function pay() {
alert(this.color);
}
var color = "red";
var o = { color: "red" };
pay(); // 输出red
o.pay = pay; //将函数名pay的指针赋于o.pay
o.pay(); // 调用函数,实质是调用pay(); 输出blue,因为this作用域已经指向o,所以输出的是o.color
事例2:
// 代码函数定义沿用事例1
pay.call(this); // call里参数必须要传入作用域对象,这里的this指向全局执行环境,也就是window对象。输出red
pay.call(window); // 输出red
pay.call(o); // 输出blue,传入o作用域
事例1和事例2实现功能一样,但从代码耦合程度则完全不同。事例1多了一段o.pay = pay代码,导致 pay与pay函数紧耦合;事例2只需要调用pay.call并传入对象作用域,即可实现根据不同作用域做不同的事。注:推荐事例2写法。对于上面的事例,也可以用apply,即pay.apply(this); 只不过传入的参数形式不一样。
浙公网安备 33010602011771号