英语级别划分标准JavaScript 中的function 使⽤⽅法
简易方程五年级
JavaScript⼊门易,可深究起来,竟搞得我如此混乱,这恐怕就是弱类型语⾔的特点吧?写惯了C++,还真是不适应。近⽇在google上搜来搜去,学习了半天function、this和prototype,这就总结⼀下,但愿能把它们理清楚。
这是第⼀篇,关于JavaScript中的function。
参考了⼀些⽂章,我认为JavaScript中的function可以有以下两种⽤法:
⼀是做“普通逻辑代码容器”,也就是我们通常意义上的函数、⽅法,和我们C/C++⾥的函数没什么⼤分别,只是写法稍有不同、⽤法更加灵活;
⼆是做对象,有的地⽅叫它函数对象,其⽤法和作⽤有点类似C++⾥的class(类)。
下⾯来详细说说这两种⽤法。
⼀、 function⽤作普通函数
function⽤作普通函数的定义⽅法如下:
function functionName([argument1] [, argument2] [..., argumentN]){
[statements]
}
具体写法有以下两种:
1. 定义式:如:
function multiply(x, y){
return x*y;
它的使⽤⽅法如下:
2. 声明式:如:
var product = function
}
需要说明的是:
创业团队介绍1. ⽤作普通函数时,function⼏乎可以在脚本的任何地⽅定义,但推荐在⼀个HTML⽂档的<head></head>区域⾥定义,这样可以保证如果另⼀个脚本需要⽴即使⽤这⾥声明的函数时,就可以⽴即使⽤它。
2. 上述两种具体写法在重复定义的时候也有⼀些差别,如下
若做如下函数定义:
}example();var example =
example();
银杏湖公园得到结果是
动火作业方案12 若做如下函数定义:example();function example(){return 2;
}
taxi69>读书百遍的下一句是什么
example();
那么会得到另⼀种结果:22 在采⽤定义式创建同名函数时,后创建的函数会覆盖先创建的函数。这种差别是由于JavaScript解释引擎的⼯作机制所导致的。由于注册函数时,后定义的函数重写了先定义的函数,因此⽆论调⽤语句位于何处,执⾏的都是后定义的函数。相反,对于声明式创建的函数,JavaScript解释引擎会像对待任何声明的变量⼀样,等到执⾏调⽤该变量的代码时才会对变量求值。因此当执⾏第⼀个example()调⽤时,example函数的代码就是⾸先定义代码;⽽当执⾏第⼆个example()调⽤时,example函数的代码⼜变成了后来定义的代码。当然,好的习惯是不要这样写,也不要试图利⽤“声明式”的这种机制来投机取巧。不过,函数重载除外,但是,javascript⾥好像并没有函数重载这种写法吧?
⼆、函数对象
1.基本概念
在JavaScript中,function还可以被⽤做对象(或者窃以为该叫做类更合适)。这也许听起来很怪异也
很难理解,但考虑到JavaScript既然是⼀种⾯向对象的语⾔,那么它⾥⾯总得可以实现类和对象吧?看看下⾯的⽤法就知道了——⽤function来实现类和对象倒也真⽆可厚⾮。
⾸先要说明⼀下的是与function有密切关系的this这个东西。“JavaScript在解析代码时,会为声明或定义的函数指定调⽤对象。所谓调⽤对象,就是函数的执⾏环境。”也就是说,在函数体中,可以以this关键字来使⽤它的调⽤对象(关于this的具体⽤法,另作讨论,详见下篇)。“如果函数体内有以关键字this声明的变量,则this引⽤的就是调⽤对象。”
下⾯就来看看作为函数对象的function通常是怎么写的:
鬼神传说this.character = character;}
上⾯的代码就定义了⼀个函数对象,其意义与C++中的class相似,它的构造函数就是这个函数Animal。其实看起来跟上⾯的普通函数没什么分别,换句话说,按照上⾯介绍的普通函数定义⽅法写,结果就会得到⼀个函数对象,窃以为JavaScript中其实只存在函数对象,不存在我们传统意义上的“函数”,只是它的使⽤⽅法灵活多样,可以按照我们传统的使⽤⽅法functionName(…)直接调⽤,也可以按下⾯的⽅法作为对象使⽤:
Animal(”mammal”,”个函数对象实例
2.函数对象创建过程
函数怎么⼜成了对象了呢?它是怎么构造的呢?先来了解⼀下JavaScript⾥的函数对象都有什么吧~简单地说,JavaScript⾥的函数对象最初包含⼀个默认的构造函数,函数名是Object,同时,还有个成员(属性)——__proto__,与⼤名⿍⿍的prototype属性相关(⽤于实现JavaScript⾥的继承),关于prototype的⽤法,另作讨论,详见后⽂。
了解了这些,再看看上⾯这个dog对象的构造过程吧~
“创建dog的对象的过程如下:⾸先,new运算符创建⼀个空对象({}),然后以这个空对象为调⽤对象调⽤函数Animal”(也就是跟传统意义上的对象构造过程相同,调⽤它的构造函数进⾏初始化)“,为这个空对象添加两个属性sort和character,接着,再将这个空对象的默认constructor属性修改为构造函数的名称(即Animal;空对象创建时默认的constructor属性值是Object),并且将空对象的
__proto__属性设置为指向Animal.prototype——这就是所谓的对象初始化。最后,返回初始化完毕的对象。这⾥将返回的新对象赋值给了变量dog。”
3.直接实例化的写法
函数对象的定义、实例化过程也可以简化如下:
dog.age = “3 months”;
name is “+ this.name }dog.shout(); // “Hello, My name is
上⾯的代码中,dog是个对象,它有name、age两个属性,还有个成员函数(也是个对象,就是我们的函数对象)shout。这⾥的shout的定义⽅法就是做了简化——直接被function赋值。对象也可以借⽤其他对象的⽅法:
My name is xiaohua and I am 2 years 这⾥需要强调的是,每个函数对象都有两个特殊的⽅法——call和apply,⽤它们可以动态指定函数或⽅法的调⽤对象:years old!”//或者// “Hello, My name is years old!” 从这⾥想到,是不是我们可以⽤call或apple函数来替代上⾯的⽅法进⾏函数对象的实例化
呢?答案是否定的。让我们来从这个⾓度进⼀步分析⼀下函数对象的构造过程,以便加深理解:如果我们企图这么写来达到函数对象实例化的效果:legs”); 那么,“表⾯上看,这两⾏代码与var dog = new Animal(”mammal”,”four legs”);是等价的,其实却不是。虽然通过指定函数的执⾏环境能够部分达到初始化对象的⽬的,例如空对象dog确实获得了sort和character这两个属性“:
然⽽,“最关键的是新创建的dog对象失去了通过Animal.prototype属性继承其他对象的能⼒。只要与前⾯采⽤new运算符调⽤构造函数创建对象的过程对⽐⼀下,就会发现,new运算符在初始化新对象期间,除了为新对象添加显式声明的属性外,还会对新对象进⾏了⼀番“暗箱操作”——即将新对象的constructor属性重写为Animal,将新对象的__proto__属性设置为指向Animal.prototype。虽然⼿⼯“初始化对象”也可以将structor重写为Animal,但根据ECMA262规范,对象的__proto__属性对开发⼈员是只读的,对它的设置只能在通过new运算符创建对象时由JavaScript解释引擎替我们完成。”
看看这样做的后果:如果不能正确设置对象的__proto__属性,那么就意味着默认的继承机制会失效:
看看这样做的后果:如果不能正确设置对象的__proto__属性,那么就意味着默认的继承机制会失效:
事实上,虽然在Firefox中,__proto__属性也是可写的:
但这样做只能在Firefox中⾏得通。考虑到在兼容多浏览器,必须依赖于new运算符,才能实现基于原型的继承。Animal.prototype;
<; // Hi, good
lucky!
参考⽂献:
2.,(美)R.Allen Wyke 等著,闻道⼯作室 译,机械⼯业出版社