牛客网前端大挑战题解

一、获取 url 中的参数
1. 指定参数名称,返回该参数的值 或者 空字符串
2. 不指定参数名称,返回全部的参数对象 或者 {}
3. 如果存在多个同名参数,则返回数组

看到牛客一位大神的代码非常简洁,如下:

function getUrlParam(sUrl, sKey) {
      var result = {};
      // replace()方法的参数replacement可以是函数。此时,每个匹配都调用该函数,它返回的字符串将作为替换文本使用。
      // 该函数的第一个参数是匹配模式的字符串,接下来的参数是与模式中的子表达式匹配的字符串,可以有0个或多个。
      // 再接下来的参数是一个整数,声明了匹配在stringObject中出现的位置,最后一个参数是stringObject本身
      sUrl.replace(/\??(\w+)=(\w+)&?/g, function (a, k, v) {
        // console.log(a);
        // console.log(k);
        // console.log(v);
        // void 0 === undefined, void 0比undefined占用的字节少,多用在压缩文件上
        if (result[k] !== void 0) {
          var t = result[k];
          result[k] = [].concat(t, v);
        } else {
          result[k] = v;
        }
      });
      if (sKey === void 0) {
        return result;
      } else {
        return result[sKey] || '';
      }
    }
console.log(getUrlParam("http://www.baidu.com/#/?t1=1&t3=2&t5=3"));

打印出来的a, k, v的值和最后结果如下:

打印结果

a对应匹配的字段,k对应参数,v对应参数值。
对于replace结合正则表达式的运用,可以看一下这篇:replace()结合正则表达式

二、根据包名,在指定空间中创建对象
如题:根据包名,在指定空间中创建对象
输入描述:namespace({a: {test: 1, b: 2}}, 'a.b.c.d')
输出描述:{a: {test: 1, b: {c: {d: {}}}}}

通俗说,就是:根据包名,比较指定空间中有没有与包名对应的对象,有则保留,无则创建一个空对象。

    function isObj(value) {
      return Object.prototype.toString.call(value) == "[object Object]";
    }

    function namespace(oNamespace, sPackage) {
      var scope = sPackage.split('.');
      var ns = oNamespace;
      for (var i = 0; i < scope.length; i++) {
        if (!ns.hasOwnProperty(scope[i]) || !isObj(ns[scope[i]])) {
          ns[scope[i]] = {};
        }
        ns = ns[scope[i]];
      }
      return oNamespace;
    }
    console.log(namespace({ a: { test: 1, b: 2 } }, 'a.b.c.d'));

这里有两点需要注意:
1、判断指定空间里是否存在于包名对应的对象,用hasOwnProperty判断是否存在,如果存在,接着判断是否为对象,正确的判断是:Object.prototype.toString.call(value) == "[object Object]";
2、对最后直接return oNamespace;的理解:Object是引用赋值,将对象赋值给某个变量,实际上相当于把指向引用类型的地址指针赋予给这个变量。两个变量都指向了堆内存中的同一个对象,他们中任何一个做出的改变都会反应在另一个身上。

三、数组去重
输入:[false, true, undefined, null, NaN, 0, 1, {}, {}, 'a', 'a', NaN]
输出:[false, true, undefined, null, NaN, 0, 1, {}, {}, 'a']
可以看出,需要对NaN去重, {}则不需要
1、使用indexOf()方法

    Array.prototype.uniq = function (){
      var newarr = [];
      var flag = true;
      for(var i = 0;i < this.length;i++) {
        if(newarr.indexOf(this[i]) == -1) {
          if(this[i] != this[i]) {
            if(flag) {
              newarr.push(this[i]);
              flag = false;
            }
          }else {
            newarr.push(this[i]);
          }
        }
      }
      return newarr;
    }

需要注意的点:
在indexOf判断中,NaN和空对象{}均返回-1,需要单独判断。而NaN和{}又有区别:

var a = NaN;
var b = NaN;
var c = {};
var d = {};
console.log(a == b);    // false
console.log(c == d);    // false
console.log(a == a);    // false
console.log(c == c);    // true

以上代码可以看出:NaN != NaN, {} != {},但NaN不等于它自己本身,{}会等于自己本身,可以以此来区分NaN和{}, 对NaN去重。
2、ES6 的Set方法

Array.prototype.uniq = function () {
    return [...new Set(this)];
}

有兼容性问题
3、使用splice直接在数组本身操作

    Array.prototype.uniq = function() {
      var hasNaN = false;
      for(var i = 0;i < this.length;i++) {
        if(this[i] !== this[i]) {
          hasNaN=true;
        }
        for(var j = i+1;i < this.length;) {
          if(this[i] === this[j] || (hasNaN && this[j] !== this[j])) {
            this.splice(j, 1);
          }else{
            j++;
          }
        }
      }
      return this;
    }

四、时间格式化输出
描述:
按所给的时间格式输出指定的时间
格式说明
对于 2014.09.05 13:14:20
yyyy: 年份,2014
yy: 年份,14
MM: 月份,补满两位,09
M: 月份, 9
dd: 日期,补满两位,05
d: 日期, 5
HH: 24制小时,补满两位,13
H: 24制小时,13
hh: 12制小时,补满两位,01
h: 12制小时,1
mm: 分钟,补满两位,14
m: 分钟,14
ss: 秒,补满两位,20
s: 秒,20
w: 星期,为 ['日', '一', '二', '三', '四', '五', '六'] 中的某一个,本 demo 结果为 五
输入: formatDate(new Date(1409894060000), 'yyyy-MM-dd HH:mm:ss 星期w')
输出: 2014-09-05 13:14:20 星期五

  function formatDate(oDate, sFormation) {
      var obj = {
        yyyy: oDate.getFullYear(), 
        yy: ("" + oDate.getFullYear()).slice(-2),
        M: oDate.getMonth() + 1,
        MM: ("" + (oDate.getMonth()+1)).slice(-2),
        d: oDate.getDate(),
        dd: ("0" + oDate.getDate()).slice(-2),
        H: oDate.getHours(),
        HH: ("0" + oDate.getHours()).slice(-2),
        h: oDate.getHours() % 12,
        hh: ("0" + oDate.getHours() % 12).slice(-2),
        m: oDate.getMinutes(),
        mm: ("0" + oDate.getMinutes()).slice(-2),
        s: oDate.getSeconds(),
        ss: ("0" + oDate.getSeconds()).slice(-2),
        w: ['日', '一', '二', '三', '四', '五', '六'][oDate.getDay()]
      };
      return sFormation.replace(/([a-z]+)/ig, function($1){return obj[$1]});
    }

    console.log(formatDate(new Date(1409894060000),'yy-MM-dd HH:mm:ss 星期w'));

$1 表示正则表达式第一个小括号中匹配项的值。

比如 /gai([\w]+?)over([\d]+)/
匹配 gainover123
$1= 括号里的 n
$2= 第2个括号里的 123

你可能感兴趣的:(牛客网前端大挑战题解)