犀牛书笔记:(10)Functions

和对象相关的称为方法,否则称为函数

 

如果一个函数没有return语句,则返回undefined.

 

如果传入的参数超过了函数期望的参数个数,后面的参数将被自动忽略。如果传入的参数少于期望的个数,参数将初始化为undefined.

 

function literal, 通过function literal定义一个无名的函数。当然也可以可选的定义一个名字,虽然function literal定义的函数没有名字,但是可以通过一个变量来引用到它

 

 

var f = function a() { alert("hello world");};
f();//returns hello world.
a();//error

 在上面的例子可以看出,函数的引用存在变量里,而和函数名没有关系,函数名仅能用于函数体内部

 

 

当传入的参数小于函数声明的参数时,实际上是一种多态的实现。比如:

 

function test(a,b){

if(!b) b = [];//另一种写法是: b = b || [];

for( var property in a ) b.push(property);
return b;

}

 

上面的例子就可以传入一个引用,函数将第一个参数的属性都存到该引用中,如果不传入,函数返回一个新的引用。

 

函数体内部有一个隐含的属性arguments,该属性是一个类数组对象。虽然定义函数时,只能定义有限个数个形参,但可以通过arguments对象来访问到所有传入的参数,即arguments[0], arguments[1], arguments[2]。。。arguments还有一个length属性表明传入参数的个数

 

function temp(a,b,c){
var str = new String();
for( var i=0; i < arguments.length; i++){
    str += arguments[i];
}
return str;
}

alert(temp("1","2","3","4");//returns 1234

 注意,arguments并不是数组,只是一个类似数组的对象。因此它不提供数组的通用方法。

 

可以接受不限数目的函数被称为variadic function, variable arity function, varags function.

 

实际上arguments索引到的对象和直接使用形参名是同义的。

arguments不是保留字,因此可以命名同名属性隐藏该属性

 

arguments定义了一个callee属性,该属性指向该函数本身,因此可以用于无名函数进行递归。

 

当形参数目太多时,形参的顺序可能会造成混乱,一个好办法时将所有的形参作为一个对象的属性传入,这样实际上传入类似一个MAP的键值对。

 

由于js是无类型语言,所以在某些情况下有必要对参数进行类型判断:

 

 

function sum(a) {
if( a instanceof Array ) {
......
}
else throw new Error("......");
}

 JS作为语言的不同之处之一就是,在JS中,函数不仅作为可执行代码,更被看作是数据(DATA)

 

function temp(){
    alert("hello world");
}

var a = temp();
var b = a;
b();//returns hello world.

 函数也可以作为数据赋值给某个对象的属性。

 

函数作为方法(面向对象)

 

var calculator = {
   operand1: 1,
   operand2: 1,
   compute: function(){
         this.result = this.opperand1 + this.operand2;
   }
}

 this是JS的关键字,如果函数作为方法来使用,this将引用到该方法所在的对象如果函数仅作为函数过程使用,this表示global对象。即使是一个方法中的内嵌函数,使用this仍然是指向global对象的

 

 

构造函数

构造函数用于初始化一个对象的属性,和new操作符一起使用。

这个过程是,new操作符先建立一个新的对象,然后由构造函数对该对象进行初始化在构造函数中,可以通过this关键字引用到new操作符建立的对象

 

一个函数的形参个数(期望传入参数的过程)也用length属性,该属性是该函数的属性:

 

 

function test(a,b,c){
   alert(arguments.callee.length);//returns 3
}
 

 

function test(a,b,c){
   alert("hello world");
}

alert(test.length);//returns 3
 

每个函数有一个prototype属性,该属性用于函数作为构造器时。

 

可以在声明一个属性,作为函数的静态属性,

 

function test(){
}
test.counter = 0;
 

call和apply函数

当函数作为对象时,它们都有两个内建的函数call和apply,这两个函数第一个参数是要调用原函数的对象,后面的参数是传入的参数,区别在于apply后面的参数是一个数组

 

f.call(o,1,2) = f.apply(o,[1,2]) = o.m=f; o.m(1,2); delete o.m;

 

Functions in JavaScript are lexically rather than dynamically scoped. This means that they run in the scope in which they are defined, not the scope from which they are executed.

 

当函数定义后,当前的范围链就成为了该函数的内建属性。

 

 

当JS解释器调用一个函数时,首先将SCOPE设置成该函数定义所在的SCOPE CHAIN,然后将一个新的CALL对象加入到SCOPE CHAIN的前端,CALL对象在初始化时设置了一个属性arguments,该函数的其他参数将被加到CALL对象中,在函数内部用VAR定义的变量也被加入,其他的在CALL对象之上的同名变量将被隐藏。

 

有的时候,利用call对象这样的特性,可以把它当作命名空间使用,这样,在GLOBAL对象中之新增了一个属性(指向函数的变量)。

 

 

当内嵌函数从它定义的SCOPE导出,这种情况称为闭包closure

当一个函数被调用时,一个CALL对象被创建并设置到SCOPE CHAIN的合适位置,当函数返回时,该CALL对象被移去。

 

 

试想一种情况,需要一个函数能够在跨多个调用的情况下保存一个值,当然可以使用全局变量,但是全局变量将会污染全局变量命名空间,同时有可能被隐藏,此时就可以用闭包来完成这个功能。

 

uniqueID = ( function() {
     var id = 0;
     return function() { return id++;};
})();
 

IE的垃圾回收算法无法识别循环引用,会造成内存泄漏。(not sure what the exactly version he is talking about)

 

定义函数也可以使用Function()构造器,因为这种方法比较不方便,因此很少使用。

Function()构造器创建的函数是匿名的

 

Function()构造器允许JS代码动态的在运行时创建并编译函数。

Function()构造器每次都创建一个新的函数对象,也就是说,如果在同一个CALL对象中,这个过程将是缺乏效率的,与之对应的,function literal或者内嵌函数即使在循环或者函数中,都只进行一次编译

最重要的一点,Function()构造器不使用本地空间,而直接使用GLOBAL对象

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值