18、改造下面的代码,使之输出0 - 9,写出你能想到的所有解法。
for (var i = 0; i< 10; i++) {
setTimeout(() => { console.log(i);
}, 1000) }
答案:
首先我们先要复习一下setTimeout的用法:
方法一:
我们可以使用setTimeout的第三个参数,会作为回调函数的第一个参数传入;
利用bind函数部分执行的特性;
for (var i = 0; i < 10; i++) {
setTimeout(i = > {
console.log(i);
},1000, i)
}
for (var i = 0; i < 10; i++) {
setTimeout (console.log(i), 1000, i);
}
for (var i = 0; i < 10; i++) {
setTimeout(console.log.bind(Object.create(null), i), 1000);
}
bind()
方法创建一个新的函数,在 bind()
被调用时,这个新函数的 this
被指定为 bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
方法二:
利用let变量的特性——在每一次for循环的过程中,let声明的变量会在当前的块级作用域里面(for循环的body体,也就是两个花括号之间的内容区域)创建一个文法环境(lexical environment),该环境里面包含了当前for循环过程中的i, 参考链接
for (let i = 0; i< 10; i++) {
setTimeout(() = > {
console.log(i);
}, 1000)
}
等价于:
for (let i = 0; i < 10; i++) {
let _i = i; // const _i = i;
setTimeout(() = > {
console.log(_i);
}, 1000)
}
方法三:
利用函数自执行的方式,把当前for循环过程中的i传递出去,构建出块级作用域。IIFE其实并不属于闭包的范围。参考链接如下:
利用其它方式构建出块级作用域;
for (var i = 0; i < 10; i++) {
(i = > {
setTimeout(() = > {
console.log(i);
}, 1000)
})(i)
}
另一种实现方法:
for (var i = 0; i < 10; i++) {
try {
throw new Error(i);
} catch({
message: i
}) {
setTimeout(() = > {
console.log(i);
}, 1000)
}
}
方法四:
很多方案只是吧console.log(i)放到一个函数里面,因为setTimeout函数的第一个参数只接受函数以及字符串,如果是js语句的话,js引擎应该会自动在该语句外面包裹一层函数;
for (var i = 0; i < 10; i++) {
setTimeout(console.log(i), 1000);
}
for (var i = 0; i < 10; i++) {
setTimeout((i = > {
console.log(i);
})(i), 1000)
}
for (var i = 0; i < 10; i++) {
setTimeout((() = > {
console.log(i);
}) (), 1000)
}
18、下面的代码打印什么内容,为什么?
var b = 10;
(function b () {
b = 20;
console.log(b);
}) ();
答案:
ƒ b () {
b = 20;
console.log(b);
}
解析:先不看函数自执行,直接 fn b ()
首先函数声明比变量要高,其次b=20没有var获取,说明是window最外层定义的变量。js作用域中,先找最近的进行打印,那就是fn b ();如果b=20前面有var,那就是打印20。
19、简单改造下面的代码,使之分别打印10和20。
var b = 10;
(function b() {
b = 20;
console.log(b);
}) ();
答案:
1、打印10:
var b = 10;
(function b() {
window.b = 20;
console.log(b)
})(b);
var b = 10;
(function b (b) {
b.b = 20;
console.log(b);
})(b);
2、打印20:
var b = 10;
(function b() {
b = 20;
console.log(b);
})();
var b = 10;
(function b() {
var b = 20;
console.log(b);
})();
20、简单介绍HTML5缓存的机制:
答案:
首先,我们简单介绍一下服务器端的存储介质:
- cache:缓存,它可以让从数据库、磁盘上输出的数据存放在缓存里,从而减少数据库或是磁盘的读取与写入(IO)操作;
- 磁盘文件:我们常常会将图片、视频等文件存放在磁盘上;
- 数据库:MySQL、MongoDB.....关系\非关系数据库等;
- 内存:通常放置频繁需要使用到的东西,能够提升读取效率,缓存(cache)也是存放在内存里的。
HTML的存储-cookies:
在HTML5出生之前,通常在浏览器(客户端)使用cookies来存储客户端的内容;
cookies的特点:
- 每次的http请求头中,都会带有cookies——这是一个缺点;
- 每个域名只能存储4K大小的cookies;
- 主域名污染:如果我们使用cookies存储主域名的东西,那么子域名下得Http请求都会带上主域名的东西。
cookie分为会话cookie和持久cookie——
- 会话cookie是指在不设定它的生命周期expires时的状态,前面说了,浏览器的开启到关闭就是一次会话,当关闭浏览器时,会话cookie就会跟随浏览器而销毁。当关闭一个页面时,不影响会话cookie的销毁。会话cookie就像我们没有办理积分卡时,单一的买卖过程,离开之后,信息则销毁。
- 持久cookie则是设定了它的生命周期expires,此时,cookie像商品一样,有个保质期,关闭浏览器之后,它不会销毁,直到设定的过期时间。对于持久cookie,可以在同一个浏览器中传递数据,比如,你在打开一个淘宝页面登陆后,你在点开一个商品页面,依然是登录状态,即便你关闭了浏览器,再次开启浏览器,依然会是登录状态。这就是因为cookie自动将数据传送到服务器端,在反馈回来的结果。持久cookie就像是我们办理了一张积分卡,即便离开,信息一直保留,直到时间到期,信息销毁。
HTTP这一列,如果在setCookie的时候,这里就会打钩,这与HTTPOnly相关。
HTTPOnly:
如果把HTTPOnly设置为true,那么cookies只能被server服务器端来读取或是修改,客户端没有权限进行读取和修改。例如,我们在进行身份验证的时候,就可以使用这个。
Secure:与安全相关,如果设置了,那么请求只能是来自HTTP加密请求。
HTML的存储-UserData:
- 只有IE支持,由微软提供API,但不符合W3C标准;
- 存储在XML文件中。
-------------------------------------------------------分割线----------------------------------------------------------
针对以上问题,HTML5的出现,需要解决一下问题:
- 解决4K的大小问题;
- 解决请求头常带有存储信息的问题;
- 解决关系型存储的问题;
- 跨浏览器平台问题。
HTML5的存储形式:
- 本地存储——localStorage(永久存储,永不失效,除非手动删除)\sessionStorage(重新打开页面或是关闭浏览器的时候会消失)
存储大小:每个域名都能存5M
使用方法:主要涉及到5个方法:
getItem:获取localStorage\sessionStorage (使用方法:在console控制面板上输入localStorage.setItem('test1','test'); 这 时在Resources面板的Local Storage下,将会出现key = test1,value = test的记录,另外 localStorage.getItem('test1')的结果就是test)
setItem:设置localStorage\sessionStorage
removeItem:移除localStorage\sessionStorage
key:获取某一个位置上的key值,按值从0开始索引;
clear:全部清除localStorage\sessionStorage
本地存储可以存储什么(只要能转化为字符串的数据,都能被localStorage存储):
数组(需要将其序列化为字符串才能存储)、json数组(转化为字符串存储)、图片、脚本、样式文件(通过ajax)
- 离线缓存——application cache (web 应用可进行缓存,并可在没有因特网连接时进行访问)
- indexedDB(IndexedDB是一种低级API,用于客户端存储大量结构化数据(包括, 文件/ blobs)。该API使用索引来实现对该数据的高性能搜索)、Web SQL(Web SQL 数据库 API 并不是 HTML5 规范的一部分,但是它是一个独立的规范,引入了一组使用 SQL 操作客户端数据库的 APIs)
HTML5本地存储的使用限制以及解决方法:
- 存储更新策略,过期控制——localStorage是永不过期的,业务上如果想实现一些过期策略,需要在localStorage上加一层处理过期的机制;
- 各个子域名之间不能共享存储数据——可以借助HTML5的postMessage()这个API做一些跨域上的处理;
- 超出存储大小之后如何存储——使用一些如LRU、FIFO的算法去淘汰一些旧的数据;
- server端如何取到数据——使用post\get参数。
application cache简介:
它是能让web应用在离线的情况下继续使用,通过一个叫manifest的文件指明需要缓存的资源;你可以通过navigator.online
检测是否在线:
解释:
(1)用户通过浏览器(browser)去访问应用,首先检测浏览器是否有一个叫做“App cache”的东西存在,如果存在,则从中检索出app cache所要缓存的list,然后把资源(缓存在浏览器中)拉取出来,返回给用户;
(2)在访问的同时,会检查server上一个叫做manifest的文件,如果该文件有更新,就把manifest指定的文件从server端重新拉取一次,然后把这些缓存在浏览器中,并更新相应的app cache文件;如果manifest这个文件没有更新,那么就啥也不做。
从上图,我们总结2点:
- 缓存机制的改变,会更新app cache.但是,用户访问,会返回上一次的结果。这样一来,会有一个麻烦,即如果你的业务发生更改,你就需要去更新一次manifest。
注意:更改完,第一次是不生效的,只有第二次刷新才会生效;
- 如果有一个文件要更新,你就要去更新manifest,而更新manifest文件,它会把server上的文件全部重新拉取一次,而非只是拉取你需要更改的那个文件,这就会造成损耗;
indexedDB简介:
indexedDB是按域名分配独立空间,一个独立域名下可以创建多个数据库,每个数据库可以创建对个对象存储空间(表/table),一个对象存储空间可以存储多个对象数据,如下图所示: