33道面向初中级前端的基础面试题(持续更新中)

如需获取完整版229页PDF面试题,请直接滑到文末。

1.如何确定this指向

如果要判断一个运行中函数的 this 绑定,就需要找到这个函数的直接调用位置。找到之后就可以顺序应用下面这四条规则来判断 this 的绑定对象。

  1. 由 new 调用?绑定到新创建的对象。
  2. 由 call 或者 apply (或者 bind )调用?绑定到指定的对象。
  3. 由上下文对象调用?绑定到那个上下文对象。
  4. 默认:在严格模式下绑定到 undefined ,否则绑定到全局对象。

一定要注意,有些调用可能在无意中使用默认绑定规则。如果想“更安全”地忽略 this 绑定,你可以使用一个 DMZ 对象,比如 ø = Object.create(null) ,以保护全局对象。
ES6 中的箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this ,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这其实和 ES6 之前代码中的 self = this 机制一样

参考资料:

2.==和===的区别是什么

==是抽象相等运算符,而===是严格相等运算符。==运算符是在进行必要的类型转换后,再比较。===运算符不会进行类型转换,所以如果两个值不是相同的类型,会直接返回false。使用==时,可能发生一些特别的事情,例如:

1 == '1'; // true
1 == [1]; // true
1 == true; // true
0 == ''; // true
0 == '0'; // true
0 == false; // true

如果你对=====的概念不是特别了解,建议大多数情况下使用===

3.箭头函数和普通函数有什么区别

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象,用call apply bind也不能改变this指向
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
  • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
  • 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
  • 箭头函数没有原型对象prototype

4.白屏时间

白屏时间是指浏览器从输入网址,到浏览器开始显示内容的时间。

Performance 接口可以获取到当前页面中与性能相关的信息,该类型的对象可以通过调用只读属性 Window.performance 来获得。

performance.timing.navigationStart 是一个返回代表一个时刻的 unsigned long long 型只读属性,为紧接着在相同的浏览环境下卸载前一个文档结束之时的 Unix 毫秒时间戳。如果没有上一个文档,则它的值相当于 PerformanceTiming.fetchStart。

所以将以下脚本放在 </head> 前面就能获取白屏时间。

<script>
    new Date() - performance.timing.navigationStart
</script>

参考资料:

5.当你在浏览器输入一个地址后发生了什么

当···时发生了什么?

6.页面大量图片,如何优化加载,优化用户体验

  1. 图片懒加载。在页面的未可视区域添加一个滚动事件,判断图片位置与浏览器顶端的距离与页面的距离,如果前者小于后者,优先加载。
  2. 如果为幻灯片、相册等,可以使用图片预加载技术,将当前展示图片的前一张和后一张优先下载。
  3. 如果图片为css图片,可以使用CSSsprite,SVGsprite等技术。
  4. 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。
  5. 如果图片展示区域小于图片的真实大小,应在服务器端根据业务需要先进行图片压缩,图片压缩后大小与展示一致。

7.js网络请求性能优化之防抖与节流

防抖(debounce)

在函数需要频繁触发时,只有当有足够空闲的时间时,才执行一次。就好像在百度搜索时,每次输入之后都有联想词弹出,这个控制联想词的方法就不可能是输入框内容一改变就触发的,他一定是当你结束输入一段时间之后才会触发。

节流(thorttle)

预定一个函数只有在大于等于执行周期时才执行,周期内调用不执行。就好像你在淘宝抢购某一件限量热卖商品时,你不断点刷新点购买,可是总有一段时间你点上是没有效果,这里就用到了节流,就是怕点的太快导致系统出现bug。

区别

在发生持续触发事件时,防抖设置事件延迟并在空闲时间去触发事件,而节流则是隔一定的时间触发一次。

一个简单的防抖示例

let timer
input.on('input', () => {
    clearTimeout(timer)
    // 停止输入 500 毫秒后开始搜索
    timer = setTimeout(() => {
    // 搜索
    }, 500)
})

一个简单的节流示例

let isClick = false
button.on('click', () => {
    if (isClick) return
    isClick = true
    // 其他代码。。。
    // 每 10 秒只允许点击一次
    setTimeout(() => {
    isClick = false
    }, 10000)
})

参考资料:

8.如何做到修改url参数页面不刷新

HTML5引入了 history.pushState()history.replaceState() 方法,它们分别可以添加和修改历史记录条目。

let stateObj = {
    foo: "bar",
};

history.pushState(stateObj, "page 2", "bar.html");
复制代码

假设当前页面为 foo.html,执行上述代码后会变为 bar.html,点击浏览器后退,会变为 foo.html,但浏览器并不会刷新。 pushState() 需要三个参数: 一个状态对象, 一个标题 (目前被忽略), 和 (可选的) 一个 URL. 让我们来解释下这三个参数详细内容:

  • 状态对象 — 状态对象 state 是一个 JavaScript 对象,通过 pushState () 创建新的历史记录条目。无论什么时候用户导航到新的状态,popstate 事件就会被触发,且该事件的 state 属性包含该历史记录条目状态对象的副本。

状态对象可以是能被序列化的任何东西。原因在于 Firefox 将状态对象保存在用户的磁盘上,以便在用户重启浏览器时使用,我们规定了状态对象在序列化表示后有640k的大小限制。如果你给 pushState() 方法传了一个序列化后大于 640k 的状态对象,该方法会抛出异常。如果你需要更大的空间,建议使用 sessionStorage 以及 localStorage.

  • 标题 — Firefox 目前忽略这个参数,但未来可能会用到。传递一个空字符串在这里是安全的,而在将来这是不安全的。二选一的话,你可以为跳转的 state 传递一个短标题。

  • URL — 该参数定义了新的历史URL记录。注意,调用 pushState() 后浏览器并不会立即加载这个 URL,但可能会在稍后某些情况下加载这个 URL,比如在用户重新打开浏览器时。新URL不必须为绝对路径。如果新URL是相对路径,那么它将被作为相对于当前 URL 处理。新 URL 必须与当前URL同源,否则 pushState() 会抛出一个异常。该参数是可选的,缺省为当前 URL。

参考资料:

9.请用js去除字符串空格

去除所有空格

str.replace(/\s/g, '')

去除两边空格

str.replace(/^\s+|\s+$/g, '')
// 原生方法
str.trim()

10.创建对象有几种方法

  • 字面量
const obj = {a: 1}
  • 构造函数
function Obj(val) {
    this.a = val
}

const obj = new Obj(1)
  • Object.create
const obj = Object.create({a: 1})

11.null和undefined的区别

null 表示一个对象是“没有值”的值,也就是值为“空”

undefined 表示一个变量声明了没有初始化(赋值)

undefinednull 在if语句中,都会被自动转为false

undefined 不是一个有效的JSON,而 null

undefined 的类型(typeof)是 undefined

null 的类型(typeof)是 object

Javascript将未赋值的变量默认值设为 undefined

Javascript从来不会将变量设为 null。 它是用来让程序员表明某个用var声明的变量时没有值的

12.异步求和

要求

假设有一台本地机器,无法做加减乘除运算,因此无法执行 a + b、a+ = 1 这样的 JS 代码,然后我们提供一个服务器端的 HTTP API,可以传两个数字类型的参数,响应结果是这两个参数的和,这个 HTTP API 的 JS SDK(在本地机器上运行)的使用方法如下:

asyncAdd(3, 5, (err, result) => {
  console.log(result); // 8
});

模拟实现:

function asyncAdd(a, b, cb) {
  setTimeout(() => {
    cb(null, a + b);
  }, Math.floor(Math.random()*100))
}

现在要求在本地机器上实现一个 sum 函数,支持以下用法:

(async () => {
  const result1 = await sum(1, 4, 6, 9, 1, 4);
  const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7);
  const result3 = await sum(1, 6, 0, 5);
  console.log([result1, result2, result3]); // [25, 36, 12]
})();

要求 sum 能在最短的时间里返回以上结果

实现

function asyncAdd(a, b, cb) {
    setTimeout(() => {
        cb(null, a + b);
    }, Math.floor(Math.random()*100))
}

function sum(...args) {
    const result = []
    function _sum(resolve, reject) {
        new Promise((r, j) => {
            let a = args.pop()
            let b = args.pop()
            a = a !== undefined? a : 0
            b = b !== undefined? b : 0 // 如果访问的元素超出了数组范围,则转为 0
            asyncAdd(a, b, (err, res) => {
                if (err) j(err)
                r(res)
            })

            if (args.length) {
                _sum(resolve, reject)
            }
        })
        .then(val => {
            result.push(val)
            setTimeout(() => {
                if (args.length <= 0) {
                    resolve(sum(...result))
                }
            }, 100)
        })
    }

    return new Promise((resolve, reject) => {
        if (!args || !args.length) resolve(0)
        if (args.length == 1) resolve(args[0])
        _sum(resolve, reject)
    })
}

(async () => {
    const result1 = await sum(1, 4, 6, 9, 1, 4)
    const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7)
    const result3 = await sum(1, 6, 0, 5)
    console.log([result1, result2, result3]) // [25, 36, 12]
})()

13.CommonJS,ES module 是什么,有什么区别?

它们都是一种模块规范,例如 Node 使用的就是 CommonJS 规范。ES module 则是语言标准上的模块规范。

区别:

  1. CommonJS 模块使用 require()module.exports,ES6 模块使用 importexport
  2. CommonJS 模块输出的是一个值的浅拷贝,ES6 模块输出的是值的引用。
  3. CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  4. CommonJS 模块的 require() 是同步加载模块,ES6 模块的 import 命令是异步加载,有一个独立的模块依赖的解析阶段。
  5. ES6 模块之中,顶层的 this 指向 undefined;CommonJS 模块的顶层 this 指向当前模块,
  6. 对于循环加载的处理方法不同

第 3 个差异是因为 CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成。

而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

参考资料:

14.preload和prefetch

preload

preload<link> 标签 rel 属性的属性值,同时需要配合 as 属性使用。

as 指定将要预加载的内容的类型,使得浏览器能够:

  1. 更精确地优化资源加载优先级。
  2. 匹配未来的加载需求,在适当的情况下,重复利用同一资源。
  3. 为资源应用正确的内容安全策略。
  4. 为资源设置正确的 Accept 请求头。

看一下这个示例:

<link rel="preload" href="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" as="script">

这种做法将把 <link> 标签塞入一个预加载器中。

这个预加载器在不阻塞页面 onload 事件的情况下,去加载资源。

我们可以通过以下两个示例来作一个对比:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        console.time('load')
    </script>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/2.1.10/chart/bar.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<script>
window.onload = () => {
    console.timeEnd('load') // load: 1449.759033203125ms
}
</script>
</body>
</html>

上面这个示例从加载到触发 onload 事件需要大概 1400 ms 的时间。再看一下使用 preload 预加载的时间:

<link rel="preload" href="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" as="script">
<link rel="preload" href="https://cdn.bootcdn.net/ajax/libs/echarts/2.1.10/chart/bar.js" as="script">
<link rel="preload" href="https://unpkg.com/element-ui/lib/index.js" as="script">
<link rel="preload" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" as="style">

window.onload = () => {
    console.timeEnd('load') // load: 10.8818359375ms
}

用 preload 来加载资源,只需要 10 ms 就触发了 onload 事件。

说明同样是下载文件,使用 preload 不会阻塞 onload 事件。

prefetch

prefetchpreload 不同,使用 prefetch 属性指定的资源将在浏览器空闲时间下下载。

在资源的请求头如果发现有下面这个属性,就代表它是通过 prefetch 加载的:

purpose: prefetch

另外,空闲时间是如何确定、如何获取的,目前还没有相关 API。

15.preload 和 defer 的区别

preload 和 defer 的相同点是异步下载。那它们的不同点是什么呢?

preload 下载的资源只有在遇到同样的 script 标签时,才会执行对应的脚本。例如下面预加载的 vue.js

<link rel="preload" as="script" href="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">

只有在遇到下面的标签时,才会执行加载的 vue.js

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

defer 则是异步下载资源,在所有元素解析完成后,触发 DOMContentLoaded 事件前执行。

16.window.onload 和 DOMContentLoaded 的区别

当整个页面及所有依赖资源如样式表和图片都已完成加载时,将触发load事件。

它与 DOMContentLoaded不同,当纯HTML被完全加载以及解析时,DOMContentLoaded 事件会被触发,而不必等待样式表,图片或者子框架完成加载。

17.Object 与 Map 的区别

  1. Object 只能选择字符、数值、符号作为 key,Map 则可以使用任何类型的数据作为 key。
  2. Map 实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。Chrome Opera 中使用 for-in 语句遍历 Object 属性时会遵循一个规律:它们会先提取所有 key 的 parseFloat 值为非负整数的属性,然后根据数字顺序对属性排序首先遍历出来,然后按照对象定义的顺序遍历余下的所有属性。其它浏览器则完全按照对象定义的顺序遍历属性。

选择 Object 还是 Map

对于多数Web开发任务来说,选择 Object 还是 Map 只是个人偏好问题,影响不大。不过,对于在乎内存和性能的开发者来说,对象和映射之间确实存在显著的差别。

1. 内存占用

