javascript函数使用的时候,往往都比较单一,这里介绍几种不同于我们之前使用的函数调用方式!
1、函数表达式包含名称,用于递归
var f = function s(num) { if (num < 1) { return 1; } else { return num * s(num - 1); //return 语句会导致函数停止运行 } }
一般要实现递归的功能的时候,使用函数表达式包含名称的使用比较方便!
调用方式:
var num = f(5);//120
2、函数表达式定以后立即执行
var s = (function (x) { return x * x } (10)); console.log(s); //100
3、函数声明
函数声明并非真正的语句,ECMAScript规范只是允许它们作为顶级语句!
4、函数链式调用
function s() { console.log(1); this.s1 = function () { console.log("2"); this.s2 = function () { console.log("3"); } return this; } return this; }
调用方式:
s().s1().s2();
5、构造函数调用
如果函数函数或者方法调用之前使用new关键字,就是构造函数调用的方式。
var s = new Object(); //如果构造函数没有参数可以采用下面一行,省略括号
var s = new Object;
构造函数调用创建的对象是会继承构造函数的prototype的属性!并将这个对象用做调用上下文操作,因此可以使用this关键字!
6、函数的参数对象
arguments; arguments[0]//传入的第一个参数 arguments[1]//传入的第二个参数 arguments.length; //参数的长度 //arguments并不是一个真正的数组,它是一个实参对象 callee 和 caller //参数对象的属性 arguments.callee //当前正在执行的函数 arguments.caller //当前正在执行的函数的函数 function s() { console.log(arguments.callee); //执行当前函数 等价于s(); console.log(arguments.caller); //显示当前函数的函数代码块 }
7、函数自定义属性调用
//每次调用都会加1
s.index = 0; function s() { return s.index++; }
s(); console.log(s.index);//1
s();
console.log(s.index);//2
s();
console.log(s.index);//3
console.log(s.index);//3
//自定义属性计算阶乘 //isFinite() 函数用于检查其参数是否是无穷大 function s(n) { if (isFinite(n) && n > 0 && n == Math.round(n)) { if (!(n in s)) { s[n] = n * s(n - 1); } return s[n]; } else { return NaN; } } s[1] = 1;
s(2);//2
s(3);//6
s(5);//120
8、函数的命名空间
//定义一个扩展函数,用来将第二个及后续的参数复制到第一个参数上 var extend = (function () { for (var p in { toString : null }) { return function extend(o) { for (var i = 0; i < arguments.length; i++) { var source = arguments[i]; for (var prop in source) { o[prop] = source[prop]; } } return o; } } return function patch_extend(o) { for (var i = 0; i < arguments.length; i++) { var source = arguments[i]; for (var prop in source) { o[prop] = source[prop]; } for (var j = 0; j < protoprops.length; j++) { prop = protoprops[j]; if (source.hasOwnProperty(prop)) { o[prop] = source[prop]; } } } return o; } var protoprops = ['toString', 'valueOf', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumable', 'toLocaleString']; }());
9、闭包的使用
var a = "1"; //全局 function chech() { var a = "2"; //局部 function f() { return a; } return f(); //执行 f()时依然在局部 } chech(); //这里返回2 //另外一个例子: var a = "1"; //全局 function chech() { var a = "2"; //局部 function f() { return a; } return f; } chech()(); //这里返回2 //javascript 函数执行的时候用到了作用域链,这个作用域链是在函数定义的时候创建的,嵌套的函数f()定义在这个作用域链中,其中的a一定是局部变量,无论何时执行f(),这种绑定是一种有效的。 //计数例子 var count = (function () { var num = 1; return function () { return num++; } } ()); //多个嵌套函数共同调用 function count() { var num = 1; return { reset : function () { return num = 1; }, conum : function () { return num++; } }; } var a = count(); var b = count(); a.conum(); //1 a.conum(); //2 b.reset(); //1 a.conum(); //3 //每次调用count会创建不同的作用域对象,两者并不会被干扰 //闭包例子: /*function repeat (func, times, wait) { * } //这个函数能返回一个新函数,比如这样用 * var repeatedFun = repeat(alert, 10, 5000) * //调用这个 repeatedFun ("hellworld") * //会alert十次 helloworld, 每次间隔5秒 * var repeatedFun = repeat(alert, 10, 100); * repeatedFun ("hellworld"); */ function repeat(func, times, wait) { return function (str) { var i = 0; var count = 0; var timer = setInterval(function () { count++; if (count % (wait / 1000) == 0) { alert(str); i++; if (i == times) { window.clearInterval(timer); } } }, 1000); } } var repeatedFun = repeat(alert, 10, 5000); repeatedFun('hellworld');
10、实参的个数检测
function check(args) { var actual = args.length; //实参的真实个数 var expected = args.callee.length; //期望的实参个数 if (actual !== expected) { throw Error('参数异常'); } } function sum(x, y, z) { check(arguments); return x + y + z; }
11、apply和call
//1、每个函数都包含两个非继承而来的方法:apply()和call()。 //2、他们的用途相同,都是在特定的作用域中调用函数。 //3、接收参数方面不同,apply()接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。 //call()方法第一个参数与apply()方法相同,但传递给函数的参数必须列举出来。 //例1: //代码如下: window.firstName = "diz"; window.lastName = "song"; var myObject = { firstName : "my", lastName : "Object" }; function HelloName() { console.log("Hello " + this.firstName + " " + this.lastName, " glad to meet you!"); } HelloName.call(window); //huo .call(this); HelloName.call(myObject); 运行结果为: Hello diz song glad to meet you! Hello my Object glad to meet you! //例子2: function sum(num1, num2) { return num1 + num2; } console.log(sum.call(window, 10, 10)); //20 console.log(sum.apply(window, [10, 20])); //30
12、bind函数
function f(y) { return this.x + y; } var o = { x : 1 }; var g = f.bind(o); g(2); //3 //例子2 function sum(x, y) { return x + y; } var s = sum.bind(null, 1); //这里的1绑定到x上 s(2); //3 //s(2)中的2绑定到y上了 function f(y, z) { return this.x + y + z; } var g = f.bind({ x : 1 }, 2); //这里this.x绑定到了x:1,y绑定到了2上 g(3); //这里3绑定到了z上 //结果为:6
13、函数的toString方法
//和所有的Javascript对象一样,所有的函数都有toString()方法,ECMAScript规定它返回一个字符串! //大多数的代码返回的都是函数的源代码,少数会返回[native code]; function s() { console.log(this); } console.log(s.toString());
14、Function()创建函数
//Function()构造函数所创建的函数可以穿入任意数量的参数,最后一个参数就是函数的函数体 //例如: var d = new Function("a", "b", "return a;") //关于Function创建函数以下需要注意 //Function创建函数并非是使用词法作用域,相反,函数体代码的编译总是会在顶层函数执行: 如下代码: var scope = "global"; function s() { var scope = "local"; return new Function('return scope'); //此处提前执行,是找不到局部变量的 } s(); //返回global
15、高阶函数
//高阶函数,即操作函数的函数,它接收一个或多个函数作为参数,返回一个新的函数! function not(f) { return function () { var result = f.apply(this, arguments); return !result; } } var even = function () { return even % 2 === 0; } var odd = not(even); [1, 3, 5, 7, 9].every(odd); //true
16、记忆函数
function s(f) { var cache = {}; return function () { //将实参转换为字符串形式,并将其用做缓存的键 var key = arguments.length + Array.prototype.join.call(arguments, ','); if (key in cache) { console.log(cache[key]); return cache[key]; } else { console.log(cache[key]); return cache[key] = f.apply(this, arguments); } } } //使用1 function gcd(a,b){ var t; if(a<b){ t = b;b = a; a = t; } while(b != 0){ t = b;b = a%b; a = t; return a; } } var gcmo = s(gcd); gcmo(85,187); //使用2 var fac = s(function(n){ return (n <= 1) ? 1 : n*fac(n-1); }); fac(5);//120