[关闭]
@greenfavo 2015-10-12T10:55:30.000000Z 字数 4036 阅读 755

js函数学习笔记

js


一,用Array.sort()对数组排序

1,对字符串排序

  1. var a=new Array("Banana","chery","apple");
  2. a.sort();
  3. //忽略大小写
  4. a.sort(function(s,t){
  5. var a=s.toLowerCase();
  6. var b=t.toLowerCase();
  7. if(a<b) return -1;
  8. if(a>b) return 1;
  9. return 0;
  10. });

2,对数字排序

  1. var a=[33,4,111,222];
  2. a.sort();//默认按字母表顺序排序 111,222,33,4
  3. a.sort(function(a,b){//按数值大小排序
  4. return a-b;
  5. })//=>4,33,111,222

二,闭包

官方定义:函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内,这种特性在计算机科学文献中成为“闭包”。即函数定义时的作用域链到函数执行时依然有效

  1. //嵌套函数的词法作用域规则
  2. var scope="global scope";
  3. function checkscope(){
  4. var scope="local scope";
  5. function f(){return scope};
  6. return f();
  7. }
  8. checkscope();//=>"local scope"
  1. /*
  2. 嵌套的函数f()定义在这个作用域链里,其中的变量scope一定是局部变量, 不管在何时何地执行f(),这种绑定在执行f()时依然有效。
  3. 简而言之,闭包的这个特性大到让人吃惊:它们可以捕捉到局部变量(和参数),并一直保存下来,看起来像这些变量绑定到了在其中定义它们的外部函数
  4. */
  5. var scope="global scope";
  6. function checkscope(){
  7. var scope="local scope";
  8. function f(){return scope};
  9. return f;//注意此处没有括号
  10. }
  11. checkscope()();//=>"local scope"

在同一个外部函数内定义的多个嵌套函数也可以访问函数内部的私有变量,这多个嵌套函数都共享一个作用域链。

  1. function counter(){
  2. var n=0;
  3. return {
  4. count: function(){return n++;},
  5. reset: function(){n=0;}
  6. };
  7. }
  8. var c=counter(),d=counter();//创建2个计数器
  9. c.count();//=>0
  10. d.count();//=>0 它们互不干扰
  11. c.reset();//reset()和count()方法共享状态
  12. c.count();//=>0 因为我们重置了c
  13. d.count();//=>1 而没有重置d

下面这段代码创建了10个闭包,并将它们存储到一个数组中。这些闭包都是在同一个函数调用中定义的,因此它们可以共享变量i。当constfuncs()返回时,变量i的值是10,所有的闭包都共享这一个值。因此,数组中的函数的返回值都是同一个值。

  1. function constfuncs(){
  2. var funcs=[];
  3. for(var i=0;i<10;i++){
  4. funcs[i]=function(){return i;};
  5. }
  6. return funcs;
  7. }
  8. var func=constfuncs();
  9. func[5]();//=>10
  10. func[1]();//=>10
  11. func();//报错
  1. //上述代码正确的写法
  2. function constfunc(v){
  3. return function(){//注意单个return语句不能换行
  4. return v;
  5. };
  6. }
  7. //创建一个数组来存储常数函数
  8. var funcs=[];
  9. for(var i=0;i<10;i++){
  10. funcs[i]=constfunc(i);
  11. }
  12. funcs[5]();//=>5

四,函数属性,方法和构造函数

1,length属性
函数的length属性是只读的,表示在函数调用时期望传入函数的实参个数。

  1. function check(args){
  2. var actual=args.length;//实参的真实个数
  3. var expected=args.callee.length;//期望的实参个数
  4. if(actual!==expected){
  5. throw Error("期望"+expected+"个参数,得到"+actual+"个参数");
  6. }
  7. }
  8. function fx(x,y,z){
  9. check(arguments);//检查实参个数和形参个数是否一致
  10. return x+y+z;
  11. }
  12. fx(1,1);

2,call()方法和apply()方法
这两个方法看做是某个对象的方法,通过调用方法的形式来间接调用函数.call()和apply()的第一个实参是要调用函数的母对象,它是调用上下文,在函数体内通过this来获得对它的引用。
比如,要想以对象o的方法来调用函数f(),可以这样使用call()和apply():

  1. f.call(o);
  2. f.apply(o);
  3. //上面每行代码都和下面代码的功能类似(假设对象o中预先不存在属性m)
  4. o.m=f;//将f存储为o的临时方法
  5. o.m();//调用它,不传入参数
  6. delete o.m;//将临时方法删除