Object 和 Map 的工程级实现在不同浏览器间存在明显差异,但存储单个键/值对所占用的内存数量都会随键的数量线性增加。批量添加或删除键/值对则取决于各浏览器对该类型内存分配的工程实现。

不同浏览器的情况不同,但给定固定大小的内存, Map 大约可以比 Object 多存储50%的键/值对。

2. 插入性能

向 Object 和 Map 中插入新键/值对的消耗大致相当,不过插入Map 在所有浏览器中一般会稍微快一点儿。对这两个类型来说,插入速度并不会随着键/值对数量而线性增加。

如果代码涉及大量插入操作,那么显然 Map 的性能更佳。

3. 查找速度

与插入不同,从大型 Object 和 Map 中查找键/值对的性能差异极小,但如果只包含少量键/值对,则 Object 有时候速度更快。在把 Object 当成数组使用的情况下(比如使用连续整数作为属性),浏览器引擎可以进行优化,在内存中使用更高效的布局。

这对 Map 来说是不可能的。对这两个类型而言,查找速度不会随着键/值对数量增加而线性增加。如果代码涉及大量查找操作,那么某些情况下可能选择 Object 更好一些。

4. 删除性能

使用 delete 删除 Object 属性的性能一直以来饱受诟病,目前在很多浏览器中仍然如此。为此,出现了一些伪删除对象属性的操作,包括把属性值设置为 undefined 或 null 。但很多时候,这都是一 种讨厌的或不适宜的折中。

而对大多数浏览器引擎来说, Map 的 delete() 操作都比插入和查找更快。如果代码涉及大量删除操作,那么毫无疑问应该选择 Map 。

参考资料:

18.为什么 WeakMap 和 WeakSet 的键只能使用对象?

是为了保证只有通过键对象的引用来取得值。

const m = new WeakMap()
m.set({}, 100) // 由于 {} 没有在其他地方引用,所以在垃圾回收时,这个值也会被回收。

const a = {}
m.set(a, 100) // 如果使用这种方式,则不会被回收。因为 {} 有 a 变量在引用它。

a = null // 将 a 置为空后,m 里的值 100 在垃圾回收时将会被回收。

如果允许原始值,那就没办法区分初始化时使用的字符串字面量和初始化之后使用的一个相等的字符串了。

所以这句话的意思很明确:

const a = {} // 在创建对象时,分配了一块内存,并把这块内存的地址传给 a 
m.set(a, 100) // 执行 set 操作时,实际上是将 a 指向的内存地址和 100 关联起来

const a = 'abc' // 由于基本数据类型在传递时,传递的是值,而不是引用。
m.set(a, 100) // 所以执行 set 操作时,实际上是将新的 'abc' 和 100 关联起来,而不是原来 a 变量指向的那个。
          // 那这样就会有问题,m 里存储的永远是没有被引用的键,随时都会被回收。

参考资料:

HTML

19.HTML5语义化

什么是语义化?就是用合理、正确的标签来展示内容,比如h1~h6定义标题。

好处

  • 易于用户阅读,样式丢失的时候能让页面呈现清晰的结构。
  • 有利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重。
  • 方便其他设备解析,如盲人阅读器根据语义渲染网页
  • 有利于开发和维护,语义化更具可读性,代码更好维护,与CSS3关系更和谐。

20.为什么最好把 CSS 的<link>标签放在<head></head>之间?为什么最好把 JS 的<script>标签恰好放在</body>之前,有例外情况吗?

<link>放在<head>

这种做法可以让页面逐步呈现,提高了用户体验。将样式表放在文档底部附近,会使许多浏览器(包括 Internet Explorer)不能逐步呈现页面。一些浏览器会阻止渲染,以避免在页面样式发生变化时,重新绘制页面中的元素。这种做法可以防止呈现给用户空白的页面或没有样式的内容。

<script>标签恰好放在</body>之前

脚本在下载和执行期间会阻止 HTML 解析。把<script>标签放在底部,保证 HTML 首先完成解析,将页面尽早呈现给用户。

如果一定要放在 <head> 中,可以让 <script> 标签使用 defer 属性。

21.什么是渐进式渲染(progressive rendering)?

渐进式渲染是用于提高网页性能(尤其是提高用户感知的加载速度),以尽快呈现页面的技术。

在以前互联网带宽较小的时期,这种技术更为普遍。如今,移动终端的盛行,而移动网络往往不稳定,渐进式渲染在现代前端开发中仍然有用武之地。

