ECMAScript的函数是对象,函数名是指针
创建:
函数声明法:
function sum (num1, num2) { return num1 + num2; }函数表达式法:
- var sum = function(num1, num2) {
- return num1 + num2;
- };
函数表达式法:这种不推荐,因为这种语法会导致解析两次代码(第一次解析常规ECMAScript代码,第二次解析传入构造函数中的字符串),从而影响性能
- var sum = new Function("num1", "num2", "return num1 + num2"); //不推荐
同时使用函数声明和函数表达式:这种语法会在Safari出错
- var sum = function sum () {}
由于函数名只是指针,所以如下:
- function sum(num1, num2){
- return num1 + num2;
- }
- alert(sum(10,10)); //20
- var anotherSum = sum;
- alert(anotherSum(10,10)); //20
- sum = null;
- alert(anotherSum(10,10)); //20
函数名是指针,所以没有重载:
- function addSomeNumber (num) {
- return num + 100;
- }
- function addSomeNumber (num) {
- retrun num + 200;
- }
- var result = addSomeNumber(100); //300
上面代码实际上是:
- function addSomeNumber (num) {
- return num + 100;
- }
- addSomeNumber = function (num) {
- retrun num + 200;
- }
- var result = addSomeNumber(100); //300
创建第二个函数时,改变了addSomeNumber的指向
函数声明与函数表达式的一个区别:
解析器会率先读取函数声明,并使其在执行任何代码前可用;而函数表达式,必须等到解析器执行到所在行,才能被解释执行
- alert(sum(10,10)); //20
- function sum(num1, num2){
- return num1 + num2;
- }
如果改成如下,就会报错
- alert(sum(10,10)); //causes an error
- var sum = function(num1, num2){
- return num1 + num2;
- };
把函数当值使用:
将一个函数作为另一个函数的结果返回
- function callSomeFunction(someFunction, someArgument){
- return someFunction(someArgument);
- }
- function add10(num){
- return num + 10;
- }
- var result1 = callSomeFunction(add10, 10);
- alert(result1); //20
- function getGreeting(name){
- return "Hello, " + name;
- }
- var result2 = callSomeFunction(getGreeting, "Nicholas");
- alert(result2); //Hello, Nicholas
从一个函数中返回另一个函数,如给对象数组排序:(默认情况下,sort()会调用toString()方法)
- function createComparisonFunction(propertyName) {
- return function(object1, object2){
- var value1 = object1[propertyName];
- var value2 = object2[propertyName];
- if (value1 < value2){
- return -1;
- } else if (value1 > value2){
- return 1;
- } else {
- return 0;
- }
- };
- }
- var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];
- data.sort(createComparisonFunction("name"));
- alert(data[0].name); //Nicholas
- data.sort(createComparisonFunction("age"));
- alert(data[0].name); //Zachary
函数内部属性:
函数内部有两个特色的对象 arguments 和 this
arguments:是一个类数组对象,包含传入函数的所有参数
callee:是arguments的属性,该属性是一个指针,指向拥有这个arguments对象的函数
下面是一个经典的阶乘例子:
- function factorial(num){
- if (num <= 1) {
- return 1;
- } else {
- return num * arguments.callee(num-1)
- }
- }
- var trueFactorial = factorial;
- factorial = function(){
- return 0;
- };
- alert(trueFactorial(5)); //120
- alert(factorial(5)); //0
this:引用的是函数据以执行的环境对象(当在网页的全局作用域中调用函数时,this对象引用的就是window)
- window.color = "red";
- var o = { color: "blue" };
- function sayColor(){
- alert(this.color);
- }
- sayColor(); //red
- o.sayColor = sayColor;
- o.sayColor(); //blue
caller:这个属性中保存着调用当前函数的函数的引用,如果在全局作用域中调用当前函数,它的值为null(Opera9.6版之前不支持该属性)
- function outer(){
- inner();
- }
- function inner(){
- alert(inner.caller);
- }
- outer(); //function outer(){
- // inner();
- //}
下面这种写法与上面同理,只是达到了更好的松耦合,这样函数名称可以变动而不用改变内部代码
- function outer(){
- inner();
- }
- function inner(){
- alert(arguments.callee.caller);
- }
- outer(); //function outer(){
- // inner();
- //}
注意:
1.这严格模式下,访问 arguments.callee 会导致错误。
2.ECMAScript5 还定义了 arguments.caller 属性,但在严格模式下也会导致错误,而在非严格模式下这个属性始终是undefined。定义这个属性是为了分清 arguments.caller 和 函数的caller属性。以上都是为了加强这门语言的安全性,这样第三方代码就不会在相同的环境里窥视其他代码了。
3.在严格模式下,不能给函数的caller属性赋值,否则会出错。
函数属性和方法:
由于在ECMAScript中,函数是对象,所以函数有属性和方法
length:表示函数希望接收的命名参数的个数
- function sayName(name){
- alert(name);
- }
- function sum(num1, num2){
- return num1 + num2;
- }
- function sayHi(){
- alert("hi");
- }
- alert(sayName.length); //1
- alert(sum.length); //2
- alert(sayHi.length); //0
prototype:第6章
apply():用途是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值?
需传入2个参数:该运行函数的作用域(this)、参数数组
- function sum(num1, num2){
- return num1 + num2;
- }
- function callSum1(num1, num2){
- return sum.apply(this, arguments); //由于在全局作用域中调用的,所以this指的是window对象
- }
- function callSum2(num1, num2){
- return sum.apply(this, [num1, num2]);
- }
- alert(callSum1(10,10)); //20
- alert(callSum2(10,10)); //20
注意:在严格模式下,未指定环境对象而调用函数,则this值不会转型为window。除非明确把函数添加到某个对象 或者 调用apply()或call(),否则this值将是undefined
call():用途是在特定的作用域中调用函数?
传入参数:该运行函数的作用域(this)、逐一列出参数
- function sum(num1, num2){
- return num1 + num2;
- }
- function callSum(num1, num2){
- return sum.call(this, num1, num2);
- }
- alert(callSum(10,10)); //20
apply()和call()真正的用武之地是扩充函数赖以运行的作用域,如下:
- window.color = "red";
- var o = { color: "blue" };
- function sayColor(){
- alert(this.color);
- }
- sayColor(); //red
- sayColor.call(this); //red
- sayColor.call(window); //red
- sayColor.call(o); //blue
使用apply()或call()来扩充作用域的最大的好处,就是对象不需要与方法有任何耦合关系(这跟之前那个版本比(讲this时),省下很多多余的步骤)
bind():把this值与该函数绑定
- window.color = "red";
- var o = { color: "blue" };
- function sayColor(){
- alert(this.color);
- }
- var objectSayColor = sayColor.bind(o);
- objectSayColor(); //blue
把o与objectSayColor的this绑定,所以调用时返回的是blue,而不是red,第22章
支持bind()的浏览器有IE9+、Firefox 4+、Chrome……
每个函数继承的toLocaleString()、toString()、valueOf()都返回的函数的代码,因浏览器而异。