Github每日一题——7.15学习记录

2019-07-15  本文已影响0人  极奏

前言


题目来自Daily-Interview-Question 木易杨
欢迎star,加入讨论

本文记录自己对题目的解决方式以及综合大神们的看法。

题目


1、匹配elective后的数字输出(写出你认为的最优解法)

https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=&local_province_id=33
https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=800&local_province_id=33
https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=800,700&local_province_id=33

正则表达式解决方法:

const getUrlValue = function(url){
  let res = url.match(/(?<=elective=)(\d+(,\d+)*)/)
  return res ? res[0].split(',') : []
}

(?<=elective=) 是指匹配以elective=开头的字符串;
(\d+(, \d+))指匹配数字开头,可能不定数量逗号分隔后是数字的字符串。

String.prototype.match()

语法:

str.match(regexp)

参数:
返回值:

URLSearchParams的解决方案:

 new URLSearchParams('https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=800,700&local_province_id=33').get('elective')
urls.forEach(url => {
console.log(new URLSearchParams(url).get('elective').split(','));
});

URLSearchParams

构造函数:
方法:
不过URLSearchParams对IE的兼容性不友好

URL解决方法:

new URL
("[https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=700,800&local_province_id=33](https://www.xx.cn/api?keyword=&level1=&local_batch_id=&elective=700,800&local_province_id=33)")
.searchParams.get("elective")
.split(",")
.filter(e=>e)
.map(e=>e)

2、模拟实现一个 localStorage

localStorage

语法:

myStorage = localStorage

示例:

增加一个数据项目

localStorage.setItem('myCat', 'Tom');

读取 localStorage

let cat = localStorage.getItem('myCat')

移除 localStorage 项

localStorage.removeItem('myCat')

移除所有的 localStorage 项

localStorage.clear()

现在我们知道了localStorage的接口有增加,读取,删除和删除所有

思路:

先实现这些功能,然后挂载到全局变量里面去

来自EnergySUD的解决方案

const localStorageMock = (function() {
    let store = {}
    return {
        getItem: function(key) { return store[key] || null },
        setItem: function(key, value) { store[key] = value.toString() },
        removeItem: function(key) { delete store[key] },
        clear: function() { store = {} },
    }
})()

Object.defineProperty(window, 'localStorage2', {
    value: localStorageMock
})
        
localStorage2.setItem('test', 'test')
console.log(localStorage2.getItem("test"))  //test

localStorage2.removeItem('test')
console.log(localStorage2.getItem("test"))  //null

localStorage2.setItem('test', 'test')
localStorage2.clear()
console.log(localStorage2.getItem("test"))  //null

但是这个方法有问题,问题在于value的值如果是个对象,就跟浏览器的表示方式不一样。

方案二

楼下13834242832有个解决方案,用String字符串对象解决了上面的问题
同时用了Map对象来保存键值对

'use strict'
const valuesMap = new Map()

class LocalStorage {
  getItem (key) {
    const stringKey = String(key)
    if (valuesMap.has(key)) {
      return String(valuesMap.get(stringKey))
    }
    return null
  }

  setItem (key, val) {
    valuesMap.set(String(key), String(val))
  }

  removeItem (key) {
    valuesMap.delete(key)
  }

  clear () {
    valuesMap.clear()
  }

  key (i) {
    if (arguments.length === 0) {
      throw new TypeError("Failed to execute 'key' on 'Storage': 1 argument required, but only 0 present.") // this is a TypeError implemented on Chrome, Firefox throws Not enough arguments to Storage.key.
    }
    var arr = Array.from(valuesMap.keys())
    return arr[i]
  }

  get length () {
    return valuesMap.size
  }
}
const instance = new LocalStorage()

global.localStorage = new Proxy(instance, {
  set: function (obj, prop, value) {
    if (LocalStorage.prototype.hasOwnProperty(prop)) {
      instance[prop] = value
    } else {
      instance.setItem(prop, value)
    }
    return true
  },
  get: function (target, name) {
    if (LocalStorage.prototype.hasOwnProperty(name)) {
      return instance[name]
    }
    if (valuesMap.has(name)) {
      return instance.getItem(name)
    }
  }
})

Map

Objects 和 maps 的比较
相同点:
不同点:

来源:Map - JavaScript | MDN

Proxy

语法:
let p = new Proxy(target, handler)
参数:
实例:

在以下简单的例子中,当对象中不存在属性名时,缺省返回数为37,例子中使用了get
有一种给指定对象挂载了get方法的意思。

