Javascript语言精粹

来源:互联网 发布:统计软件 编辑:程序博客网 时间:2024/05/17 23:12
  1. 如何检查对象的类型

    关于对象的类型可以想到如下几个方法:

    1. typeof

      一元运算符,返回对象类型的字符串。可以识别原始值的类型和函数

    2. instanceof

      检测某个对象是否是是某一类,实际上检测的是一种继承关系,返回的是bool型

    3. constructor

      识别对象是否属于某一类的方法,根据的是这个构造器属性,有些对象可能没有constructor这个属性。

    4. classof

      自定义方法返回构造函数的名称,对于内置的方法有用,自定义的类不起作用。

      function classof(o){    return Object.prototype.toString.call(o).slice(8,-1);}
function myContructor1(name){    this.name=name}
obj typeof classof constructor getObjType null ‘object’ ‘Null’ ‘Null’ undefined ‘undefined’ ‘Undefined’ ‘Undefined’ ‘str’ ‘string’ ‘String’ function String() { [native code] } ‘String’ 3 ‘number’ ‘Number’ function Number() { [native code] } ‘Number’ true ‘boolean’ ‘Boolean’ function Boolean() { [native code] } ‘Boolean’ NaN ‘number’ ‘Number’ function Number() { [native code] } ‘Number’ new Array() ‘object’ ‘Array’ function Array() { [native code] } ‘Array’ new Date() ‘object’ ‘Date’ function Date() { [native code] } ‘Date’ new RegExp ‘object’ ‘RegExp’ function RegExp() { [native code] } ‘RegExp’ new myContructor1 ‘object’ ‘object’ function myContructor1() { [native code] } ‘myContructor1’ classof ‘function’ ‘Function’ function Function() { [native code] } ‘Function’

由上表可以看出:

typeof和classof对自定义类型无法识别,constructor对于具有constructor属性的对象可以识别自定义的类型。根据以上可以设计一个获取自定义构造函数name的函数,区分具有constructor属性的自定义函数。