一些举例:

  • 图片懒加载——页面上的图片不会一次性全部加载。当用户滚动页面到图片部分时,JavaScript 将加载并显示图像。
  • 确定显示内容的优先级(分层次渲染)——为了尽快将页面呈现给用户,页面只包含基本的最少量的 CSS、脚本和内容,然后可以使用延迟加载脚本或监听DOMContentLoaded/load事件加载其他资源和内容。
  • 异步加载 HTML 片段——当页面通过后台渲染时,把 HTML 拆分,通过异步请求,分块发送给浏览器。更多相关细节可以在这里找到。

22.. viewport

Viewport :字面意思为视图窗口,在移动web开发中使用。表示将设备浏览器宽度虚拟成一个特定的值(或计算得出),这样利于移动web站点跨设备显示效果基本一致。移动版的 Safari 浏览器最新引进了 viewport 这个 meta tag,让网页开发者来控制 viewport 的大小和缩放,其他手机浏览器也基本支持。

在移动端浏览器当中,存在着两种视口,一种是可见视口(也就是我们说的设备大小),另一种是视窗视口(网页的宽度是多少)。 举个例子:如果我们的屏幕是320像素 * 480像素的大小(iPhone4),假设在浏览器中,320像素的屏幕宽度能够展示980像素宽度的内容。那么320像素的宽度就是可见视口的宽度,而能够显示的980像素的宽度就是视窗视口的宽度。

为了显示更多的内容,大多数的浏览器会把自己的视窗视口扩大,简易的理解,就是让原本320像素的屏幕宽度能够容下980像素甚至更宽的内容(将网页等比例缩小)。

Viewport属性值

  • width 设置layout viewport 的宽度,为一个正整数,或字符串"width-device"
  • initial-scale 设置页面的初始缩放值,为一个数字,可以带小数
  • minimum-scale 允许用户的最小缩放值,为一个数字,可以带小数
  • maximum-scale 允许用户的最大缩放值,为一个数字,可以带小数
  • height 设置layout viewport 的高度,这个属性对我们并不重要,很少使用
  • user-scalable 是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes代表允许这些属性可以同时使用,也可以单独使用或混合使用,多个属性同时使用时用逗号隔开就行了。

23.Reflow和Repaint

Reflow

当涉及到DOM节点的布局属性发生变化时,就会重新计算该属性,浏览器会重新描绘相应的元素,此过程叫Reflow(回流或重排)。

Repaint

当影响DOM元素可见性的属性发生变化 (如 color) 时, 浏览器会重新描绘相应的元素, 此过程称为Repaint(重绘)。因此重排必然会引起重绘。

引起Repaint和Reflow的一些操作

  • 调整窗口大小
  • 字体大小
  • 样式表变动
  • 元素内容变化,尤其是输入控件
  • CSS伪类激活,在用户交互过程中发生
  • DOM操作,DOM元素增删、修改
  • width, clientWidth, scrollTop等布局宽高的计算

Repaint和Reflow是不可避免的,只能说对性能的影响减到最小,给出下面几条建议:

  • 避免逐条更改样式。建议集中修改样式,例如操作className。
  • 避免频繁操作DOM。创建一个documentFragment或div,在它上面应用所有DOM操作,最后添加到文档里。设置display:none的元素上操作,最后显示出来。
  • 避免频繁读取元素几何属性(例如scrollTop)。绝对定位具有复杂动画的元素。
  • 绝对定位使它脱离文档流,避免引起父元素及后续元素大量的回流

参考资料:

24. img中的alt和元素的title属性作用

  • img的alt属性

如果无法显示图像,浏览器将显示alt指定的内容

  • 元素title属性

在鼠标移到元素上时显示title的内容

25.href和src区别

href

href标识超文本引用,用在link和a等元素上,href是引用和页面关联,是在当前元素和引用资源之间建立联系
若在文档中添加href ,浏览器会识别该文档为 CSS 文件,就会并行下载资源并且不会停止对当前文档的处理。这也是为什么建议使用 link 方式加载 CSS,而不是使用 @import 方式。

src

src表示引用资源,替换当前元素,用在img,script,iframe上,src是页面内容不可缺少的一部分。
当浏览器解析到src ,会暂停其他资源的下载和处理(图片不会暂停其他资源下载和处理),直到将该资源加载、编译、执行完毕,图片和框架等也如此,类似于将所指向资源应用到当前内容。这也是为什么建议把 js 脚本放在底部而不是头部的原因。

参考资料:

