-
Notifications
You must be signed in to change notification settings - Fork 3.3k
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 103 题:模拟实现一个 localStorage #166
Comments
|
没有校验 value 是否为字符串 |
因为自带的localStorage也是把对象自动转成字符串的。我测试过自带的localStorage也是这样子。 |
'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)
}
}
}) |
class mockLocalStorage {
constructor() {
this.store = {}
}
getItem(key) {
return this.store[key] || null
}
setItem(key,value) {
this.store[key] = value
}
removeItem(key) {
delete this.store[key]
}
clear() {
this.store = {}
}
}
window.localStorage2 = new mockLocalStorage() |
这答案吓到我了。存储过之后,刷新页面,还能取出来吗??? |
代理中这个判断又什么作用呀 |
|
|
我的也是这样的,你可以试一下啊。 |
localStorage 可以通过 localStorage.xxx 方式取值。 |
https://html.spec.whatwg.org/multipage/webstorage.html#dom-localstorage 这个是localStorage的定义似乎还挺复杂的 |
难道不是应该用 cookie 模拟 localStorage 吗(兼容 IE8 及以下的 polyfill)? !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); |
@wingmeng 使用cookie解决了刷新浏览器存储信息不被清除的问题,但是这样存储的信息就参与了服务器的通信,增加了请求负担,这个问题需要考虑吗 |
@wingmeng 考虑了刷新浏览器存储信息不被清除。 |
localStorage.setItem('a', {a:1})
undefined
localStorage.getItem('a')
"[object Object]"
a={a:1}
localStorage.setItem(a, {a:1})
{[object Object]: "[object Object]"}
localStorage.setItem('a', document.body)
localStorage.getItem('a')
"[object HTMLBodyElement]" |
// 模拟实现一个 localStorage |
|
嗯,加上这2点,就变得更加智能了,省去了手动序列化的操作
…------------------ 原始邮件 ------------------
发件人: "james9527"<[email protected]>;
发送时间: 2019年7月12日(星期五) 上午9:48
收件人: "Advanced-Frontend/Daily-Interview-Question"<[email protected]>;
抄送: "最快的蜗牛"<[email protected]>; "Comment"<[email protected]>;
主题: Re: [Advanced-Frontend/Daily-Interview-Question] 第 103 题:模拟实现一个 localStorage (#166)
` 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 是否为字符串
因为自带的localStorage也是把对象自动转成字符串的。我测试过自带的localStorage也是这样子。
楼主写的基本上跟浏览器自带的功能一样了,localStorage.setItem存一个对象时一般要加上JSON.stringify序列化下,localStorage.getItem取一个对象时再用JSON.parse反序列化下就可以了。
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
|
localStorage 难道最主要的功能不是持久化存储么?还可以在控制台手动删除。上面的答案没有一个能打的啊 |
你要知道,js的权限是被限制的,如果不用浏览器自带的,是不可能持久化的。 |
所以上面模拟的都是啥,就实现一个api也叫模拟么?就不说持久化存储好了,最基本的容量限制也没处理吧? |
这,要不你设计一个,我们只是给自己的想法而已,有缺陷是很正常的啊。 |
使用Map数据结构构造localstorage
测试 this.mockLocalstorage = new mockLocalstorage();
this.mockLocalstorage.setItem("name", "duya");
console.log(this.mockLocalstorage.getItem("name")); // 测试mockLocalstorage duya |
为什么要用proxy啊,它的作用是什么呢?求解 |
不用proxy,也可以localStorage.xxx方式取值啊~~~ |
这个题目设计的没有意义。 我一看题目就觉得实现的是持久化存储 |
忽略了 localStorage 的特性,即刷新,关闭页面仍然存在。正解应该是使用能够持久化的方法或者接口,比如 cookie 来模拟实现。 #171 |
如题(localStorage)的核心功能没有体现,持久化存储不是js模拟能实现的,浏览器自带功能还是借助浏览器吧 |
localStorage.key(i)访问key的时候,越界返回null,arr[i]越界返回undefined,需要修正这一点。 |
如果是要求实现localStorage的持久化存储功能....这是不可能的; 如果不是,那么这个题....好像没有什么意义啊,最多考察一下语法 |
标注是阿里的题,明显考察的是用cookie实现polyfill,为啥一堆人认为在考api语法... |
可是这样无法实现持久存储啊 |
全都没有考虑持久化存储呀, 我的想法是通过cookie或者indexedDB |
使用indexedDB 模拟实现一个基础的 localStorageindex.html,添加一个触发按钮<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<button>set</button>
</body>
</html>
<script src="./localStorageMock.js"></script> localStorageMock.jsconst name = Symbol('localStorageMock');
const localStorageMock = new (class {
constructor() {
Object.assign(this, { [name]: {}, db: {}, objectStore: {}, result: '' });
Object.defineProperties(this, {
DBOpenRequest: {
value: window.indexedDB.open('localStorageMock', 1),
writable: false,
configurable: false,
},
});
this.DBOpenRequest.onupgradeneeded = event => {
this.db = event.target.result;
if (!this.db.objectStoreNames.contains('store')) {
this.objectStore = this.db.createObjectStore('store', { keyPath: 'name' });
this.objectStore.createIndex('name', 'name', { unique: false });
}
};
this.DBOpenRequest.onerror = event => console.error(event);
this.DBOpenRequest.onsuccess = event => {
this.db = event.target.result;
};
}
/** 获取所有Storage数据列表 */
readAll() {
return new Promise(resolve => {
let objectStore = this.db.transaction('store').objectStore('store');
let arr = [];
objectStore.openCursor().onsuccess = event => {
let cursor = event.target.result;
if (cursor) {
arr.push(cursor.value);
cursor.continue();
return resolve(arr);
} else {
console.log('没有更多数据了!');
}
};
});
}
getItem(key) {
return new Promise((resolve, reject) => {
let request = this.db
.transaction(['store'], 'readonly')
.objectStore('store')
.index('name')
.get(key);
request.onerror = () => reject('事务失败');
request.onsuccess = function(event) {
if (request.result) {
return resolve(request.result);
} else {
return reject('未获得数据记录');
}
};
});
}
/** 注意隐患,刷新会情况this[name]数据,建议直接setItem */
add(key, value) {
console.log(this[name].hasOwnProperty(key));
if (this[name].hasOwnProperty(key)) {
return this.setItem(key, value);
}
Object.assign(this[name], { [key]: value });
let request = this.db
.transaction(['store'], 'readwrite')
.objectStore('store')
.add({ name: key, value: value });
request.onsuccess = event => console.log('数据写入成功', event.target.result);
request.onerror = err => console.error('数据写入失败', err.target.error);
}
removeItem(key) {
let request = this.db
.transaction(['store'], 'readwrite')
.objectStore('store')
.delete(key);
request.onsuccess = () => console.log('数据删除成功');
request.onerror = err => console.error('数据删除失败', err);
}
clear() {
let request = this.db
.transaction(['store'], 'readwrite')
.objectStore('store')
.clear();
request.onsuccess = () => console.log('数据库清除成功');
request.onerror = err => console.error('数据库清除失败', err);
}
setItem(key, value) {
let request = this.db
.transaction(['store'], 'readwrite')
.objectStore('store')
.put({ name: key, value: value });
request.onsuccess = () => console.log('数据写入成功');
request.onerror = err => console.error('数据写入失败', err);
}
})();
document.getElementsByTagName('button')[0].addEventListener('click', async function() {
console.log(localStorageMock);
await localStorageMock.setItem('小明', '22岁');
console.log(await localStorageMock.getItem('小明'));
console.log(await localStorageMock.readAll());
await localStorageMock.removeItem('小明');
await localStorageMock.clear();
}); |
No description provided.
The text was updated successfully, but these errors were encountered: