关于javascript:这样回答前端面试题才能拿到offer

2次阅读

共计 9785 个字符,预计需要花费 25 分钟才能阅读完成。

代码输入后果

function runAsync (x) {const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))
  return p
}
function runReject (x) {const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x))
  return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
       .then(res => console.log(res))
       .catch(err => console.log(err))

输入后果如下:

// 1s 后输入
1
3
// 2s 后输入
2
Error: 2
// 4s 后输入
4

能够看到。catch 捕捉到了第一个谬误,在这道题目中最先的谬误就是 runReject(2) 的后果。如果一组异步操作中有一个异样都不会进入 .then() 的第一个回调函数参数中。会被 .then() 的第二个回调函数捕捉。

首屏和白屏工夫如何计算

首屏工夫的计算,能够由 Native WebView 提供的相似 onload 的办法实现,在 ios 下对应的是 webViewDidFinishLoad,在 android 下对应的是 onPageFinished 事件。

白屏的定义有多种。能够认为“没有任何内容”是白屏,能够认为“网络或服务异样”是白屏,能够认为“数据加载中”是白屏,能够认为“图片加载不进去”是白屏。场景不同,白屏的计算形式就不雷同。

办法 1:当页面的元素数小于 x 时,则认为页面白屏。比方“没有任何内容”,能够获取页面的 DOM 节点数,判断 DOM 节点数少于某个阈值 X,则认为白屏。办法 2:当页面呈现业务定义的错误码时,则认为是白屏。比方“网络或服务异样”。办法 3:当页面呈现业务定义的特征值时,则认为是白屏。比方“数据加载中”。

浏览器渲染优化

(1)针对 JavaScript: JavaScript 既会阻塞 HTML 的解析,也会阻塞 CSS 的解析。因而咱们能够对 JavaScript 的加载形式进行扭转,来进行优化:

(1)尽量将 JavaScript 文件放在 body 的最初

(2)body 两头尽量不要写 <script> 标签

(3)<script>标签的引入资源形式有三种,有一种就是咱们罕用的间接引入,还有两种就是应用 async 属性和 defer 属性来异步引入,两者都是去异步加载内部的 JS 文件,不会阻塞 DOM 的解析(尽量应用异步加载)。三者的区别如下:

  • script 立刻进行页面渲染去加载资源文件,当资源加载结束后立刻执行 js 代码,js 代码执行结束后持续渲染页面;
  • async 是在下载实现之后,立刻异步加载,加载好后立刻执行,多个带 async 属性的标签,不能保障加载的程序;
  • defer 是在下载实现之后,立刻异步加载。加载好后,如果 DOM 树还没构建好,则先等 DOM 树解析好再执行;如果 DOM 树曾经筹备好,则立刻执行。多个带 defer 属性的标签,依照程序执行。

(2)针对 CSS:应用 CSS 有三种形式:应用link、@import、内联款式,其中 link 和 @import 都是导入内部款式。它们之间的区别:

  • link:浏览器会派发一个新等线程 (HTTP 线程) 去加载资源文件,与此同时 GUI 渲染线程会持续向下渲染代码
  • @import:GUI 渲染线程会临时进行渲染,去服务器加载资源文件,资源文件没有返回之前不会持续渲染(妨碍浏览器渲染)
  • style:GUI 间接渲染

内部款式如果长时间没有加载结束,浏览器为了用户体验,会应用浏览器会默认款式,确保首次渲染的速度。所以 CSS 个别写在 headr 中,让浏览器尽快发送申请去获取 css 款式。

所以,在开发过程中,导入内部款式应用 link,而不必 @import。如果 css 少,尽可能采纳内嵌款式,间接写在 style 标签中。

(3)针对 DOM 树、CSSOM 树: 能够通过以下几种形式来缩小渲染的工夫:

  • HTML 文件的代码层级尽量不要太深
  • 应用语义化的标签,来防止不规范语义化的非凡解决
  • 缩小 CSSD 代码的层级,因为选择器是从左向右进行解析的

(4)缩小回流与重绘:

  • 操作 DOM 时,尽量在低层级的 DOM 节点进行操作
  • 不要应用 table 布局,一个小的改变可能会使整个 table 进行从新布局
  • 应用 CSS 的表达式
  • 不要频繁操作元素的款式,对于动态页面,能够批改类名,而不是款式。
  • 应用 absolute 或者 fixed,使元素脱离文档流,这样他们发生变化就不会影响其余元素
  • 防止频繁操作 DOM,能够创立一个文档片段documentFragment,在它下面利用所有 DOM 操作,最初再把它增加到文档中
  • 将元素先设置display: none,操作完结后再把它显示进去。因为在 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘。
  • 将 DOM 的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写。这得益于 浏览器的渲染队列机制

