1. Function是什么
从Javascript对function的定义, function是一个由代码集合而成的对象.
从中我们可看出,我们可以使用向C语言中的函数那样使用function,也可以对function进行面向对象编程.当然Javascript中function的强
大还不止如此.
2. 如何使用function
2.1定义
function myfunc(param) {
//code
}
注意Javascript中的这两个function被认为是同一个:
在运行时到底调用哪一个function取决于加载顺序,后一个加载的function会覆盖前一个.
function func1() {return 'func1'; }
function func1(name) { return name; }
换句话说就是,function的参数都是可选参数,因此funciton的识别是不包括如参的,而函数入参处的声明是为了引用方便以及可读性.
以上的代码也等价于:
function func1() {
return arguments[0] || 'func1';
}
func(); //return 'func1'
func('function'); //return 'function'
2.2 function当作对象
是的没错,在javascript中function就是对象,我们可以向使用一个对象那样使用function.
它可以有自己的属性和方法.有如下的一个funciton:
function nameOf(name) {
return name.toUpperCase();
}
2.2.1 function作为对象进行赋值
var person = person || {};
person.nameOf = nameOf;
person.nameOf('yang dong') // return "YANG DONG"
2.2.2 定义function的属性
看看以下的代码, 你能从中的到什么信息:
function nameOf() {return nameOf.blogger;}
nameOf.blogger = "YANG_DONG";
没错,function可以拥有自己的属性.
考虑这样一种场景, 假如我们要统计某个function被调用的次数.那么我们有两种方式来实现:
1.设定一个全局变量来记录,该funciton被调用的次数,每调用一次,该变量加1:
var globalNameOfCounter = 0;
nameOf();
globalNameOfCounter ++;
这样做看起来是没有问题的,在代码还是比较简单的时候,它可以工作的很好,但是随着代码越来越复杂,维护这段逻辑的成本会直线上升.
主要是因为:globalNameOfCounter污染的global命名空间,并且破坏了代码的封装性.
2.使用function的属性
看看以下代码:
function nameOf() {
nameOf.counter++;
return nameOf.blogger;
}
nameOf.blogger = “YANG_DONG"
nameOf.counter = 0;
nameOf(); //nameOf.counter = 1
nameOf(); //nameOf.counter = 2
显而易见,第二种方式有着很好的封装性和维护性.function的属性的应用还不止如此.请看下文.
2.3 function作为名字空间
Javascript不支持名字空间(本人不太理解如此强大的语言为什么不支持名字空间呢,这是为什么呢?),
不过我们依然可以使用其强大的funciton为我们支持名字空间.
从上节我们知道function可以定义自己的属性,我们就可以利用该特性来生成名字空间.请看以下代码:
nameOf.getBloggerName = function() {
return nameOf.blogger;
}
此时在nameOf名字空间之下已经包含了:blogger,counter属性和function getBloggerName.
2.4 function作为method
在javascript中function和method其实是没有什么本质区别的,如果非的区分两者的话,我想也就是this变量不同吧.
function g() {return this;}
var local = local || {};
local.method = g; //修改this指向local
local.method(); //返回local对象
g(); //返回DOMWindow对象
2.5 function皆为closure
在Javascript中所有的function都绑定了一个scope chain,因此它是一个保存了调用上下文的函数.看看下面的实例代码:
var variable = 'global';
function getVariable(){
var variable = 'local',
func = function() {
return variable;
};
return func;
}
getVariable()(); //return local;
当func被调用的时候,它所取的varible的值是调用上下文中的变量而并非与之同名的全局变量.
3. 总结
如果用一句话概括今天对funciton的介绍,那么我想应该是: function是可以被调用执行的代码集对象.
以上是function的一些应用场景,当然它还不止这些.
如何定义一个函数
- 声明式
函数定义最常用的方式之一。
1 //声明函数 2 function add(x, y) { 3 return x + y; 4 } 5 6 //声明构造函数 7 function Animal(name, age) { 8 this.name = name; 9 this.age = age; 10 } 11 12 Animal.prototype.bark = function() {return 'bark'};
其实这两种发式完全一样,没有任何区别,你同样可以为add的prototype属性增加新的函数或者属性。
不过两种方式是基于不同的用途产生的,我们之所以称后者为构造函数,仅仅因为它的命名和函数实现。
命名: 对于构造函数我们遵循首字母大学的规则以区别普通函数和方法,这和java中对于类的定义是非常相似的。
实现: 构造函数是我们用来生产实例对象的工具,它通长与new关键字连用,如
1 var dog = new Animal('pipi', 3); 2 dog; // Animal {name: "pipi", age: 3}
同时你可能也注意到了Animal中使用到了this关键字,通长情况下this会指向函数的调用对象,
也就是说如果你在浏览器中运行一下代码,你应该得到window对象:
1 function getThis() {return this}; 2 getThis(); //window
试想一下,如果你这样使用构造函数:
1 var dog = Animal('pipi', 3);
这段代码会产生什么有趣的结果呢?
恭喜你!你中招了!
你会发现,你的window对象新增加了两个属性, 同时没有任何对象产生:
1 window.name === 'pipi'; //true 2 window.age === 3 //true 3 dog === undefined; //true
对比使用构造函数的两种方式,其实这都是new在作怪,当我们在像使用java类那样对构造函数new出javascript对象时,
它帮我们完成了一些magic(这也是javascript new关键字被人诟病的地方),我们不妨来一次魔术揭秘:
//魔术 var dog = new Animal('pipi', 3); //揭秘 function newAlternative(constructor, name, age) { var obj = {}; //修改this,指向新对象obj constructor.call(obj, name, age); //使实例对象继承构造函数 obj.__proto__ = constructor.prototype; return obj; } var dog = newAlternative(Animal, 'pipi', 3); dog; //Animal {name: "pipi", age: 3, bark: function}
因此,我们需要非常细心的处理函数,如果它就是‘类’那么请根据潜规则,首字母大写它,并且在使用的时候一定要与new连用。
- 匿名
匿名函数广泛在javascript代码中使用,先看看这段代码:
1 //定义处理元素的匿名函数 2 [1,2].map(function(e) {return e + 2}); 3 4 //定义匿名构造函数 5 var Animal = function(name, age) { 6 this.name = name; 7 this.age = age; 8 } 9 Animal.prototype.bark = function() {return 'bark'}; 10 11 Animal.name === ''; //true
- Function
相对与前两种方式,使用Function来定义一个新的function相对少见。如果说构造函数是为生成实例对象而生,
那么Function就是为生成函数而生,它是生成函数的模板,构造函数,‘类’.
1 var Animal = 2 new Function('name', 'age', 'this.name = name; this.age = age;'); 3 Animal.prototype.bark = function() {return 'bark'};
虽然这种方式在实际开发中很少被用到,但是它对我们理解函数的生成过程有帮助作用,对比一下两组代码,
我们不难发现Animal其实就是Function的实例对象,就如同dog是Animal的实例对象一样。
1 Animal.__proto__ === Function.prototype //true 2 3 var dog = new Animal('pipi', 3); 4 dog.__proto__ === Animal.prototype; //true
总结
函数在javascirpt中起着至关重要的作用,构造函数是其中一种特殊的函数,他通过和new关键字搭配使用,
帮助我们完成看起来与普通面向对 象相似的对象构造过程,不过这仅仅是想像而已,我们必须理解其中的奥秘才能是我们不会在编码过程中犯错。