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

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

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

它的使用方法如下:

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

2. 声明式:
如:

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

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

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

得到结果是

1
2

若做如下函数定义:

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

那么会得到另一种结果:

2
2

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

二、函数对象

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

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

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

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运算符,才能实现基于原型的继承。

function()的更多相关文章

  1. js(function(){alert(‘’‘)})

    function(){alert('sss')}是个匿名函数.没有名字.所以没有办法调用.在外面加个括号,就变成了一个值,值的内容是函数的引用.例如var a = (function(){" ...

  2. 知识点摸清 - - function()——JavaScript 函数名后什么时候加括号,什么时候不

    加括号——调用函数 只要是要调用函数执行的,都必须加括号. 此时,function()实际上等于函数的返回值.(没有返回值也已经执行了函数体内的行为).就是说,只要加括号的,就代表将会执行函数体代码. ...

  3. 函数也是对象,本片介绍函数的属性、方法、Function()狗仔函数。

    1.arguments.length表示实参的个数. 2.arguments.callee.length表示形参个数. function test(a,b,c,d,e,f){ alert(argume ...

  4. Solidity 没名字的function(){...}作用

    官方解释: 这个叫做fallback function,当有人 1. 只发送以太币给合约而不带任何输入数据:2. 调用smart contract时调起了一个不存在的方法.会触发执行这个方法. Wha ...

  5. bind()方法

    当点击鼠标时,隐藏或显示 p 元素: $("button").bind("click",function(){ $("p").slideTo ...

  6. JavaScript学习总结(二、隐式类型转换、eval())

    一.(避免)隐式类型转换 console.log(false == 0);   //logs true; console.log(false === 0);   //logs false; conso ...

  7. jQuery - 03. each、prevaAll、nextAll、获取属性、修改属性attr/val/text()、jq.height/width、offset()./position()./scrol Left/Top 、事件绑定bind、delegate、on、事件解绑、事件对象、多库共存

    each 方法 $ ( selector).each(function( index,element) {  } );   参数一表示当前元素在所有匹配元素中的索引号 参数二表示当前元素(DOM对象) ...

  8. window.onload后跟函数 和跟函数名的区别【window.onload = asd() 和 window.onload = asd 】

    window.onload:页面加载完毕执行[DOM tree + 外部图片 + 资源] <script> function asd(){ return 10; } window.onlo ...

  9. Angular从0到1:function(下)

    1.前言 2.function(下) 2.13.angular.isArray(★★) angular.isArray用于判断对象是不是数组,等价于Array.isArray console.log( ...

随机推荐

  1. cuda 配置要点

    1. 安装驱动 :sudo apt-get install nvidia- 2. 安装cuda : cuda 文件中包含驱动程序,因此在安装过程中当被问及是否安装驱动时,选择no 3. 安装cudnn ...

  2. Filter过滤器 不登陆无法访问其他页面

    package com.cscy.Filter; import java.io.IOException; import javax.servlet.Filter; import javax.servl ...

  3. 安装USB驱动时报错“无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动”

    今天在安装一个USB设备的时候报错“Windows已找到设备的驱动程序软件,但在试图安装它时遇到错误”. 这个错误的描述是“无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动”. 事实上,这个 ...

  4. jQuery之位置坐标图形相关方法

    jQuery实例方法-位置图形 位置坐标图形大小相关方法: .offset() .position() .scrollTop() ..scrollLeft() .width()..height() . ...

  5. Swagger2 header 添加token

    @Bean public Docket apiDocument() { return new Docket(DocumentationType.SWAGGER_2) .groupName(" ...

  6. PHP拦截器之__set()与__get()的理解与使用方法

    “一般来说,总是把类的属性定义为private,这更符合现实的逻辑.   但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值 ...

  7. 使用Log4J收集日志

    一:搭建好Selenium+testNG+Maven环境,可参考 http://www.cnblogs.com/hc1020/p/8602863.html 二:百度搜索Maven仓库,然后搜索Log4 ...

  8. Python学习—数据库篇之pymysql

    一.pymysql简介 对于Python操作MySQL主要使用两种方式: 原生模块 pymsql ORM框架 SQLAchemy pymsql是Python中操作MySQL的模块,其使用方法和MySQ ...

  9. 【JAVA】String[]配列の相関

    配列の作成: ①String[] str = new String[5]; ②String[] str = new String[]{"","","& ...

  10. Spring BeanDefinitionRegistryPostProcessor BeanPostProcessor作用

    写博客,写博客,把自己知道的小知识点全部记录,