function()

avaScript中的function能够有如下两种用法:
一是作“普通逻辑代码容器”,也就是咱们一般意义上的函数、方法,和咱们C/C++里的函数没什么大分别,只是写法稍有不一样、用法更加灵活;
二是作对象,有的地方叫它函数对象,其用法和做用有点相似C++里的class(类)。
下面来详细说说这两种用法。

1、 function用做普通函数
function用做普通函数的定义方法以下:
function functionName([argument1] [, argument2] [..., argumentN]){
  [statements]
}
具体写法有如下两种:
1. 定义式:
如:javascript

function multiply(x, y){    
    return x*y;    
    }  

 


 
它的使用方法以下:java

var product = multiply(128,128); // product = 16384  

 




2. 声明式:
如:浏览器

var product = function multiply(x, y){    
    return x*y;    
    }  

 




须要说明的是:
1. 用做普通函数时,function几乎能够在脚本的任何地方定义,但推荐在一个HTML文档的<head></head>区域里定义,这样能够保证若是另外一个脚本须要当即使用这里声明的函数时,就能够当即使用它。
2. 上述两种具体写法在重复定义的时候也有一些差异,以下
若作以下函数定义:app

var example = function(){  
    return 1;  
    }  
    example();  
    var example = function(){  
    return 2;  
    }  
    example();  

获得结果是函数

1  
    2  


若作以下函数定义:this

function example(){  
    return 1;  
    }  
    example();  
    function example(){  
    return 2;  
    }  
    example();  


那么会获得另外一种结果:spa

2  
    2  

 




在采用定义式建立同名函数时,后建立的函数会覆盖先建立的函数。这种差异是因为JavaScript解释引擎的工做机制所致使的。因为注册函数时,后定义的函数重写了先定义的函数,所以不管调用语句位于何处,执行的都是后定义的函数。相反,对于声明式建立的函数,JavaScript解释引擎会像对待任何声明的变量同样,等到执行调用该变量的代码时才会对变量求值。所以当执行第一个example()调用时,example函数的代码就是首先定义代码;而当执行第二个example()调用时,example函数的代码又变成了后来定义的代码。
固然,好的习惯是不要这样写,也不要试图利用“声明式”的这种机制来投机取巧。不过,函数重载除外,可是,javascript里好像并无函数重载这种写法吧?

2、函数对象

 1.基本概念
在JavaScript中,function还能够被用作对象(或者窃觉得该叫作类更合适)。这也许听起来很怪异也很难理解,但考虑到JavaScript既然是一种面向对象的语言,那么它里面总得能够实现类和对象吧?看看下面的用法就知道了——用function来实现类和对象倒也真无可厚非。
首先要说明一下的是与function有密切关系的this这个东西。“JavaScript在解析代码时,会为声明或定义的函数指定调用对象。所谓调用对象,就是函数的执行环境。”也就是说,在函数体中,能够以this关键字来使用它的调用对象(关于this的具体用法,另做讨论,详见下篇)。“若是函数体内有以关键字this声明的变量,则this引用的就是调用对象。”
下面就来看看做为函数对象的function一般是怎么写的:prototype

function Animal(sort, character){  
    this.sort = sort;  
    this.character = character;  
    }  


上面的代码就定义了一个函数对象,其意义与C++中的class类似,它的构造函数就是这个函数Animal。其实看起来跟上面的普通函数没什么分别,换句话说,按照上面介绍的普通函数定义方法写,结果就会获得一个函数对象,窃觉得JavaScript中其实只存在函数对象,不存在咱们传统意义上的“函数”,只是它的使用方法灵活多样,能够按照咱们传统的使用方法functionName(…)直接调用,也能够按下面的方法做为对象使用:code

var dog = new Animal(”mammal”,”four legs”); //建立一个函数对象实例  

 


