30秒系列之面试

容易

图片标签 imgalt 属性有什么用?

当图片加载失败没法看到时,页面会显示alt 属性提供的信息。alt 属性是用于描述图片信息的,那些装饰性的图片除外,这些图片的 alt 信息应该置空。css

善意:html

  • 修饰性的图片的alt应该为 ''
  • Web crawlers网络爬虫使用 alt 标签识别图片内容,所以这些属性对 Search Engine Optimization (SEO) 搜索引擎优化很重要
  • alt 标签后加. 提升可访问性

CSS BEM 是什么?

BEM 方法是CSS类名的命名约定,目的是经过定义命名空间,使 CSS 更易于维护,解决类(class)的范围问题 。BEMBlock Element Modifier —— 块元素修饰符Block 是一个独立的部分,它能够在项目里重复利用并为子元素(Element)充当命名空间。当一个块或元素在某个状态或者结构样式不一样时,Modifier能够用做标识符区别这些状态或差别。数据库

/* block component */
.block {
}

/* element */
.block__element {
}

/* modifier */
.block__element--modifier {
}

这是一个类名标记的例子:编程

<nav class="navbar">
  <a href="/" class="navbar__link navbar__link--active"></a>
  <a href="/" class="navbar__link"></a>
  <a href="/" class="navbar__link"></a>
</nav>

在上例中,navbarBlocknavbar__link 元素 除了是 navbar 组件外没任何意义, navbar__link--active 是一个修饰符, 表示 navbar————link 元素的一种不一样的状态。数组

因为修饰符过于冗长,更多状况下是使用 is-* 标识promise

<a href="/" class="navbar__link is-active"></a>

这些必须与元素连接不能独立使用,不然就会有范围问题。浏览器

.navbar__link.is-active {
}

善意:缓存

  • 另外一个解决范围问题的方案是 CSS-in-JS
范围问题: CSS只有一个全局命名空间。 在非平凡的应用程序中不可能避免选择器冲突。

cache busting 的用途以及如何实现

cache busting ——我暂时不知道如何翻译,大体就是解决缓存文件不刷新问题服务器

浏览器有一个缓存机制来临时存储网站上的文件,因此在页面之间切换或从新加载相同的页面时,这些文件不须要被从新下载。服务器被设置为发送报头,报头告诉浏览器在给定的时间内存储文件。这大大提升了网站的速度,并保持了带宽。网络

可是,当开发人员更改了网站,由于用户的缓存仍然引用旧文件,这可能会致使问题。若是缓存的CSS和JavaScript文件引用的元素已不复存在、已移动或已重命名,则会使它们保留原有功能,或破坏网站。

cache busting是一种强制浏览器下载新文件的方式,经过将文件命名为与旧文件不一样的名称来实现。

有一种强制浏览器从新下载文件的常见的方式是在文件名称末尾添加一个索引字符串

src="js/script.js" => src="js/script.js?v=2"

这种方式浏览器会将它视做不一样的文件,而且不用重命名文件。

CSS 预处理器的好处是什么?

CSS预处理程序添加了本地CSS没有的有用功能,一般经过启用DRY(不要重复)原则使CSS更整洁、更易于维护。它们用于嵌套选择器的简洁语法减小了重复代码。它们为一致的主题化提供了变量(然而,CSS变量已经在很大程度上取代了这个功能),并提供了额外的工具,如color函数(变亮、变暗、透明等)、mixin和循环,这些工具使CSS更像一种真正的编程语言,并使开发人员有更多的能力生成复杂的CSS。

善意:

  • 容许咱们书写更易于维护和扩展的css代码
  • 一些使用CSS预处理器的缺点: 安装,从新编译耗时等

===== 的区别

(===)检查严格的相等性,这意味着类型和值必须相同。另外一方面,(==)首先执行类型强制转换,使两个操做数具备相同的类型,而后应用严格的比较。

善意:

  • 只要可能,使用===来测试等式,由于松散等式==可能会获得不直观的结果。
  • 类型强制转换表示将值转换为相同的类型。
  • 假值以及这些值的比较。

使用弹性盒子模型建立一个三列布局,每一列占据容器col-{n} / 12的比例

<div class="row">
  <div class="col-2"></div>
  <div class="col-7"></div>
  <div class="col-3"></div>
</div>

设置 .row的父元素display: flex;使用flex的 简写属性 给列类设置一个 与它的比例对应的 flex-grow

.row {
  display: flex;
}

.col-2 {
  flex: 2;
}

.col-7 {
  flex: 7;
}

.col-3 {
  flex: 3;
}

网页能包含多个 <header>元素么? <footer>呢?

二者均可以。W3文档声明标记表示其最近祖先“部分”的页眉(<header>)和页脚(<footer>)区域。所以,不只页面<body>能够包含页眉和页脚,并且每一个<article><section>元素也能够包含页眉和页脚。

善意:

  • W3建议你想要多少就有多少,可是对于你页面的每个“部分”,好比正文、部分等,每一个部分只能有一个。

简要描述如下HTML5语义元素的正确用法:<header><article><section><footer>

  • <header>用于包含关于页面某个部分的介绍和导航信息。这能够包括章节标题、做者姓名、出版时间和日期、目录或其余导航信息。
  • <article>是一个自包含的组合,逻辑上能够在页面以外独立地从新建立,而不会失去它的意义。我的博客文章或新闻故事就是很好的例子。
  • <section>是一个灵活的容器,用于保存具备相同信息主题或目的的内容。
  • <footer>用于保存应该出如今内容部分末尾的信息,并包含关于该部分的附加信息。做者姓名、版权信息和相关连接就是此类内容的典型例子。

善意:

  • 其余语义元素是<form><table>

你能说出 @media 属性的四种类型吗?

  • all 适用于全部媒体类型的设备
  • print 它只适用于打印机
  • screen 仅适用于屏幕(台式机、平板电脑、手机等)
  • speech 这只适用于屏幕阅读器

中级

值比较(下列代码输出?)

const a = [1, 2, 3]
const b = [1, 2, 3]
const c = "1,2,3"

console.log(a == c)
console.log(a == b)

第一个console.log输出true,由于JavaScript的编译器执行类型转换,所以它根据字符串的值与字符串进行比较。另外一方面,第二个console.log输出false,由于数组是对象,对象经过引用进行比较(比较的是内存地址)。

善意之言:

  • JavaScript执行自动类型转换
  • 经过引用来比较对象
  • 按值比较基本类型(null, undefined, number, string, boolean)数据的值

rel="noopener"的使用情景和使用目的

rel="noopener"<a>元素(超连接)中使用的一个属性。它防止页面拥有window.opener属性,这个属性指向原来的的页面,并容许从超连接打开的页面操做超连接所在的页面,即新打开的页面控制原来跳转页。务必在target='_blank'后加上此属性,兼容火狐写法rel="noopener norefferrer"

善意之言

  • rel=“noopener”应用于超连接。
  • rel="noopener"防止打开的连接操做源页面。

JavaScript 的自动分号插入(ASI)

下列代码输出什么?

function greet() {
  return
  {
    message: "hello"
  }
}
undefined

因为 JavaScript的自动分号插入机制 automatic semicolon insertion (ASI), 编译器在return关键字后放置分号,所以它返回undefined,不会抛出错误。

善意之言:

  • 自动分号插入机制会致使一些耗时难缠的bug

nullundefined之间的区别是什么?

JavaScript中,两个值分别表示——undefinednull。它们之间的具体区别是null是显式的,而undefined是隐式的。当属性不存在或变量没有被赋予值时,该值是undefined。设置值null是显式地指示“no value”。在本质上,undefined用于未知的状况,null用于已知的状况。也就是说,变量只声明不知道它指代什么时,也就是说它是未知的,是undefined,若变量已知,但在一些时候是没有内容的,则用null赋值

善意之言:

  • typeof undefined的值为“undefined”
  • typeof null计算“object”。然而,它仍然是一个原始值,这在JavaScript中被认为是一个实现错误。
  • undefined == null的值为true。

MIME类型是什么?它的用途是什么?

MIMEMulti-purpose Internet Mail Extensions的缩写。它是用做在Internet上对文件类型进行分类的标准方法。

善意之言:

  • MIME type实际上有两个部分:一个类型和一个用斜杠(/)分隔的子类型。例如,Microsoft Word文件的MIME类型是application/msword(类型为application,子类型为msword)。

typeof 的运算结果

求下列代码的值

typeof typeof 0

输出: "string"

先获得 0的类型"number", 而后 typeof "number" 得出 "string"

typeof 操做符返回一个 字符串表示未鉴定的操做数的类型

JavaScript 的数据类型

最新的 ECMAScript 标准定义了种数据类型,六种基本/原始数据类型:Boolean, Null, Undefined, Number, String, Symbol ,以及一种非原始数据类型: Object.

对以上数据类型使用 typeof(结果都是小写): boolean, object, undefined, number, string, symbol, object

善意之言

  • 新补充的基本数据类型 Symbol
  • Array, Date and Function 都是 object 对象类型(typeof 函数的出来function)
  • JavaScript中的函数是能被调用的对象
判断类型:
object instanceof constructor
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

参数parameterarguments 的区别

参数Parameter 是函数定义时形参的变量名,而arguments 是函数调用时给定的值

function myFunction(parameter1, parameter2) {
  console.log(arguments[0]) // "argument1"
}
myFunction("argument1", "argument2")

友情提示

  • arguments 是一个类数组对象,包含了函数触发调用时获得的参数信息
  • myFunction.length 只表示函数的参数数量(本例中为2),不管函数调用时传入多少参数

示例以下

function myFunction(parameter1, parameter2) {
   console.log(myFunction.length) //2
   console.log(arguments[2]) // "3"  这里虽然函数只接受两个参数,但调用时传了多的两个`3,4`在arguments中也取到了
}
console.log(myFunction.length) // 2
myFunction("argument1", "argument2", 3, 4)

建立一个函数,使用指定符号maskCahr屏蔽除最后count为以外的字符

mask("123456789") // "#####6789"

有不少方法解决:

使用 String.prototype.slice() 传入参数-4 获取字符串最后 4 位字符 ,而后用 String.prototype.padStart() 传入字符串长度和 替换符号 把字符串用 指定符号填充至 指定长度.

const mask = (str, maskChar = "#") =>
  str.slice(-4).padStart(str.length, maskChar)

善意之言

  • 若是问题的解决方案是有效的,那么应该首选简短、单行的功能性解决方案

困难

递归recursion 是什么 ? 何时用?

递归是一个过程的重复应用。在JavaScript中,递归涉及不断调用自身的函数,直到它们达到一个基本条件。基本条件打破递归循环,不然函数将无限递归循环下去。当处理嵌套若干层的数据时递归很是有用。

例如,有一个数据库返回的一系列评论,它存在于一个平面数组中,可是须要嵌套以在UI中显示。每一个注释要么是顶级注释(没有父注释),要么是对父注释的回复。评论能够是回复的回复,回复的回复…咱们事先不知道一个评论可能有多少层深度。这就是递归能够提供帮助的地方。

const nest = (items, id = null, link = "parent_id") =>
  items
    .filter(item => item[link] === id)
    .map(item => ({ ...item, children: nest(items, item.id) }))

const comments = [
  { id: 1, parent_id: null, text: "First reply to post." },
  { id: 2, parent_id: 1, text: "First reply to comment #1." },
  { id: 3, parent_id: 1, text: "Second reply to comment #1." },
  { id: 4, parent_id: 3, text: "First reply to comment #3." },
  { id: 5, parent_id: 4, text: "First reply to comment #4." },
  { id: 6, parent_id: null, text: "Second reply to post." }
]

nest(comments)
/*
[
  { id: 1, parent_id: null, text: "First reply to post.", children: [...] },
  { id: 6, parent_id: null, text: "Second reply to post.", children: [] }
]
*/