在ECMAScript5严格模式中,call和apply的第一个实参都会变为this的值,哪怕传入的实参是原始值甚至是null或undefined。在ECMAScript3和非严格模式中,传入的null和undefined都会被全局对象代替,而其他原始值则会被相应的包装对象所代替。
对于call()来说,第一个调用上下文实参之后的所有实参就是要传入待调用函数的值。比如,以对象o的方法的形式调用函数f(),并传入两个参数。

  1. f.call(o,1,2);

apply与call类似,只不过它的实参都放入一个数组中。
如果一个函数的实参是任意数量,给apply传入的参数数组可以是任意长度,例如,找出数组中的最大值

  1. var biggest=Math.max.apply(Math,[22,13,4545,1,.....]);

需要注意的是,传入apply()的参数数组可以是类数组对象也可以是普通的数组,实际上可以将当前函数的arguments数组直接传入apply()来调用另一个函数。

  1. f.apply(this,arguments);

3,bind()方法
这个方法的主要作用就是将函数绑定至某个对象。当在函数f()上调用bind()方法并传入一个对象o作为参数,这个方法将返回一个新的函数。以函数调用的方式调用新的函数将会把原始的函数f()当中o的方法来调用。传入新函数的任何实参都将传入原始函数。

  1. function f(y){//这个是待绑定的函数
  2. return this.x+y;
  3. }
  4. var o={x:1};//这个是将要绑定的对象
  5. var g=f.bind(o);//通过调用g(x)来调用o.f(x)
  6. g(2);//=>3

三,零碎记忆点

1,arguments是对实参对象的引用,是类数组,有length属性,但没有push,pop等数组方法。
2,为避免污染全局命名空间,可以将代码块放入一个函数中,或者直接定义一个匿名函数,并在单个表达式中调用它。

  1. (function(){
  2. //模块代码
  3. }());//结束函数定义并立即调用它

3,callee和caller属性
在ECMAScript5严格模式中,对着两个属性的读写操作都会产生一个类型错误。而在非严格模式下,ECMAScript标准规范规定callee属性指代当前正在执行的函数。caller是非标准的,但浏览器都实现了这个属性,它指代调用当前正在执行的函数的函数。通过caller属性可以访问调用栈。callee属性在某些时候会很有用,比如在匿名函数中通过callee来递归地调用自身。

  1. //callee与caller
  2. var factorial=function(x){
  3. if(x<=1) return 1;
  4. return x*arguments.callee(x-1);
  5. //return x*factorial.callee(x-1)结果一样
  6. };

4,大多数函数的toString()方法返回的是该函数源码,内置函数往往返回一个类似"[native code]"的字符串作为函数体。
5,Function()构造函数允许js在运行时动态地创建并编译函数。它所创建的函数并不使用词法作用域,相反,函数体代码的编译总是会在全局作用域中执行

  1. var scope="global";
  2. function constructFunction(){
  3. var scope="local";
  4. return new Function("return scope;");//无法捕捉局部作用域
  5. }
  6. constructFunction()();//=>"global"

5,可调用对象:是一个对象,但可以在函数调用表达式中调用这个对象。所有的函数都是可调用的,但并非所有可调用对象都是函数。就像类数组对象一样。诸如window.alert()和Document.getElementById()使用了可调用的宿主对象,而不是内置函数对象,RegExp也是可调用对象,只是越来越多的浏览器将它们函数化了,对它们做typeof操作,有些浏览器返回function,有些返回object.

6,我们可以通过使用 return 语句实现将函数返回调用它的地方。

在使用 return 语句时,函数会停止执行,并返回指定的值。

函数通常会返回一个唯一值,那么这个值也可能是另一个函数:

  1. <script type="text/javascript">
  2. //函数表达式
  3. var box = function(){
  4. var a=1;
  5. return function(){
  6. alert(a++)
  7. }
  8. alert(a);//永远不会执行
  9. }
  10. alert(box());//弹出"function(){alert(a++)}"
  11. </script>
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注