Javascript 函数初探
在 Javascript 中, 函数是“一等公民”, 它是 Javascript 的中心对象。
1. 函数是值,可以用在值被用到的任何地方。 可以存储在变量中, 用于表达式中,放在数组里, 放在对象的值对里, 作为参数传入函数, 作为函数返回值;
2. 函数是对象, 可以拥有数据属性, 拥有方法, 指向原型对象;
3. 函数拥有可调用的代码块,有多种调用模式; 可以制造闭包和回调, 这两种编程模式是非常强大的。
代码运行: 打开 chrome 浏览器, 工具 --- Javascript 控制台。
参考文献:
《Javascript: The Good Parts》 Douglas Crockford
一. 函数是值
让我们从最常规的函数调用形式开始吧!
1. 函数存储在变量中。
先看一段普通的代码:
function numAdd(a,b) { return a+b; } numAdd(5, 7);
实际上,它的含义是:
var numAdd = function(a,b) { return a+b; } numAdd(5, 7);
函数对象被存储在变量 numAdd 中, 可以通过该变量进行引用;
2. 函数用于表达式中
var choice = function(boolvar) { return boolvar ? function(num) { return num*num } : function(num) { return num / 2; } } var square = choice(true); square(2); // print 4 var half = choice(false); half(4); // print 2
这段代码根据传入的布尔值, 分别返回不同的函数对象; 如果为真, 则返回平方值函数, 如果为假,则返回取半函数。 它也演示了函数如何作为返回值。
3. 函数作为参数传入函数
var worker = function(callback) { var arrparams = [1, 2, 3, 4, 5]; callback(arrparams); }; worker(function(arrparams) { document.write('You get me print it !'); document.write(arrparams.join(' ')); }); worker(function(arrparams) { document.write('You get me print it reversed !'); var reversed = arrparams.reverse(); document.write(reversed.join(' ')); });
函数作为参数传入函数, 可以演变成回调。 回调是一种非常强大的编程模式。回调请参考文章 《编程模式:回调》
4. 函数作为对象的值对
var person = { name : 'Shuqin', say : function() { document.write("I am " + this.name); } } person.say();
上述代码演示了 Javascript 中的对象封装基本方法。
二、 函数是对象
对象拥有数据属性, 拥有方法, 拥有原型对象。 函数的原型对象是 Function.prototype . 继续前面的例子:
worker.salary = '6K'; document.write("My salary is " + worker.salary); document.write("My type is " + worker.typename); Function.prototype.typename = 'func'; // 将所有函数的 typename 属性设置为 func document.write("My type is " + worker.typename); document.write("My type is " + choice.typename); Function.prototype.fsay = function() { // 为所有函数添加 fsay 方法 document.write('Hey, i am a function, the first class object in javascript'); } worker.fsay(); choice.fsay(); worker.mycareer = function(career) { // 仅为 worker 函数添加方法 document.write('I am worker ' + career); } worker.mycareer(' a programmer'); choice.mycareer(' a choice'); // Error: Has no method 'mycareer'
基于原型的继承机制的最大优点就是动态灵活, 可以在运行时动态地添加任何属性和方法。 当然, 过度滥用会导致混乱。
三、 闭包
函数可以嵌套在另一函数中, 内层函数可以访问外层函数的私有变量,从而延伸了其作用域。
var secretMan = function() { var count = 1; var secret = 'very very important secret. Poison case happened in tsinghua 19 years ago'; return function() { count +=1; return secret + " ********* " + count; } } document.write("The secret: " + secret); //Error: ReferenceError: secret is not defined var revealTruth = secretMan(); document.write('Now is the time to reveal it out: ' + revealTruth()); // 页面打印: Now is the time to reveal it out: very very important secret. Poison case happened in tsinghua 19 years ago ********* 2 document.write('Now is the time to reveal it out: ' + revealTruth()); // 页面打印: Now is the time to reveal it out: very very important secret. Poison case happened in tsinghua 19 years ago ********* 3
注意到, 当执行完 var revealTruth = secretMan() 之后, 作为局部变量的 count, secret 均应该退出其作用域(退出参数栈而不存), 但由于内层函数的存在,它们依然存在着并可以继续使用, 例如 在 第二遍 revealTruth() 调用时依然可以访问 count 的值。
四、 调用模式与 this
函数有四种调用模式: 通过变量引用, 通过对象方法, 通过构造器, 通过 apply 函数.
1. 变量引用: 将函数对象存储在变量中, 从而通过变量引用来调用。 this 绑定在全局对象中;
2. 对象方法: 函数作为对象方法而调用, this 动态绑定给当前调用函数的对象; 绑定发生在调用时;
3. 构造器: 函数用于创建和初始化新对象, this 绑定给新创建的对象;
4. apply : 函数作为参数传入 apply 函数, this 绑定给指定的对象。
第一种情况:
var outer = function() { document.write('Outer this: ' + this); // [object Window] var inner = function() { document.write('Inner this: ' + this); // [object Window] }; inner(); } outer();
第二种情况:
var person = { name : 'Shuqin', sayme : function() { document.write("Object this: " + this.name); // Shuqin ( function() { document.write('Inner this: ' + this); // [object Window] , this 被切换了! })(); } } person.sayme();
第三种情况:
var Man = function(name, power) { this.name = name; // this 绑定到将要被创建的新对象 this.sex = 'Man'; this.power = power; this.ability = function() { document.write('Name: ' + this.name + 'Sex: ' + this.sex + 'Power: ' + this.power); if (this.power < 80) { document.write('Oh, no , you power is little, you must strengthen it!'); } } } var me = new Man('Shuqin', 60); me.ability();
第四种情况:
var generalsum = function(callback, args) { document.write("generalsum this: " + this); var result = 0; var caller ; if (typeof this == 'function') { caller = this; } else { caller = callback; } document.write((typeof caller) + ' ' + args.join(' ')) for (i=0; i < args.length; i++) { result += caller(args[i]); document.write(result); } return result; }; var plainsumdef = function(num) { return num; } generalsum(plainsumdef, [1, 2, 3, 4, 5]); // this: [object Window] var plainsum = generalsum.apply(plainsumdef, [null, [1,2,3,4,5]]); // this: function (num) { return num; }
在这种情况下, this 被绑定到指定对象。
小结
本文初步探讨了 Javascript 的函数,所给例子倾向于阐明它的基本特征。在实际中, 还需要深入去使用它, 衍化出各种高级技巧。 理解它, 将成为理解 javascript 的一把钥匙。