let handler = {
    get: function(target, name){
        return name in target ? target[name] : 37;
    }
};

let p = new Proxy({}, handler);

p.a = 1;
p.b = undefined;

console.log(p.a, p.b);    // 1, undefined

console.log('c' in p, p.c);    // false, 37

在以下例子中,我们使用了一个原生 JavaScript 对象,代理会将所有应用到它的操作转发到这个对象上。

let target = {};
let p = new Proxy(target, {});

p.a = 37;   // 操作转发到目标

console.log(target.a);    // 37. 操作已经被正确地转发

通过代理,你可以轻松地验证向一个对象的传值。这个例子使用了 set
有点将函数挂载到对象上的意思

let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }

    // The default behavior to store the value
    obj[prop] = value;
  }
};

let person = new Proxy({}, validator);

person.age = 100;

console.log(person.age); 
// 100

person.age = 'young'; 
// 抛出异常: Uncaught TypeError: The age is not an integer

person.age = 300; 
// 抛出异常: Uncaught RangeError: The age seems invalid

方法代理可以轻松地通过一个新构造函数来扩展一个已有的构造函数。这个例子使用了constructapply

function extend(sup,base) {
  var descriptor = Object.getOwnPropertyDescriptor(
    base.prototype,"constructor"
  );
  base.prototype = Object.create(sup.prototype);
  var handler = {
    construct: function(target, args) {
      var obj = Object.create(base.prototype);
      this.apply(target,obj,args);
      return obj;
    },
    apply: function(target, that, args) {
      sup.apply(that,args);
      base.apply(that,args);
    }
  };
  var proxy = new Proxy(base,handler);
  descriptor.value = proxy;
  Object.defineProperty(base.prototype, "constructor", descriptor);
  return proxy;
}

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

var Boy = extend(Person, function(name, age) {
  this.age = age;
});

Boy.prototype.sex = "M";

var Peter = new Boy("Peter", 13);
console.log(Peter.sex);  // "M"
console.log(Peter.name); // "Peter"
console.log(Peter.age);  // 13

有时你希望切换两个不同的元素的属性或类名

let view = new Proxy({
  selected: null
},
{
  set: function(obj, prop, newval) {
    let oldval = obj[prop];

    if (prop === 'selected') {
      if (oldval) {
        oldval.setAttribute('aria-selected', 'false');
      }
      if (newval) {
        newval.setAttribute('aria-selected', 'true');
      }
    }

    // The default behavior to store the value
    obj[prop] = newval;
  }
});

let i1 = view.selected = document.getElementById('item-1');
console.log(i1.getAttribute('aria-selected')); // 'true'

let i2 = view.selected = document.getElementById('item-2');
console.log(i1.getAttribute('aria-selected')); // 'false'
console.log(i2.getAttribute('aria-selected')); // 'true'

来源自Proxy - JavaScript | MDN

方案三

wingmeng解决了刷新浏览器存储信息不被清除的问题

!window.localStorage && !function(win) {
  var thousandYears = 1e3 * 365 * 24 * 36e5;

  function getCookies() {
    return document.cookie.match(/([^;=]+)=([^;]+)/g) || [];
  }

  function getExpires(flag) {
    flag = flag || 1;

    return 'expires=' +
      (new Date((+new Date()) + thousandYears * flag)).toUTCString();
  }

  function get(key) {
    var cookies = getCookies();

    for (var i = 0; i < cookies.length; i++) {
      var param = cookies[i].match(/^\s*([^=]+)=(.+)/);

      if (param[1] === String(key)) {
        return decodeURIComponent(param[2]);
      }
    }

    return null;
  }

  function set(key, value, isExpired) {
    document.cookie = [
      key + '=' + encodeURIComponent(value),
      getExpires(isExpired ? -1 : 1),
      'path=/'
    ].join('; ');
  }

  function remove(key) {
    set(key, '', true);
  }

  function clear() {
    var cookies = getCookies();

    for (var i = 0; i < cookies.length; i++) {
      var key = cookies[i].match(/^\s*([^=]+)/)[1];
      remove(key);
    }
  }

  // 注册到 window 对象上
  win.localStorage = {
    getItem: get,
    setItem: set,
    removeItem: remove,
    clear: clear
  };
}(window);

也可以看一下 MDN LocalStorage实现

未完待续
每日更新

上一篇 下一篇

猜你喜欢

热点阅读