浏览器针对页面的回流与重绘,进行了本身的优化——渲染队列

浏览器会将所有的回流、重绘的操作放在一个队列中,当队列中的操作到了肯定的数量或者到了肯定的工夫距离,浏览器就会对队列进行批处理。这样就会让屡次的回流、重绘变成一次回流重绘。

将多个读操作(或者写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,本来应该是触发屡次回流,变成了只触发一次回流。

异步编程的实现形式?

JavaScript 中的异步机制能够分为以下几种:

  • 回调函数 的形式,应用回调函数的形式有一个毛病是,多个回调函数嵌套的时候会造成回调函数天堂,高低两层的回调函数间的代码耦合度太高,不利于代码的可保护。
  • Promise 的形式,应用 Promise 的形式能够将嵌套的回调函数作为链式调用。然而应用这种办法,有时会造成多个 then 的链式调用,可能会造成代码的语义不够明确。
  • generator 的形式,它能够在函数的执行过程中,将函数的执行权转移进来,在函数内部还能够将执行权转移回来。当遇到异步函数执行的时候,将函数执行权转移进来,当异步函数执行结束时再将执行权给转移回来。因而在 generator 外部对于异步操作的形式,能够以同步的程序来书写。应用这种形式须要思考的问题是何时将函数的控制权转移回来,因而须要有一个主动执行 generator 的机制,比如说 co 模块等形式来实现 generator 的主动执行。
  • async 函数 的形式,async 函数是 generator 和 promise 实现的一个主动执行的语法糖,它外部自带执行器,当函数外部执行到一个 await 语句的时候,如果语句返回一个 promise 对象,那么函数将会期待 promise 对象的状态变为 resolve 后再持续向下执行。因而能够将异步逻辑,转化为同步的程序来书写,并且这个函数能够主动执行。

null 和 undefined 区别

首先 Undefined 和 Null 都是根本数据类型,这两个根本数据类型别离都只有一个值,就是 undefined 和 null。

undefined 代表的含意是 未定义 ,null 代表的含意是 空对象。个别变量申明了但还没有定义的时候会返回 undefined,null 次要用于赋值给一些可能会返回对象的变量,作为初始化。

undefined 在 JavaScript 中不是一个保留字,这意味着能够应用 undefined 来作为一个变量名,然而这样的做法是十分危险的,它会影响对 undefined 值的判断。咱们能够通过一些办法取得平安的 undefined 值,比如说 void 0。

当对这两种类型应用 typeof 进行判断时,Null 类型化会返回“object”,这是一个历史遗留的问题。当应用双等号对两种类型的值进行比拟时会返回 true,应用三个等号时会返回 false。

position 的属性有哪些,区别是什么

position 有以下属性值:

属性值 概述
absolute 生成相对定位的元素,绝对于 static 定位以外的一个父元素进行定位。元素的地位通过 left、top、right、bottom 属性进行规定。
relative 生成绝对定位的元素,绝对于其原来的地位进行定位。元素的地位通过 left、top、right、bottom 属性进行规定。
fixed 生成相对定位的元素,指定元素绝对于屏幕视⼝(viewport)的地位来指定元素地位。元素的地位在屏幕滚动时不会扭转,⽐如回到顶部的按钮⼀般都是⽤此定位⽅式。
static 默认值,没有定位,元素呈现在失常的文档流中,会疏忽 top, bottom, left, right 或者 z-index 申明,块级元素从上往下纵向排布,⾏级元素从左向右排列。
inherit 规定从父元素继承 position 属性的值

后面三者的定位形式如下:

  • relative: 元素的定位永远是绝对于元素本身地位的,和其余元素没关系,也不会影响其余元素。
  • fixed: 元素的定位是绝对于 window(或者 iframe)边界的,和其余元素没有关系。然而它具备破坏性,会导致其余元素地位的变动。
  • absolute: 元素的定位绝对于前两者要简单许多。如果为 absolute 设置了 top、left,浏览器会依据什么去确定它的纵向和横向的偏移量呢?答案是浏览器会递归查找该元素的所有父元素,如果找到一个设置了 position:relative/absolute/fixed 的元素,就以该元素为基准定位,如果没找到,就以浏览器边界定位。如下两个图所示:

JavaScript 有哪些数据类型,它们的区别?

JavaScript 共有八种数据类型,别离是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。

其中 Symbol 和 BigInt 是 ES6 中新增的数据类型:

  • Symbol 代表创立后举世无双且不可变的数据类型,它次要是为了解决可能呈现的全局变量抵触的问题。
  • BigInt 是一种数字类型的数据,它能够示意任意精度格局的整数,应用 BigInt 能够平安地存储和操作大整数,即便这个数曾经超出了 Number 可能示意的平安整数范畴。

这些数据能够分为原始数据类型和援用数据类型:

  • 栈:原始数据类型(Undefined、Null、Boolean、Number、String)
  • 堆:援用数据类型(对象、数组和函数)

两种类型的区别在于 存储地位的不同:

  • 原始数据类型间接存储在栈(stack)中的简略数据段,占据空间小、大小固定,属于被频繁应用数据,所以放入栈中存储;
  • 援用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;援用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找援用值时,会首先检索其在栈中的地址,获得地址后从堆中取得实体。

堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:

  • 在数据结构中,栈中数据的存取形式为先进后出。
  • 堆是一个优先队列,是按优先级来进行排序的,优先级能够依照大小来规定。

在操作系统中,内存被分为栈区和堆区:

  • 栈区内存由编译器主动调配开释,寄存函数的参数值,局部变量的值等。其操作形式相似于数据结构中的栈。
  • 堆区内存个别由开发着调配开释,若开发者不开释,程序完结时可能由垃圾回收机制回收。

参考:前端进阶面试题具体解答

元素的层叠程序

层叠程序,英文称作 stacking order,示意元素产生层叠时有着特定的垂直显示程序。上面是盒模型的层叠规定:

(1)背景和边框:建设以后层叠上下文元素的背景和边框。
(2)负的 z -index:以后层叠上下文中,z-index 属性值为负的元素。
(3)块级盒:文档流内非行内级非定位后辈元素。
(4)浮动盒:非定位浮动元素。
(5)行内盒:文档流外行内级非定位后辈元素。
(6)z-index:0:层叠级数为 0 的定位元素。
(7)正 z -index:z-index 属性值为正的定位元素。

留神: 当定位元素 z -index:auto,生成盒在以后层叠上下文中的层级为 0,不会建设新的层叠上下文,除非是根元素。

|| 和 && 操作符的返回值?

|| 和 && 首先会对第一个操作数执行条件判断,如果其不是布尔值就先强制转换为布尔类型,而后再执行条件判断。

  • 对于 || 来说,如果条件判断后果为 true 就返回第一个操作数的值,如果为 false 就返回第二个操作数的值。
  • && 则相同,如果条件判断后果为 true 就返回第二个操作数的值,如果为 false 就返回第一个操作数的值。

|| 和 && 返回它们其中一个操作数的值,而非条件判断的后果

实现一个扇形

用 CSS 实现扇形的思路和三角形基本一致,就是多了一个圆角的款式,实现一个 90°的扇形:

div{
    border: 100px solid transparent;
    width: 0;
    heigt: 0;
    border-radius: 100px;
    border-top-color: red;
}

浏览器的次要组成部分

  • ⽤户界⾯ 包含地址栏、后退 / 后退按钮、书签菜单等。除了浏览器主窗⼝显示的您申请的⻚⾯外,其余显示的各个局部都属于⽤户界⾯。
  • 浏览器引擎 在⽤户界⾯和出现引擎之间传送指令。
  • 出现引擎 负责显示申请的内容。如果申请的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。
  • ⽹络 ⽤于⽹络调⽤,⽐如 HTTP 申请。其接⼝与平台⽆关,并为所有平台提供底层实现。
  • ⽤户界⾯后端 ⽤于绘制根本的窗⼝⼩部件,⽐如组合框和窗⼝。其公开了与平台⽆关的通⽤接⼝,⽽在底层使⽤操作系统的⽤户界⾯⽅法。
  • JavaScript 解释器。⽤于解析和执⾏ JavaScript 代码。
  • 数据存储 这是长久层。浏览器须要在硬盘上保留各种数据,例如 Cookie。新的 HTML 标准 (HTML5) 定义了“⽹络数据库”,这是⼀个残缺(然而轻便)的浏览器内数据库。

值得注意的是,和⼤少数浏览器不同,Chrome 浏览器的每个标签⻚都别离对应⼀个出现引擎实例。每个标签⻚都是⼀个独⽴的过程。

Vue 通信

1.props 和 $emit
2. 地方事件总线 EventBus(根本不必)
3.vuex(官网举荐状态管理器)
4.$parent 和 $children
当然还有一些其余方法,但根本不罕用,或者用起来太简单来。介绍来通信的形式,还能够扩大说一下应用
场景,如何应用,注意事项之类的。

IndexedDB 有哪些特点?

IndexedDB 具备以下特点:

  • 键值对贮存:IndexedDB 外部采纳对象仓库(object store)存放数据。所有类型的数据都能够间接存入,包含 JavaScript 对象。对象仓库中,数据以 ” 键值对 ” 的模式保留,每一个数据记录都有对应的主键,主键是举世无双的,不能有反复,否则会抛出一个谬误。
  • 异步:IndexedDB 操作时不会锁死浏览器,用户仍然能够进行其余操作,这与 LocalStorage 造成比照,后者的操作是同步的。异步设计是为了避免大量数据的读写,拖慢网页的体现。
  • 反对事务:IndexedDB 反对事务(transaction),这意味着一系列操作步骤之中,只有有一步失败,整个事务就都勾销,数据库回滚到事务产生之前的状态,不存在只改写一部分数据的状况。
  • 同源限度: IndexedDB 受到同源限度,每一个数据库对应创立它的域名。网页只能拜访本身域名下的数据库,而不能拜访跨域的数据库。
  • 贮存空间大:IndexedDB 的贮存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有下限。
  • 反对二进制贮存:IndexedDB 不仅能够贮存字符串,还能够贮存二进制数据(ArrayBuffer 对象和 Blob 对象)。

说一下 SPA 单页面有什么优缺点?

长处:1. 体验好,不刷新,缩小 申请  数据 ajax 异步获取 页面流程;2. 前后端拆散

3. 加重服务端压力

4. 共用一套后端程序代码,适配多端

毛病:1. 首屏加载过慢;2.SEO 不利于搜索引擎抓取

Vue 路由守卫有哪些,怎么设置,应用场景等

罕用的两个路由守卫:router.beforeEach 和 router.afterEach

每个守卫办法接管三个参数:to: Route: 行将要进入的指标 路由对象

from: Route: 以后导航正要来到的路由

next: Function: 肯定要调用该办法来 resolve 这个钩子。在我的项目中,个别在 beforeEach 这个钩子函数中进行路由跳转的一些信息判断。判断是否登录,是否拿到对应的路由权限等等。

其余值到数字值的转换规则?

  • Undefined 类型的值转换为 NaN。
  • Null 类型的值转换为 0。
  • Boolean 类型的值,true 转换为 1,false 转换为 0。
  • String 类型的值转换如同应用 Number() 函数进行转换,如果蕴含非数字值则转换为 NaN,空字符串为 0。
  • Symbol 类型的值不能转换为数字,会报错。
  • 对象(包含数组)会首先被转换为相应的根本类型值,如果返回的是非数字的根本类型值,则再遵循以上规定将其强制转换为数字。

为了将值转换为相应的根本类型值,形象操作 ToPrimitive 会首先(通过外部操作 DefaultValue)查看该值是否有 valueOf()办法。如果有并且返回根本类型值,就应用该值进行强制类型转换。如果没有就应用 toString() 的返回值(如果存在)来进行强制类型转换。

如果 valueOf() 和 toString() 均不返回根本类型值,会产生 TypeError 谬误。

Cookie 有哪些字段,作用别离是什么

Cookie 由以下字段组成:

  • Name:cookie 的名称
  • Value:cookie 的值,对于认证 cookie,value 值包含 web 服务器所提供的拜访令牌;
  • Size:cookie 的大小
  • Path:能够拜访此 cookie 的页面门路。比方 domain 是 abc.com,path 是 /test,那么只有/test 门路下的页面能够读取此 cookie。
  • Secure:指定是否应用 HTTPS 平安协定发送 Cookie。应用 HTTPS 平安协定,能够爱护 Cookie 在浏览器和 Web 服务器间的传输过程中不被窃取和篡改。该办法也可用于 Web 站点的身份甄别,即在 HTTPS 的连贯建设阶段,浏览器会查看 Web 网站的 SSL 证书的有效性。然而基于兼容性的起因(比方有些网站应用自签订的证书)在检测到 SSL 证书有效时,浏览器并不会立刻终止用户的连贯申请,而是显示平安危险信息,用户仍能够抉择持续拜访该站点。
  • Domain:能够拜访该 cookie 的域名,Cookie 机制并未遵循严格的同源策略,容许一个子域能够设置或获取其父域的 Cookie。当须要实现单点登录计划时,Cookie 的上述个性十分有用,然而也减少了 Cookie 受攻打的危险,比方攻击者能够借此动员会话定置攻打。因此,浏览器禁止在 Domain 属性中设置.org、.com 等通用顶级域名、以及在国家及地区顶级域下注册的二级域名,以减小攻打产生的范畴。
  • HTTP:该字段蕴含 HTTPOnly 属性,该属性用来设置 cookie 是否通过脚本来拜访,默认为空,即能够通过脚本拜访。在客户端是不能通过 js 代码去设置一个 httpOnly 类型的 cookie 的,这种类型的 cookie 只能通过服务端来设置。该属性用于避免客户端脚本通过document.cookie 属性拜访 Cookie,有助于爱护 Cookie 不被跨站脚本攻打窃取或篡改。然而,HTTPOnly 的利用仍存在局限性,一些浏览器能够阻止客户端脚本对 Cookie 的读操作,但容许写操作;此外大多数浏览器仍容许通过 XMLHTTP 对象读取 HTTP 响应中的 Set-Cookie 头。
  • Expires/Max-size:此 cookie 的超时工夫。若设置其值为一个工夫,那么当达到此工夫后,此 cookie 生效。不设置的话默认值是 Session,意思是 cookie 会和 session 一起生效。当浏览器敞开(不是浏览器标签页,而是整个浏览器) 后,此 cookie 生效。

总结: 服务器端能够应用 Set-Cookie 的响应头部来配置 cookie 信息。一条 cookie 包含了 5 个属性值 expires、domain、path、secure、HttpOnly。其中 expires 指定了 cookie 生效的工夫,domain 是域名、path 是门路,domain 和 path 一起限度了 cookie 可能被哪些 url 拜访。secure 规定了 cookie 只能在确保安全的状况下传输,HttpOnly 规定了这个 cookie 只能被服务器拜访,不能应用 js 脚本拜访。

手写公布订阅

class EventListener {listeners = {};
    on(name, fn) {(this.listeners[name] || (this.listeners[name] = [])).push(fn)
    }
    once(name, fn) {let tem = (...args) => {this.removeListener(name, fn)
            fn(...args)
        }
        fn.fn = tem
        this.on(name, tem)
    }
    removeListener(name, fn) {if (this.listeners[name]) {this.listeners[name] = this.listeners[name].filter(listener => (listener != fn && listener != fn.fn))
        }
    }
    removeAllListeners(name) {if (name && this.listeners[name]) delete this.listeners[name]
        this.listeners = {}}
    emit(name, ...args) {if (this.listeners[name]) {this.listeners[name].forEach(fn => fn.call(this, ...args))
        }
    }
}

typeof null 的后果是什么,为什么?

typeof null 的后果是 Object。

在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元蕴含一个小的 类型标签(1-3 bits) 以及以后要存储值的实在数据。类型标签存储在每个单元的低位中,共有五种数据类型:

000: object   - 以后存储的数据指向一个对象。1: int      - 以后存储的数据是一个 31 位的有符号整数。010: double   - 以后存储的数据指向一个双精度的浮点数。100: string   - 以后存储的数据指向一个字符串。110: boolean  - 以后存储的数据是布尔值。

如果最低位是 1,则类型标签标记位的长度只有一位;如果最低位是 0,则类型标签标记位的长度占三位,为存储其余四种数据类型提供了额定两个 bit 的长度。

有两种非凡数据类型:

  • undefined 的值是 (-2)30(一个超出整数范畴的数字);
  • null 的值是机器码 NULL 指针(null 指针的值全是 0)

那也就是说 null 的类型标签也是 000,和 Object 的类型标签一样,所以会被断定为 Object。

有哪些可能引起前端平安的问题?

  • 跨站脚本 (Cross-Site Scripting, XSS): ⼀种代码注⼊⽅式, 为了与 CSS 辨别所以被称作 XSS。晚期常⻅于⽹络论坛, 起因是⽹站没有对⽤户的输⼊进⾏严格的限度, 使得攻击者能够将脚本上传到帖⼦让其余⼈浏览到有歹意脚本的⻚⾯, 其注⼊⽅式很简略包含但不限于 JavaScript / CSS / Flash 等;
  • iframe 的滥⽤: iframe 中的内容是由第三⽅来提供的,默认状况下他们不受管制,他们能够在 iframe 中运⾏ JavaScirpt 脚本、Flash 插件、弹出对话框等等,这可能会毁坏前端⽤户体验;
  • 跨站点申请伪造(Cross-Site Request Forgeries,CSRF): 指攻击者通过设置好的陷阱,强制对已实现认证的⽤户进⾏⾮预期的个⼈信息或设定信息等某些状态更新,属于被动攻打
  • 歹意第三⽅库: ⽆论是后端服务器应⽤还是前端应⽤开发,绝⼤少数时候都是在借助开发框架和各种类库进⾏疾速开发,⼀旦第三⽅库被植⼊恶意代码很容易引起平安问题。
正文完
 0