前端笔试题整理:活到老学到老③

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),一个对象存储空间可以存储多个对象数据,如下图所示:

在这里插入图片描述

 

おすすめ

転載: blog.csdn.net/qq_36451496/article/details/104294702