zoukankan      html  css  js  c++  java
  • Javascript语言精粹The Excellence in Javascript

    //Javascript语言精粹 全书脚本Demo,可以用Firefox 的firebug运行每个demo

    demo url:https://files.cnblogs.com/vihone/TheExcellenceInJavascript.rar

    //3.5 原型 if(typeof Object.beget !== 'function') {  Object.beget = function(o)  {   var F = function() {};   F.prototype = o;   return new F();  }; }

    var another_stooge = Object.beget(stooge); another_stooge['first-name'] = 'Vihone'; another_stooge['middle-name'] = 'He'; another_stooge.nickname = 'Moe';

    //4.6 var add = function(a, b) {  if(typeof a !== 'number' || typeof b !== 'number')  {   throw 'add needs numbers';  }  return a + b; };

    //4.7 Function.prototype.method = function(name,func) {  this.prototype[name]=func;  return this; };

    Number.method('integer',function() { return Math[this<0 ? 'ceil':'floor'](this); });

      var foo = function() {  var a = 3, b=5;  var bar = function()  {   var b = 7, c=11;   a+=b+c;  };  bar();  console.log(a);  console.log(b);  console.log(c); }; foo();

    document.writeln((-10/3).integer());

    var myObject = function() {  var value = 0;  return  {   increment: function(inc)   {      value += typeof inc === 'number' ? inc :1;   },   getValue:function()   {    return value;   }  } }();

    var quo = function(status) {     return     {         get_status : function()         {             return status;         }     }; }; var myQuo = quo("amazed"); myQuo.get_status();

    var fade = function() {  node = document.body;     var level = 1;     var step = function()     {         var hex = level.toString(16);         node.style.backgroundColor = '#FFFF'+hex+hex;         if(level<15)         {             level +=1;             setTimeout(step,100);         }        };     setTimeout(step,100); };

    var add_the_handlers = function() {  var nodes = document.getElementsByTagName("input");  var i ;  for(i=0;i<nodes.length;i++)  {   nodes[i].onclick = function(i)   {    return function(e)    {     alert(e);    }   }(i);  } };

    //4.12 String.method('deentityify',function() {  var entity =  {   quot:'"',   lt:'<',   gt:'>',  };

     return function()  {   return this.replace(/&([^&;]+);/g,   function(a,b,c,d)   {    var r = entity[b];    //console.log(a);   //a 依次为 &lt;  &quot;  &gt;    //console.log(b);   //b 依次为 1t  quot   gt    //console.log(c);   //c 依次为 0 4 10    //console.log(d);   //d 为stringObj --> &lt;&quot;&gt;    return typeof r === 'string' ? r : a;   });  } }()); console.log('&lt;&quot;&gt;'.deentityify()); //replace方法的语法是:stringObj.replace(rgExp, replaceText) 其中stringObj是字符串(string),reExp可以是正则表达式对象(RegExp)也可以是字符串//(string),replaceText是替代查找到的字符串

    //如果 replaceText 为函数,对于每一个匹配的子字符串,调用该函数时带有下面的 m+3 个参数,此处 m 是在 rgExp 中捕获的左括弧的个数。第一个参数是匹配的子字符//串。接下来的 m 个参数是查找中捕获的全部结果。第 m+2 个参数是在 stringObj 中匹配出现的偏移量,而第 m+3 个参数为 stringObj。结果为将每一匹配的子字符串替//换为函数调用的相应返回值的字符串值

    //4.14 Function.method('curry',function() {  var slice = Array.prototype.slice,  args = slice.apply(arguments);//curry 的参数  //console.log(args);  //[1]  that = this;  return function()  {   //console.log(slice.apply(arguments)); //[6] 当然的参数   return that.apply(null,args.concat(slice.apply(arguments)));  }; });

    //console.log(add.curry(1)(6));   //7 var add1 = add.curry(1); console.log(add1(6));  //7

    //4.15 var count = 0; var fibonacci = function(n) {  //return n < 2 ? n : fibonacci(n-1) + fibonacci(n-2);  var memo = [0, 1];    var fib = function(n)  {   var result = memo[n];   count +=1;   if(typeof result !== 'number')   {    result = fib(n-1) + fib(n-2);    memo[n] = result;   }   return result;  };  return fib; }();

    var memoizer = function(memo, fundamental) {  var shell = function(n)  {   var result = memo[n];   count +=1;   if(typeof result !== 'number')   {    result = fundamental(shell, n);    memo[n] = result;    console.log(memo);//memo中存储每次计算后的值memo[0,1,1,2,3,5,8,13,21,34,55,...]   }   return result;  };    return shell; };

    //Fibonacci 数列 var fibonacci = memoizer([0, 1],function(shell, n) {  return shell(n-1) + shell(n-2); });

    //阶乘 var factorial = memoizer([0,1],function(shelll, n) {  return n * shell(n-1); });

    for(var i = 0; i <=10; i++) {  console.log('//' + i + ': ' + fibonacci(i)); }

    //第5章 继承

    function foo(a, b, c) {     return a*b*c; };

    console.log(foo.length);               //3 console.log(typeof foo.constructor);   //function console.log(typeof foo.call);          //function console.log(typeof foo.apply);         //function console.log(typeof foo.prototype);     //object

    //对于任何一个函数的声明,它都将会具有上面所述的5个property(方法或者属性)。

    //5.1 if(typeof Object.beget !== 'function') {  Object.beget = function(o)  {   var F = function() {};   F.prototype = o;   return new F();  }; }

    Function.method('new',function() {  var that = Object.beget(this.prototype);

     var other = this.apply(that,arguments);

     return (typeof other === 'object' && other) || that; });

    var Mammal = function(name) {  this.name = name; };

    Mammal.prototype.get_name = function() {  return this.name; };

    Mammal.prototype.says = function() {  return this.saying || ''; };

    var myMammal = new Mammal('Herb the Mammal'); var name = myMammal.get_name(); console.log(name);

    var Cat = function(name) {  this.name = name;  this.saying = 'meow'; };

    Cat.prototype = new Mammal();

    Cat.prototype.purr = function(n) {  var i, s = '';  for(i = 0; i < n; i +=1)  {   if(s)   {    s += '-';   }   s+= 'r';  }  return s; };

    Cat.prototype.get_name = function() {  return this.says() + ' ' + this.name + ' ' + this.says(); };

    var myCat = new Cat('Henrietta'); var says = myCat.says(); var purr = myCat.purr(5); var name = myCat.get_name(); console.log(says); console.log(purr); console.log(name);

    Function.method('inherits',function(Parent) {  this.prototype = new Parent();  return this; });

    var Cat = function(name) {  this.name = name;  this.saying = 'meow'; }.inherits(Mammal). method('purr', function(n) {  var i, s = '';  for(i = 0; i < n; i+=1)  {   if(s)   {    s+= '-';   }   s += 'r';  }  return s; }).method('get_name' function() {  return this.says() + ' ' + this.name + ' ' + this.says(); });

    var myCat = new Cat('Henrietta'); var says = myCat.says(); var purr = myCat.purr(5); var name = myCat.get_name(); console.log(says); console.log(purr); console.log(name);

    //5.3 var myMamml = {  name: 'Herb the Mammal',  get_name: function()  {   return this.name;  },  says: function()  {   return this.saying || '';  } };

    var myCat = Object.beget(myMammal); myCat.name = 'Henrietta'; myCat.saying = 'meow'; myCat.purr = function(n) {  var i, s = '';  for (i=0;i<n;i++ )  {   if(s)   {    s+='-';   }   s += 'r';  }  return s; };

    myCat.get_name = function() {  this.says + ' ' + this.name + ' ' + this.says; };

    //5.4函数化

    var mammal = function (spec) {  var that = {};  that.get_name = function()  {   return spec.name;  };  that.says = function()  {   return spec.saying || '';  };  return that; };

    var myMammal = mammal({name:'Herb'});

    console.log(myMammal.get_name()); //Herb console.log(myMammal.says()); //(空字符串) console.log(myMammal.name); //undefined

    var cat = function(spec) {  spec.saying = spec.saying || 'meow';  var that = mammal(spec);  that.purr = function(n)  {   var i, s = '';   for(i=0;i<n;i+=1)   {    if(s)    {     s += '-';    }    s += 'r';   }   return s;  };  that.get_name = function()  {   return that.says() + ' ' + spec.name + ' ' + that.says();  };  return that; };

    var myCat = cat({name:'Henrietta'});

    console.log(myCat.get_name());//meow Henrietta meow console.log(myCat.says());//meow console.log(myCat.purr(5));//r-r-r-r-r console.log(myCat.saying);//undefined console.log(myCat.name);//undefined

    Function.prototype.method = function(name,func) {  this.prototype[name]=func;  return this; };

    Object.method('superior',function(name) {  var that = this,  method = that[name];  return function()  {   return method.apply(that,arguments);  }; });

    var coolcat = function (spec) {  var that = cat(spec),  super_get_name = that.superior('get_name');  that.get_name = function(n)  {   return 'like ' + super_get_name() + ' baby';  };  return that; };

    var myCoolCat  = coolcat({name : 'Bix'}); var name = myCoolCat.get_name();

    console.log(name); //like meow Bix meow baby

    //5.5部件

    var eventuality = function(that) {  var registry = {};  that.fire = function(event)  {   var array,    func,    handler,    i,    type = typeof event === 'string' ? event : event.type;   if(registry.hasOwnProperty(type))   {    array = registry[type];    for(i = 0; i < array.length; i +=1)    {     handler = array[i];

        func = handler.method;     if(typeof func === 'string')     {      func = this[func];     }

        func.apply(this, handler.parameters || [event]);    }   }

      return this;  };

     that.on = function(type , method, parameters)  {   var handler =   {    method: method,    parameters:parameters   };

      if(registry.hasOwnProperty(type))   {    registry[type].push(handler);   }   else   {    registry[type] = [handler];   }   return this;  };  //eventuality(that);  return that; };

    //第6章 数组 //6.1数组字面量 var misc =  [     'string',98.6,true,false,null,undefined,     ['nested','array'],{object:true},NaN,Infinity    ]; console.log(misc[2]);   //true console.log(misc[4]);   //null      console.log(misc[5]);   //undefined console.log(misc[6]);   //["nested", "array"] console.log(misc[6][0]);  //nested console.log(misc[6][1]);  //array console.log(misc[6][2]);  //undefined console.log(misc[7]);     //Object { object=true} console.log(misc[7].object);  //true

    //6.5混淆的地方 var misc =  [     'string',98.6,true,false,null,undefined,     ['nested','array'],{object:true},NaN,Infinity    ]; var obj = {a:'1',b:'aaa',c:misc} console.log(misc.constructor) //Array() console.log(obj.constructor)  //Object() console.log(typeof misc.constructor) //function

    var is_array = function(value) {  return value &&  typeof value === 'object' &&  //value.constructor === Array;(//此方法不同识别从不同的窗口(window)或帧(frame)里构造的数组)  typeof value.length === 'number' &&  typeof value.splice === 'function' &&  !(value.propertyIsEnumerable('length'));   }; console.log(is_array(misc)); //true console.log(is_array(obj));  //false

    //6.6方法 Function.prototype.method = function(name,func) {  this.prototype[name]=func;  return this; };

    Array.method('reduce',function(f,value) {  var i;  for(i = 0;i <this.length;i++)  {   value =f(this[i],value);  }  return value; });

    var data = [4,8,15,16,23,42]; var add = function(a,b) {  return a + b; };

    var mult = function(a,b) {  return a*b;  };

    var sum = data.reduce(add,0); //sum is 108

    var product = data.reduce(mult,1); //product is 7418880

    data.total = function() {  return this.reduce(add,0); };

    total = data.total();

    console.log(sum);      //108 console.log(product);  //7418880 console.log(total);    //108

    //6.7维度 Array.dim = function(dimension,initial) {  var a = [],i;  for(i=0;i<dimension;i++)  {   a[i] = initial;  }  return a; };

    var myArray = Array.dim(10,0); console.log(myArray);    //[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

    var matrix = [     [0,1,2],     [3,4,5],     [6,7,8]    ]; console.log(matrix[2][1]); //7;

    //矩阵,二维数组 Array.matrix = function(m,n,initial) {  var a,i,j,mat=[];  for(i=0; i<m; i++)  {   a = [];   for(j=0; j<n; j++)   {    a[j] = initial;   }   mat[i]=a;  }  return mat; };

    var myMatrix = Array.matrix(4,4,1); console.log(myMatrix[3][3]);  //0

    //恒等矩阵 Array.identity = function(n) {  var i, mat = Array.matrix(n,n,0);  for(i=0;i<n;i++)  {   mat[i][i] = 1;  }  return mat; }; console.log(myMatrix); myMatrix = Array.identity(4); console.log(myMatrix[3][3]);   //1 console.log(myMatrix);

    //第7章 正则表达式 //7.1一个例子 var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/; var url = "http://wwww.ora.com:80/goodparts?q#fragment";

    var result = parse_url.exec(url); var names = ['url','schema','slash','host','port','path','query','hash']; var blanks = '      '; var i; for(i=0;i<names.length;i++) {  console.log(names[i] + ':' + blanks.substring(names[i].length),result[i]); }

    //url: http://wwww.ora.com:80/goodparts?q#fragment //schema:http //slash: // //host:  wwww.ora.com //port:  80 //path:  goodparts //query: q //hash:  fragment

    var parse_number =/^-?\d+(?:\.\d*)?(?:e[+\-]?\d+)?$/i; var test = function(num) {  console.log(parse_number.test(num); }; test('1');     //true test('number'); //false test('98.6');  //true test('132.21.86.100'); //false test('123.45E-67'); //true test('123.45D-67'); //false

    //第8章 方法 Function.prototype.method = function(name,func) {  this.prototype[name]=func;  return this; };

    Array.method('push',function() {  this.splice.apply(this,[this.length,0].concat(Array.prototype.slice.apply(arguments)));  return this.length; });

    var a = ['a','b','c']; var b = ['x','y','z']; var c = a.push(b,true); console.log(c); //5 console.log(a); //['a','b','c',['x','y','z'],true] console.log(a[3][0]);//x

    var by = function(name) {  return function(o,p)  {   var a, b;   if(typeof o === 'object' && typeof p ==='object' && o && p)   {    a = o[name];    b = p[name];    if(a === b)    {     return 0;    }    if(typeof a === typeof b)    {     return a < b ? -1 : 1;    }    return typeof a < typeof b ? -1 : 1;   }   else   {    throw 'Expected an object when sorting by ' + name;    //{     //name : "Eror",     //message: 'Expected an object when sorting by ' + name;    //}   }  }; };

    var s = [    {first:'Joe',last:'Besser'},    {first:'Moe',last:'Howard'},    {first:'Joe',last:'Derita'},    {first:'Shemp',last:'Howard'},    {first:'Larry',last:'Fine'},    {first:'Curly',last:'Howard'}   ]; var m = ['aa','bb','a',4,8,15,16,23,42]; var n = [4,8,15,16,23,42];

    s.sort(by('first')); //s.sort(by('first')).sort(by('last')); console.log(s);  //

    var sortcallback = function(a,b) {     if(a ===b)     {         return 0;     }     if(typeof a === typeof b)     {         return a < b ? -1 :1;     }     return typeof a < typeof b ? -1:1; }; m.sort(sortcallback); n.sort(sortcallback);

    console.log(m);  // console.log(n);  // 

    var by = function(name,minor) {  return function(o,p)  {   var a, b;   if(typeof o === 'object' && typeof p ==='object' && o && p)   {    a = o[name];    b = p[name];    if(a === b)    {     return typeof minor === 'function' ? minor(o,p) : 0;    }    if(typeof a === typeof b)    {     return a < b ? -1 : 1;    }    return typeof a < typeof b ? -1 : 1;   }   else   {    throw 'Expected an object when sorting by ' + name;    //{     //name : "Eror",     //message: 'Expected an object when sorting by ' + name;    //}   }  }; };

    s.sort(by('last',by('first'))); console.log(s);  //

    Array.method('splice',function(start,deleteCount) {  var max = Math.max,   min = Math.min,   delta,   element,   insertCount = max(arguments.length-2,0),   k = 0,   len = this.length,   new_len,   result = [],   shift_count;  start = start || 0;  if(start < 0)  {   start += len;  }  start = max(min(start,len),0);  deleteCount = max(min(typeof deleteCount === 'number' ? deleteCount :len, len-start),0);  delta = insertCount - deleteCount;  new_len = len + delta;  while(k < deleteCount)  {   element = this[start + k];   if(element !== undefined)   {    result[k] = element;   }   k += 1;  }  shift_count = len - start - deleteCount;  if(delta < 0)  {   k = start + insertCount;   while(shift_count)   {    this[k] = this[k-delta];    k += 1;    shift_count -= 1;   }   this.length = new_len;    }  else if(delta > 0)  {   k = 1;   while(shift_count)   {    this[new_len - k] = this[len - k];    k += 1;    shift_count -= 1;   }  }    for(k = 0; k < insertCount; k += 1)  {   this[start + k] = arguments[k + 2];  }  return result;  });

    var a = ['a','b','c']; var r = a.splice(1,1,'ache','bug','c'); // console.log(a);  //['a','ache','bug','c']; console.log(r);  //['b']

    //Function Function.method('bind', function(that) {  var method = this,   slice = Array.prototype.slice,   args = slice.apply(arguments,[1]);   console.log(args);   return function()   {    return method.apply(that,args.concat(slice.apply(arguments,[0])));   }; });

    var x = function() {  return this.value; }.bind({value:666}); console.log(x());  //666

    //RegExp String.method('deentityify',function() {  var entity =  {   quot:'"',   lt:'<',   gt:'>',  };

     return function()  {   return this.replace(/&([^&;]+);/g,   function(a,b,c,d)   {    var r = entity[b];    //console.log(a);   //a 依次为 &lt;  &quot;  &gt;    //console.log(b);   //b 依次为 1t  quot   gt    //console.log(c);   //c 依次为 0 4 10    //console.log(d);   //d 为stringObj --> &lt;&quot;&gt;    return typeof r === 'string' ? r : a;   });  } }());

    var text = '<html><body bgcolor=linen><p>'+    'This is <b> bold<\/b>!<\/p><\/body><\/html>';

    var tags = /[^<>]+|<(\/?)([A-Za-z]+)([^<>]*)>/g; var a,i; while((a=tags.exec(text))) {  for(i=0;i<a.length;i+=1)  {   console.log(('//[' + i + '] ' + a[i]).deentityify());  }  console.log(); }

    //String.match var text = '<html><body bgcolor=linen><p>'+    'This is <b> bold<\/b>!<\/p><\/body><\/html>';

    var tags = /[^<>]+|<(\/?)([A-Za-z]+)([^<>]*)>/g; var a,i; a = text.match(tags); for(i=0;i<a.length;i+=1) {  console.log(('//[' + i + '] ' + a[i]).deentityify()); }

    //附录A //A.3 //返回的值如果是一个表达式, 则这个表达式的开始部分必须与return语句在同一行 var x = function() {     return  {         status:true     }; } console.log(x()); //undefined

    var x = function() {     return{         status:true     }; } console.log(x()); //Object { status=true}

    //A.6 typeof if (my_value && typeof my_value === 'object') { }

    //A.9 float var x = 0.1 + 0.2; console.log(x); //0.30000000000000004 console.log(x.toFixed(1)); //0.3

    //A.10 NaN function isNumber(value) {  return { typeof value === 'number' && isFinite(value); } };

    //A.11 伪数组 Array if(my_value && typeof my_value === 'object' && my_value.constructor === Array) {}

    //正可靠的判的数组的方法 if (my_value && typeof my_value === 'object' && typeof my_value.length === 'number' && !(my_value.propertyIsEnumerable('length')) { }

    //A.14 对象 var i; var word; var text =   "This oracle of comfort has so pleased me, " +   "That when I am in heaven I shall desire " +   "To see what this child does, " +   "and praise my Constructor."; var words = text.toLowerCase().split(/[\s,.]+/); var count = {}; for ( i = 0; i < words.length;i +=1) {  word = words[i];  if(typeof count[word] === 'number')  {   count[word] +=1;  }  else  {   count[word] = 1;  } } console.log(count);

    //附录E //E3 JSON var json_parse = function() {  // 这是一个能把json文本解析成JavaScript数据结构的函数  // 它是一个简单的递归降序解析器  var at,  //当然字符的索引   ch,  //当前字符   escape = {    '"': '"',    '\\': '\\',    '/':  '/',    b:    'b',    f:    '\f',    n:    '\n',    r:    '\r',    t:    '\t'   },  text,  error = function(m)  {   throw{    name:  'SynctaxError',    message:m,    at:     at,    text:   text   }  },  next = function(c){  //如果提供了参数c, 那么检查它是否匹配当前字符   if (c && c !== ch)   {    error("Expected '" + c + "' instead of '" + ch + "'");   }   //获取下一个字符,当没有下一个字符时,返回一个空字符串   ch = text.chartAt(at);   at += 1;   return ch;  },    number = function()  {  //解析一个数字值   var number ,    string = '';   if (ch === '-')   {    string = '-';    mext('-');   }   while (ch >= '0' && ch <= '9')   {    string += ch;    next();   }   if (ch === '.')   {    string  += '.';    while (next() && ch >= '0' && ch <= '9')    {     string += ch;    }   }   if (ch === 'e' || ch === 'E')   {    string += ch;    next();       if (ch === '-' || ch === '+')    {     string += ch;     next();    }    while (ch >= '0' && ch <= '9')    {     string += ch;     next();    }      }   number = +string;   if (isNaN(number))   {    error("Bad number");   }   else   {    return number;   }  },  string = function(){   var hex,    i,    string = '',    uffff;   //当解析字符串时,我们必须找到" 和 \ 字符   if(ch === '"')   {    while (next())    {     if (ch === '"')     {      next();      return string;     }     else if (ch === '\\')     {      next();      if (ch === 'u')      {       uffff = 0;       for (i = 0; i < 4; i++)       {        hex = parseInt(next(),16);        if(!isFinite(hex))        {         break;        }        uffff = uffff * 16 + hex;       }       string += string.fromCharCode(uffff);      }      else if ( typeof escape[ch] === 'string')      {       string += escape[ch];      }      else      {       break;      }     }     else     {      break;     }         }   }   error("Bad String");  },    white = function()  {//跳过空白   while (ch && ch <= ' ')   {    next();   }  },    word = function()  {   //true, false, null   switch (ch)   {    case 't':     next('t');     next('r');     next('u');     next('e');     return true;    case 'f':     next('f');     next('a');     next('l');     next('s');     next('e');     return false;    next('n');     next('n');     next('u');     next('l');     next('l');     return null;   }   error("Unexpected '" + ch + "'");  },    value, //值函数的点位符  array = function()  {   //解析一个数组值   var array = [];   if (ch === '[')   {    next('[');    white();    if (ch === ']')    {     next(']');     return array; //空数组    }    while (ch)    {     array.push(value());     white();     if (ch===']')     {      next(']');      return array;     }     next(',');     white();    }   }   error("Bad array");  },    //解析一个对象值  object = function()  {   var key,    object = {};   if (ch === '{')   {    next('{');    white();    if (ch === '}')    {     next('}');     return object; //空对象    }    while(ch)    {     key = string();     white();     next(':');     object[key] = value();     white();     if (ch === '}')     {      next('}');      return object;     }     next(',');     white();    }   }   error("Bad object");  },    //解析一个JSON值,它可以是对象,数组,字符串,数字或一个词  value = function()  {   white();   switch (ch)   {    case '{':     return object();    case '[':     return array();    case '"':     return string();    case '-':     return number();    default:     return ch >= '0' && ch <= '9' ? number() :word();   }  };

     //返回json_parse函数,它将能访问上述所有的函数和变量.  return function(source,reviver)  {   var result;      text = source;   at = 0;   ch = ' ';   result = value();   white();   if (ch)   {    error("Syntax error");   }      //如果存在reviver函数,我们就递归地对这个新结构调用walk函数,   //开始时先创建一个临时的启动对象,并以一个空字符串作为键名保存结果   //然后传递每个"名/值"对给reviver函数去处理可能存在的转换   //如果没有reviver函数,我们就简单地返回这个结果   return typeof reviever === 'function' ?    function walk(holder,key)    {     var k,      v,      value = holder[key];     if (value && typeof value === 'object')     {      for (k in value)      {       if (Object.hasOwnProperty.call(value,k))       {        v = walk(value,k);        if (v !== undefined)        {         value[k] = v;        }        else        {         delete value[k];        }       }      }     }     return reviver.call(holder,key,value);    }({'':result},''):result;  }   }();

  • 相关阅读:
    Deferred对象
    回流和重绘(转载)
    Javascript数组与类数组对象
    函数节流与函数去抖
    Express框架Fetch通信
    nodejs调试总结
    Webpack vs Gulp(转载)
    sourcetree管理git
    js时间转化
    React封装RadioGroup
  • 原文地址:https://www.cnblogs.com/vihone/p/2871825.html
Copyright © 2011-2022 走看看