25.浏览器的渲染过程

  1. 解析HTML生成DOM树。
  2. 解析CSS生成CSSOM规则树。
  3. 将DOM树与CSSOM规则树合并在一起生成渲染树。
  4. 遍历渲染树开始布局,计算每个节点的位置大小信息。
  5. 调用 GPU 绘制,合成图层。
  6. 将渲染树每个节点绘制到屏幕。

26.为何会出现浏览器兼容问题

  • 同一产品,版本越老 bug 越多
  • 同一产品,版本越新,功能越多
  • 不同产品,不同标准,不同实现方式

处理兼容问题的思路

  1. 要不要做
  • 产品的角度(产品的受众、受众的浏览器比例、效果优先还是基本功能优先)
  • 成本的角度 (有无必要做某件事)

2.做到什么程度

  • 让哪些浏览器支持哪些效果

3..如何做

  • 根据兼容需求选择技术框架/库(jquery)

  • 根据兼容需求选择兼容工具(html5shiv.js、respond.js、css reset、normalize.css、Modernizr)

  • 条件注释、CSS Hack、js 能力检测做一些修补

  • 渐进增强(progressive enhancement): 针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验

  • 优雅降级 (graceful degradation): 一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。

参考资料:

27.doctype有什么用

doctype是一种标准通用标记语言的文档类型声明,目的是告诉标准通用标记语言解析器要使用什么样的文档类型定义(DTD)来解析文档。

声明是用来指示web浏览器关于页面使用哪个HTML版本进行编写的指令。 声明必须是HTML文档的第一行,位于html标签之前。

浏览器本身分为两种模式,一种是标准模式,一种是怪异模式。

浏览器通过doctype来区分这两种模式,doctype在html中的作用就是触发浏览器的标准模式,如果html中省略了doctype,浏览器就会进入到Quirks模式的怪异状态。

在这种模式下,有些样式会和标准模式存在差异。

而html标准和dom标准值规定了标准模式下的行为,没有对怪异模式做出规定,因此不同浏览器在怪异模式下的处理也是不同的,所以一定要在html开头使用doctype。

28.行内元素和块级元素有哪些

行内元素

一个行内元素只占据它对应标签的边框所包含的空间
一般情况下,行内元素只能包含数据和其他行内元素

b, big, i, small, tt
abbr, acronym, cite, code, dfn, em, kbd, strong, samp, var
a, bdo, br, img, map, object, q, script, span, sub, sup
button, input, label, select, textarea

块级元素

占据一整行,高度、行高、内边距和外边距都可以改变,可以容纳块级标签和其他行内标签

header,form,ul,ol,table,article,div,hr,aside,figure,canvas,video,audio,footer

29.行内元素、块级元素区别

行内元素:和其他元素都在一行上,高度、行高及外边距和内边距都不可改变(边距上下方向不可改变,左右方向可以改变),文字图片的宽度不可改变,只能容纳文本或者其他行内元素;其中img是行元素

块级元素:总是在新行上开始,高度、行高及外边距和内边距都可控制,可以容纳内敛元素和其他元素;行元素转换为块级元素方式:display:block;

30. iframe框架有那些优缺点

优点:

  • iframe能够原封不动的把嵌入的网页展现出来。
  • 如果有多个网页引用iframe,那么你只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷。
  • 网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用。
  • 如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决。

缺点:

  • 搜索引擎的爬虫程序无法解读这种页面
  • 框架结构中出现各种滚动条
  • 使用框架结构时,保证设置正确的导航链接。
  • iframe页面会增加服务器的http请求

31. label标签有什么作用

label 标签通常是写在表单内,它关联一个控件,使用 label 可以实现点击文字选取对应的控件。

<input type="checkbox" id="test">
<label for="test" >test</label>

32.HTML5的form如何关闭自动完成功能

将不想要自动完成的 forminput 设置为 autocomplete=off

33. DOM和BOM有什么区别

DOM

Document Object Model,文档对象模型

DOM 是为了操作文档出现的 API,document 是其的一个对象

DOM和文档有关,这里的文档指的是网页,也就是html文档。DOM和浏览器无关,他关注的是网页本身的内容。

BOM

Browser Object Model,浏览器对象模型

BOM 是为了操作浏览器出现的 API,window 是其的一个对象

我平时一直有整理面试题的习惯,有随时跳出舒适圈的准备,不知不觉整理了229页了,在这里分享给大家,有需要的点击这里免费领取题目+解析PDF

篇幅有限,仅展示部分内容

如果你需要这份完整版的面试题+解析,【点击我】就可以了。

希望大家明年的金三银四面试顺利,拿下自己心仪的offer!

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):