function getName(o){    return o.constructor.toString().match(/^function\s*([^(]*)\(/)[1];}

综上构造一个比较通用的区分对象类型的方法:

function getObjType(o){    var t,c;    if((t= classof(o))!=='Object') return t;    if(o.constructor&&(c=getName(o))) return c;    return typeof o;}

对于自定义函数不存在constructor属性的构造函数返回的结果只能是object;

  1. 收集常用的正则表达式

    1. 解析URL;
    var str='https://www.baidu.com:8080/sadsd/ssssdsa?name=mzz#hash';var reg=/([\w]*):\/\/([\w.]*)(?::([\d]*))?((?:\/[\w]+)*)(?:\?([\w=&]*))?(?:#([\w]*))?/;console.log(str.match(reg));

    可以解析协议名,域名,端口,文件路径,参数,hash值,其中域名,文件路径,参数,hash值可以省略;

    1. 去掉前后空格;
    var str='  j j j    ';var reg=/^[\s]*([\w\s]*)[\s]*$/;str=str.replace(reg,'$1');console.log(str);
    1. 日期格式化;
      可以实现日期的多种格式化

    YYYY-MM-DD

    YYYY/MM/DD

    YYYY-MM-DD

    YYYY-MM-DD hh:mm : ss

    YYYY/MM/DD hh:mm : ss

    YYYY-MM-DD hh:mm : ss

    function formateDate(date,fomate){    var y=date.getFullYear(),        M=fomatelLen(date.getMonth()),        d=fomatelLen(date.getDate()),        h=fomatelLen(date.getHours()),        m=fomatelLen(date.getMinutes()),        s=fomatelLen(date.getSeconds());    var reg=/YYYY([-/:])MM([-/:])DD(?:[\s]*hh([-/:])mm([-/:])ss)?/;    return fomate.replace(reg,function(val,$1,$2,$3,$4){        if($3){            return y+$1+M+$2+d+' '+h+$3+m+$4+s;        }else{            return y+$1+M+$2+d;        }    });}function fomatelLen(m){    return m<10?'0'+m:m;}console.log(formateDate(new Date(),'YYYY-MM-DD hh:mm:ss'));

    正则知识基础知识复习点:

    1. 特殊字符
      ^ $ . * + ? = ! : | \ / ( ) [ ] { };
    2. 字符匹配 [],[^],.,\w,\W,\s,\S,\d,\D,[\b];
    3. 重复 {m,n},{n,},{n},?,+,*;?还可以表示非贪婪重复;
    4. 选择分组与引用:|,(),(?:),\n;
    5. 指定匹配位置 ^,$,\b,\B;
    6. 修饰符 i,g,m(多行匹配);
    7. String方法 search(),replace(),match();
    8. RegExp对象 exec(),test();
  2. 变量提前声明

    javascript中变量的作用域是函数作用域,就是说变量在函数的任何地方都是有定义的,包括函数的嵌套函数。’提前声明’是在javascript引擎的’预编译‘的时候进行,是在代码运行之前。声明提前啦但是初始化不会提前。所以下面1事例输出undefined。

    对下面其他三个的理解可能会有些偏差,请看见的朋友多指教

    我原本以为第二,三个会是undefined,第四个会报错,然而实际的结果却是获取到了传进来的参数的值。就此理解是:参数对具有相同参数名的局部变量进行了赋值并且对于数组,对象类的赋值不是引用赋值。

//1var hh='mzz';function fn(){    console.log(hh);    //undefined    var hh='zzq';}fn();
//2var hh='mzz';function fn(hh){    console.log(hh);    //mzz    var hh='zzq';}fn(hh);
//3var hh='mzz';function fn(hh){    var hh;    console.log(hh);    //mzz    hh='zzq';}fn(hh);
//4var hh=[1];function fn(hh){    var hh;    console.log(hh[0]); //1    hh=[2];    console.log(hh[0]); //2}fn(hh);console.log(hh[0]); //1
  1. 缓存

简单例子:

function fibonacci(){    var cache=[];    return function(n){        if(cache[n]){            return cache[n];        }        if(n==0){            cache[0]==0;            return 0;        }        if(n==1){            cache[1]==1;            return 1;        }        cache[n] = arguments.callee(n-1)+arguments.callee(n-2);        return cache[n];    }}var fib=fibonacci();console.log(fib(16));console.log(fib(8));

比较通用的缓存设计:

下面这种设计受传递的参数个数的限制,也不太通用,或许可以抽象做的更好

function memory(cache,fn){    return function(n){        if(cache[n]!==undefined){            return cache[n];        }        console.log('xxxxx');        return cache[n]=fn(arguments.callee,n);    }   }var fib=memory([0,1],function(fn,n){    return fn(n-1)+fn(n-2);});console.log(fib(10));var add=memory([1,1],function(fn,a){    return fn(a-1)*a;});console.log(add(5));console.log(add(4));
  1. 柯里化

定义:

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

根据含义我们可以写出如下事例:

function addAll(){    var cache=[];    return function(num){        if(num===undefined){            return cache.reduce(function(x,y){                return x+y;            })        }else{            cache.push(num);            return arguments.callee;        }    }}var _addobj=addAll();_addobj(1);_addobj(2);_addobj(3);console.log(_addobj());

上面这个函数实现了对传入的参数延迟相加求和的功能。

作用:

1. 参数复用;2. 提前返回;3. 延迟计算/运行。
  1. 函数的几种调用方式与内部this
    1. 方法调用:内部this指向这个方法所属的对象
    2. 函数调用:内部this指向window对象
    3. 构造函数调用:this指向一个新创建的对象,这个对象与构造函数具有同一个原型对象;
    4. call,apply:内部的this指向传入的第一个参数。

值得注意的是有时候this不知不觉被改变啦,如下:

var name='zzq';function Obj(name){    this.name=name;}Obj.prototype.getName=function(){    return this.name;}var obj=new Obj('mzz');console.log(obj.getName());     //mzzvar _getName=obj.getName;console.log(_getName());        //zzq  此处的this是window
0 0
原创粉丝点击