在上例中,基础条件是filter()返回空数组。链式的map() 不会触发递归调用的回调函数,进而跳出递归循环。

善意提醒:

  • 递归在处理包含未知层数的结构的数据时很是有用
  • 递归必须有一个跳出递归循环避免无限回调的基本条件

JavaScript中惟一不等于自身的值是什么?

当与任何比较运算符比较时,NaN (not -a- number) 是惟一不等于自身的值。NaN一般是没有意义的数学计算的结果,因此两个NaN值被认为相等没有意义。

善意提醒

  • isNaN()Number.isNaN()的区别

    //isNaN
                console.log(isNaN(null));            //false
                console.log(isNaN(true));            //false
                console.log(isNaN(false));           //false
                console.log(isNaN(0));               //false
                console.log(isNaN(undefined));       //true
                console.log(isNaN("AB"));            //true
                console.log(isNaN({a: 1}));          //true
                console.log(isNaN(NaN));             //true
                
                //Number.isNaN
                console.log(Number.isNaN(null));      //false
                console.log(Number.isNaN(true));      //false
                console.log(Number.isNaN(false));     //false
                console.log(Number.isNaN(0));         //false
                console.log(Number.isNaN(undefined)); //false
                console.log(Number.isNaN("AB"));      //false
                console.log(Number.isNaN({a: 1}));    //false
                console.log(Number.isNaN(NaN));       //true
  • const isNaN = x => x !== x

Node.js中的事件循环是什么?

事件循环处理全部异步回调。回调将在循环中排队,而其余代码将运行,并将在收到每一个代码的响应后逐个运行。

善意提醒

  • 事件循环容许Node.js执行非阻塞I/O操做,尽管JavaScript是单线程的

如何避免回调地狱?

getData(function(a) {
  getMoreData(a, function(b) {
    getMoreData(b, function(c) {
      getMoreData(c, function(d) {
        getMoreData(d, function(e) {
          // ...
        })
      })
    })
  })
})

重构使用返回promise或者使用 async/await的函数一般是最好的选择。 它们没有为函数提供致使深度嵌套的回调,而是返回一个能够等待的promise,而且在数据到达后将被解析,从而容许以相似于同步的方式计算下一行代码。

以上代码能够被重构成这样:

async function asyncAwaitVersion() {
  const a = await getData()
  const b = await getMoreData(a)
  const c = await getMoreData(b)
  const d = await getMoreData(c)
  const e = await getMoreData(d)
  // ...
}

有许多方式解决回调地狱的问题:

  • 模块化: 把回调分解成独立的函数
  • 使用控制流库,好比async
  • 使用Promise的生成器
  • 使用async/await (>es7)

善意提醒

  • 做为一个高效的JavaScript开发人员,您必须避免不断增加的缩进级别,生成干净且可读的代码,并可以处理复杂的流。

什么是闭包?你能举一个有用的例子吗?

闭包是在另外一个函数中定义的函数,即便在其词法做用域以外执行,也能够访问其词法做用域。

闭包能够访问三个范围内的变量:

  • 在它本身的做用域中声明的变量
  • 在父函数范围内声明的变量
  • 在全局范围中声明的变量

JavaScript中,全部函数都是闭包,由于它们能够访问外部范围,可是大多数函数没有利用闭包的有用性:状态的持久性。闭包有时也所以被称为有状态函数
此外,闭包是存储没法从JavaScript外部访问的私有数据的惟一方法。它们是UMD (Universal Module Definition)模式的关键,UMD模式常常用于只公开公共API但保持实现细节私有的库中,以防止与其余库或用户本身的代码发生名称冲突。

友情提醒:

  • 闭包很是有用,由于它们容许您将数据与操做该数据的函数关联起来。
  • 闭包只能用一个方法替换对象。
  • 闭包能够用来模拟私有属性和方法。
MDN的闭包解释,也很清晰
相关文章
相关标签/搜索