2.函数对象建立过程
函数怎么又成了对象了呢?它是怎么构造的呢?先来了解一下JavaScript里的函数对象都有什么吧~简单地说,JavaScript里的函数对象最初包含一个默认的构造函数,函数名是Object,同时,还有个成员(属性)——__proto__,与大名鼎鼎的prototype属性相关(用于实现JavaScript里的继承),关于prototype的用法,另做讨论,详见后文。
了解了这些,再看看上面这个dog对象的构造过程吧~
“建立dog的对象的过程以下:首先,new运算符建立一个空对象({}),而后以这个空对象为调用对象调用函数Animal”(也就是跟传统意义上的对象构造过程相同,调用它的构造函数进行初始化)“,为这个空对象添加两个属性sort和character,接着,再将这个空对象的默认constructor属性修改成构造函数的名称(即Animal;空对象建立时默认的constructor属性值是Object),而且将空对象的__proto__属性设置为指向Animal.prototype——这就是所谓的对象初始化。最后,返回初始化完毕的对象。这里将返回的新对象赋值给了变量dog。”
3.直接实例化的写法
函数对象的定义、实例化过程也能够简化以下:对象

var dog = {};  
    dog.name = “heibao”;  
    dog.age = “3 months”;  
    dog.shout = function(){  
    return “Hello, My name is “+ this.name + ” and I am ” + this.age + ” old!”;  
    }  
    dog.shout(); // “Hello, My name is heibao and I am 3 months old!”  


上面的代码中,dog是个对象,它有name、age两个属性,还有个成员函数(也是个对象,就是咱们的函数对象)shout。这里的shout的定义方法就是作了简化——直接被function赋值。
对象也能够借用其余对象的方法:

var cat = {};  
    cat.name = “xiaohua”;  
    cat.age = “2 years”;  
    cat.greet = dog.shout;  
    cat.greet(); // “Hello, My name is xiaohua and I am 2 years old!”  



这里须要强调的是,每一个函数对象都有两个特殊的方法——call和apply,用它们能够动态指定函数或方法的调用对象:

    dog.shout.call(cat); // “Hello, My name is xiaohua and I am 2 years old!”  
    //或者  
    dog.shout.apply(cat); // “Hello, My name is xiaohua and I am 2 years old!”  


从这里想到,是否是咱们能够用call或apple函数来替代上面的方法进行函数对象的实例化呢?答案是否认的。让咱们来从这个角度进一步分析一下函数对象的构造过程,以便加深理解:
若是咱们企图这么写来达到函数对象实例化的效果:

var dog = {};  
    Animal.call(dog, “mammal”,”four legs”);  


那么,“表面上看,这两行代码与var dog = new Animal(”mammal”,”four legs”);是等价的,其实却不是。虽然经过指定函数的执行环境可以部分达到初始化对象的目的,例如空对象dog确实得到了sort和character这两个属性“:

    dog.sort; // mammal  
    dog.character; // four legs  
    dog.constructor; // Object —— 注意,没有修改dog对象默认的constructor属性  

 



然而,“最关键的是新建立的dog对象失去了经过Animal.prototype属性继承其余对象的能力。只要与前面采用new运算符调用构造函数建立对象的过程对比一下,就会发现,new运算符在初始化新对象期间,除了为新对象添加显式声明的属性外,还会对新对象进行了一番“暗箱操做”——即将新对象的constructor属性重写为Animal,将新对象的__proto__属性设置为指向Animal.prototype。虽然手工“初始化对象”也能够将dog.constructor重写为Animal,但根据ECMA262规范,对象的__proto__属性对开发人员是只读的,对它的设置只能在经过new运算符建立对象时由JavaScript解释引擎替咱们完成。”
看看这样作的后果:若是不能正确设置对象的__proto__属性,那么就意味着默认的继承机制会失效:

    Animal.prototype.greet = “Hi, good lucky!”;  
    dog.greet; // undefined  


事实上,虽然在Firefox中,__proto__属性也是可写的:

    Animal.prototype.greet = “Hi, good lucky!”;  
    dog.__proto__ = Animal.prototype;  
    dog.greet; // Hi, good lucky!  

但这样作只能在Firefox中行得通。考虑到在兼容多浏览器,必须依赖于new运算符,才能实现基于原型的继承。

相关文章
相关标签/搜索