乐趣区

关于前端:京东前端一面常考面试题附答案

代码输入后果

var A = {n: 4399};
var B =  function(){this.n = 9999};
var C =  function(){var n = 8888};
B.prototype = A;
C.prototype = A;
var b = new B();
var c = new C();
A.n++
console.log(b.n);
console.log(c.n);

输入后果:9999 4400

解析:

  1. console.log(b.n),在查找 b.n 是首先查找 b 对象本身有没有 n 属性,如果没有会去原型(prototype)上查找,当执行 var b = new B()时,函数外部 this.n=9999(此时 this 指向 b) 返回 b 对象,b 对象有本身的 n 属性,所以返回 9999。
  2. console.log(c.n),同理,当执行 var c = new C()时,c 对象没有本身的 n 属性,向上查找,找到原型(prototype)上的 n 属性,因为 A.n++(此时对象 A 中的 n 为 4400),所以返回 4400。

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

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

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

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

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

单例模式

用意:保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。

次要解决:一个全局应用的类频繁地创立与销毁。

何时应用:当您想管制实例数目,节俭系统资源的时候。

如何解决:判断零碎是否曾经有这个单例,如果有则返回,如果没有则创立。

实现

var Singleton = (function() {
    // 如果在外部申明 SingletonClass 对象,则无奈在内部间接调用
    var SingletonClass = function() {}; 
    var instance;
    return function() {
        // 如果已存在,则返回 instance
        if(instance) return instance;
        // 如果不存在,则 new 一个 SingletonClass 对象
        instance = new SingletonClass();
        return instance;
    }
})();

// 测试
var a = new Singleton();
var b = new Singleton();
console.log(a === b);  // true

箭头函数和一般函数有啥区别?箭头函数能当构造函数吗?

  • 一般函数通过 function 关键字定义,this 无奈联合词法作用域应用,在运行时绑定,只取决于函数的调用形式,在哪里被调用,调用地位。(取决于调用者,和是否独立运行)
  • 箭头函数应用被称为“胖箭头”的操作 => 定义,箭头函数不利用一般函数 this 绑定的四种规定,而是依据外层(函数或全局)的作用域来决定 this,且箭头函数的绑定无奈被批改(new 也不行)。

    • 箭头函数罕用于回调函数中,包含事件处理器或定时器
    • 箭头函数和 var self = this,都试图取代传统的 this 运行机制,将 this 的绑定拉回到词法作用域
    • 没有原型、没有 this、没有 super,没有 arguments,没有 new.target
    • 不能通过 new 关键字调用

      • 一个函数外部有两个办法:[[Call]] 和 [[Construct]],在通过 new 进行函数调用时,会执行 [[construct]] 办法,创立一个实例对象,而后再执行这个函数体,将函数的 this 绑定在这个实例对象上
      • 当间接调用时,执行 [[Call]] 办法,间接执行函数体
      • 箭头函数没有 [[Construct]] 办法,不能被用作结构函数调用,当应用 new 进行函数调用时会报错。
function foo() {return (a) => {console.log(this.a);
  }
}

var obj1 = {a: 2}

var obj2 = {a: 3}

var bar = foo.call(obj1);
bar.call(obj2);

HTTP2 的头部压缩算法是怎么的?

HTTP2 的头部压缩是 HPACK 算法。在客户端和服务器两端建设“字典”,用索引号示意反复的字符串,采纳哈夫曼编码来压缩整数和字符串,能够达到 50%~90% 的高压缩率。

具体来说:

  • 在客户端和服务器端应用“首部表”来跟踪和存储之前发送的键值对,对于雷同的数据,不再通过每次申请和响应发送;
  • 首部表在 HTTP/ 2 的连贯存续期内始终存在,由客户端和服务器独特渐进地更新;
  • 每个新的首部键值对要么被追加到以后表的开端,要么替换表中之前的值。

例如下图中的两个申请,申请一发送了所有的头部字段,第二个申请则只须要发送差别数据,这样能够缩小冗余数据,升高开销。

img 的 srcset 属性的作⽤?

响应式页面中常常用到依据屏幕密度设置不同的图片。这时就用到了 img 标签的 srcset 属性。srcset 属性用于设置不同屏幕密度下,img 会主动加载不同的图片。用法如下:

<img src="image-128.png" srcset="image-256.png 2x" />

应用下面的代码,就能实现在屏幕密度为 1x 的状况下加载 image-128.png, 屏幕密度为 2x 时加载 image-256.png。

依照下面的实现,不同的屏幕密度都要设置图片地址,目前的屏幕密度有 1x,2x,3x,4x 四种,如果每一个图片都设置 4 张图片,加载就会很慢。所以就有了新的 srcset 规范。代码如下:

<img src="image-128.png"
     srcset="image-128.png 128w, image-256.png 256w, image-512.png 512w"
     sizes="(max-width: 360px) 340px, 128px" />

其中 srcset 指定图片的地址和对应的图片品质。sizes 用来设置图片的尺寸零界点。对于 srcset 中的 w 单位,能够了解成图片品质。如果可视区域小于这个品质的值,就能够应用。浏览器会主动抉择一个最小的可用图片。

sizes 语法如下:

sizes="[media query] [length], [media query] [length] ..."

sizes 就是指默认显示 128px, 如果视区宽度大于 360px, 则显示 340px。

常⽤的 meta 标签有哪些

meta 标签由 namecontent 属性定义,用来形容网页文档的属性 ,比方网页的作者,网页形容,关键词等,除了 HTTP 规范固定了一些name 作为大家应用的共识,开发者还能够自定义 name。

罕用的 meta 标签:
(1)charset,用来形容 HTML 文档的编码类型:

<meta charset="UTF-8" >

(2)keywords,页面关键词:

<meta name="keywords" content="关键词" />

(3)description,页面形容:

<meta name="description" content="页面形容内容" />

(4)refresh,页面重定向和刷新:

<meta http-equiv="refresh" content="0;url=" />

(5)viewport,适配挪动端,能够管制视口的大小和比例:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

其中,content 参数有以下几种:

  • width viewport:宽度(数值 /device-width)
  • height viewport:高度(数值 /device-height)
  • initial-scale:初始缩放比例
  • maximum-scale:最大缩放比例
  • minimum-scale:最小缩放比例
  • user-scalable:是否容许用户缩放(yes/no)

(6)搜索引擎索引形式:

<meta name="robots" content="index,follow" />

其中,content 参数有以下几种:

  • all:文件将被检索,且页面上的链接能够被查问;
  • none:文件将不被检索,且页面上的链接不能够被查问;
  • index:文件将被检索;
  • follow:页面上的链接能够被查问;
  • noindex:文件将不被检索;
  • nofollow:页面上的链接不能够被查问。

TCP/IP 五层协定

TCP/IP五层协定和 OSI 的七层协定对应关系如下:

  • 应用层 (application layer):间接为利用过程提供服务。应用层协定定义的是利用过程间通信和交互的规定,不同的利用有着不同的应用层协定,如 HTTP 协定(万维网服务)、FTP 协定(文件传输)、SMTP 协定(电子邮件)、DNS(域名查问)等。
  • 传输层 (transport layer):有时也译为运输层,它负责为两台主机中的过程提供通信服务。该层次要有以下两种协定:

    • 传输控制协议 (Transmission Control Protocol,TCP):提供面向连贯的、牢靠的数据传输服务,数据传输的根本单位是报文段(segment);
    • 用户数据报协定 (User Datagram Protocol,UDP):提供无连贯的、尽最大致力的数据传输服务,但不保障数据传输的可靠性,数据传输的根本单位是用户数据报。
  • 网络层 (internet layer):有时也译为网际层,它负责为两台主机提供通信服务,并通过抉择适合的路由将数据传递到指标主机。
  • 数据链路层 (data link layer):负责将网络层交下来的 IP 数据报封装成帧,并在链路的两个相邻节点间传送帧,每一帧都蕴含数据和必要的管制信息(如同步信息、地址信息、差错控制等)。
  • 物理层 (physical Layer):确保数据能够在各种物理媒介上进行传输,为数据的传输提供牢靠的环境。

从上图中能够看出,TCP/IP模型比 OSI 模型更加简洁,它把 应用层 / 表示层 / 会话层 全副整合为了 应用层

在每一层都工作着不同的设施,比方咱们罕用的交换机就工作在数据链路层的,个别的路由器是工作在网络层的。在每一层实现的协定也各不同,即每一层的服务也不同,下图列出了每层次要的传输协定:

同样,TCP/IP五层协定的通信形式也是对等通信:

实现一个 add 办法

题目形容: 实现一个 add 办法 使计算结果可能满足如下预期:
add(1)(2)(3)()=6
add(1,2,3)(4)()=10

其实就是考函数柯里化

实现代码如下:

function add(...args) {let allArgs = [...args];
  function fn(...newArgs) {allArgs = [...allArgs, ...newArgs];
    return fn;
  }
  fn.toString = function () {if (!allArgs.length) {return;}
    return allArgs.reduce((sum, cur) => sum + cur);
  };
  return fn;
}

z-index 属性在什么状况下会生效

通常 z-index 的应用是在有两个重叠的标签,在肯定的状况下管制其中一个在另一个的上方或者下方呈现。z-index 值越大就越是在下层。z-index 元素的 position 属性须要是 relative,absolute 或是 fixed。

z-index 属性在下列状况下会生效:

  • 父元素 position 为 relative 时,子元素的 z -index 生效。解决:父元素 position 改为 absolute 或 static;
  • 元素没有设置 position 属性为非 static 属性。解决:设置该元素的 position 属性为 relative,absolute 或是 fixed 中的一种;
  • 元素在设置 z -index 的同时还设置了 float 浮动。解决:float 去除,改为 display:inline-block;

0.1 + 0.2 === 0.3 嘛?为什么?

JavaScript 应用 Number 类型来示意数字(整数或浮点数),遵循 IEEE 754 规范,通过 64 位来示意一个数字(1 + 11 + 52)

  • 1 符号位,0 示意负数,1 示意正数 s
  • 11 指数位(e)
  • 52 尾数,小数局部(即有效数字)

最大平安数字:Number.MAX_SAFE_INTEGER = Math.pow(2, 53) – 1,转换成整数就是 16 位,所以 0.1 === 0.1,是因为通过 toPrecision(16) 去无效位之后,两者是相等的。

在两数相加时,会先转换成二进制,0.1 和 0.2 转换成二进制的时候尾数会产生有限循环,而后进行对阶运算,JS 引擎对二进制进行截断,所以造成精度失落。

所以总结:精度失落可能呈现在进制转换和对阶运算中

Object.assign()

形容 Object.assign() 办法用于将所有 可枚举 Object.propertyIsEnumerable() 返回 true)和 自有Object.hasOwnProperty() 返回 true)属性的值从一个或多个源对象复制到指标对象。它将返回批改后的指标对象(请留神这个操作是浅拷贝)。

实现

Object.assign = function(target, ...source) {if(target == null) {throw new TypeError('Cannot convert undefined or null to object');
    }
    let res = Object(target);
    source.forEach(function(obj) {if(obj != null) {
            // for...in 只会遍历对象本身的和继承的可枚举的属性(不含 Symbol 属性)// hasOwnProperty 办法只思考对象本身的属性
            for(let key in obj) {if(obj.hasOwnProperty(key)) {res[key] = obj[key];
                }
            }
        }
    });
    return res;
}

异步任务调度器

形容:实现一个带并发限度的异步调度器 Scheduler,保障同时运行的工作最多有 limit 个。

实现

class Scheduler {queue = [];  // 用队列保留正在执行的工作
    runCount = 0;  // 计数正在执行的工作个数
    constructor(limit) {this.maxCount = limit;  // 容许并发的最大个数}
    add(time, data){const promiseCreator = () => {return new Promise((resolve, reject) => {setTimeout(() => {console.log(data);
                    resolve();}, time);
            });
        }
        this.queue.push(promiseCreator);
        // 每次增加的时候都会尝试去执行工作
        this.request();}
    request() {
        // 队列中还有工作才会被执行
        if(this.queue.length && this.runCount < this.maxCount) {
            this.runCount++;
            // 执行先退出队列的函数
            this.queue.shift()().then(() => {
                this.runCount--;
                // 尝试进行下一次工作
                this.request();});
        }
    }
}

// 测试
const scheduler = new Scheduler(2);
const addTask = (time, data) => {scheduler.add(time, data);
}

addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
// 输入后果 2 3 1 4

对浏览器的了解

浏览器的次要性能是将用户抉择的 web 资源出现进去,它须要从服务器申请资源,并将其显示在浏览器窗口中,资源的格局通常是 HTML,也包含 PDF、image 及其他格局。用户用 URI(Uniform Resource Identifier 对立资源标识符)来指定所申请资源的地位。

HTML 和 CSS 标准中规定了浏览器解释 html 文档的形式,由 W3C 组织对这些标准进行保护,W3C 是负责制订 web 规范的组织。然而浏览器厂商纷纷开发本人的扩大,对标准的遵循并不欠缺,这为 web 开发者带来了重大的兼容性问题。

浏览器能够分为两局部,shell 和 内核。其中 shell 的品种绝对比拟多,内核则比拟少。也有一些浏览器并不辨别外壳和内核。从 Mozilla 将 Gecko 独立进去后,才有了外壳和内核的明确划分。

  • shell 是指浏览器的外壳:例如菜单,工具栏等。次要是提供给用户界面操作,参数设置等等。它是调用内核来实现各种性能的。
  • 内核是浏览器的外围。内核是基于标记语言显示内容的程序或模块。

函数中的 arguments 是数组吗?类数组转数组的办法理解一下?

是类数组,是属于鸭子类型的领域,长得像数组,

  • … 运算符
  • Array.from
  • Array.prototype.slice.apply(arguments)

一个 tcp 连贯能发几个 http 申请?

如果是 HTTP 1.0 版本协定,个别状况下,不反对长连贯,因而在每次申请发送结束之后,TCP 连贯即会断开,因而一个 TCP 发送一个 HTTP 申请,然而有一种状况能够将一条 TCP 连贯放弃在沉闷状态,那就是通过 Connection 和 Keep-Alive 首部,在申请头带上 Connection: Keep-Alive,并且能够通过 Keep-Alive 通用首部中指定的,用逗号分隔的选项调节 keep-alive 的行为,如果客户端和服务端都反对,那么其实也能够发送多条,不过此形式也有限度,能够关注《HTTP 权威指南》4.5.5 节对于 Keep-Alive 连贯的限度和规定。

而如果是 HTTP 1.1 版本协定,反对了长连贯,因而只有 TCP 连接不断开,便能够始终发送 HTTP 申请,继续一直,没有下限;同样,如果是 HTTP 2.0 版本协定,反对多用复用,一个 TCP 连贯是能够并发多个 HTTP 申请的,同样也是反对长连贯,因而只有一直开 TCP 的连贯,HTTP 申请数也是能够没有下限地继续发送

GET 和 POST 的申请的区别

Post 和 Get 是 HTTP 申请的两种办法,其区别如下:

  • 利用场景: GET 申请是一个幂等的申请,个别 Get 申请用于对服务器资源不会产生影响的场景,比如说申请一个网页的资源。而 Post 不是一个幂等的申请,个别用于对服务器资源会产生影响的情景,比方注册用户这一类的操作。
  • 是否缓存: 因为两者利用场景不同,浏览器个别会对 Get 申请缓存,但很少对 Post 申请缓存。
  • 发送的报文格式: Get 申请的报文中实体局部为空,Post 申请的报文中实体局部个别为向服务器发送的数据。
  • 安全性: Get 申请能够将申请的参数放入 url 中向服务器发送,这样的做法绝对于 Post 申请来说是不太平安的,因为申请的 url 会被保留在历史记录中。
  • 申请长度: 浏览器因为对 url 长度的限度,所以会影响 get 申请发送数据时的长度。这个限度是浏览器规定的,并不是 RFC 规定的。
  • 参数类型: post 的参数传递反对更多的数据类型。

冒泡排序 – 工夫复杂度 n^2

题目形容: 实现一个冒泡排序

实现代码如下:

function bubbleSort(arr) {
  // 缓存数组长度
  const len = arr.length;
  // 外层循环用于管制从头到尾的比拟 + 替换到底有多少轮
  for (let i = 0; i < len; i++) {
    // 内层循环用于实现每一轮遍历过程中的反复比拟 + 替换
    for (let j = 0; j < len - 1; j++) {
      // 若相邻元素后面的数比前面的大
      if (arr[j] > arr[j + 1]) {
        // 替换两者
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  // 返回数组
  return arr;
}
// console.log(bubbleSort([3, 6, 2, 4, 1]));

HTTP 协定的性能怎么样

HTTP 协定是基于 TCP/IP,并且应用了 申请 - 应答 的通信模式,所以性能的要害就在这两点里。

  • 长连贯

HTTP 协定有两种连贯模式,一种是继续连贯,一种非继续连贯。
(1)非继续连贯指的是服务器必须为每一个申请的对象建设和保护一个全新的连贯。
(2)继续连贯下,TCP 连贯默认不敞开,能够被多个申请复用。采纳继续连贯的益处是能够防止每次建设 TCP 连贯三次握手时所破费的工夫。

对于不同版本的采纳不同的连贯形式:

  • 在 HTTP/1.0 每发动一个申请,都要新建一次 TCP 连贯(三次握手),而且是串行申请,做了无畏的 TCP 连贯建设和断开,减少了通信开销。该版本应用的非继续的连贯,然而能够在申请时,加上 Connection: keep-a live 来要求服务器不要敞开 TCP 连贯。
  • 在 HTTP/1.1 提出了 长连贯 的通信形式,也叫长久连贯。这种形式的益处在于缩小了 TCP 连贯的反复建设和断开所造成的额定开销,加重了服务器端的负载。该版本及当前版本默认采纳的是继续的连贯。目前对于同一个域,大多数浏览器反对同时建设 6 个长久连贯。
  • 管道网络传输

HTTP/1.1 采纳了长连贯的形式,这使得管道(pipeline)网络传输成为了可能。

管道(pipeline)网络传输是指:能够在同一个 TCP 连贯外面,客户端能够发动多个申请,只有第一个申请收回去了,不用等其回来,就能够发第二个申请进来,能够缩小整体的响应工夫。然而服务器还是依照程序回应申请。如果后面的回应特地慢,前面就会有许多申请排队等着。这称为队头梗塞。

  • 队头梗塞

HTTP 传输的报文必须是一发一收,然而,外面的工作被放在一个工作队列中串行执行,一旦队首的申请解决太慢,就会阻塞前面申请的解决。这就是 HTTP 队头阻塞问题。

队头阻塞的解决方案:(1)并发连贯:对于一个域名容许调配多个长连贯,那么相当于减少了工作队列,不至于一个队伍的工作阻塞其它所有工作。
(2)域名分片:将域名分出很多二级域名,它们都指向同样的一台服务器,可能并发的长连接数变多,解决了队头阻塞的问题。

替换元素的概念及计算规定

通过批改某个属性值出现的内容就能够被替换的元素就称为“替换元素”。

替换元素除了内容可替换这一个性以外,还有以下个性:

  • 内容的外观不受页面上的 CSS 的影响:用业余的话讲就是在款式体现在 CSS 作用域之外。如何更改替换元素自身的外观须要相似 appearance 属性,或者浏览器本身裸露的一些款式接口。
  • 有本人的尺寸:在 Web 中,很多替换元素在没有明确尺寸设定的状况下,其默认的尺寸(不包含边框)是 300 像素×150 像素,如
  • 在很多 CSS 属性上有本人的一套体现规定:比拟具备代表性的就是 vertical-align 属性,对于替换元素和非替换元素,vertical-align 属性值的解释是不一样的。比方说 vertical-align 的默认值的 baseline,很简略的属性值,基线之意,被定义为字符 x 的下边缘,而替换元素的基线却被硬生生定义成了元素的下边缘。
  • 所有的替换元素都是内联程度元素:也就是替换元素和替换元素、替换元素和文字都是能够在一行显示的。然而,替换元素默认的 display 值却是不一样的,有的是 inline,有的是 inline-block。

替换元素的尺寸从内而外分为三类:

  • 固有尺寸: 指的是替换内容本来的尺寸。例如,图片、视频作为一个独立文件存在的时候,都是有着本人的宽度和高度的。
  • HTML 尺寸: 只能通过 HTML 原生属性扭转,这些 HTML 原生属性包含的 width 和 height 属性、的 size 属性。
  • CSS 尺寸: 特指能够通过 CSS 的 width 和 height 或者 max-width/min-width 和 max-height/min-height 设置的尺寸,对应盒尺寸中的 content box。

这三层构造的计算规定具体如下:
(1)如果没有 CSS 尺寸和 HTML 尺寸,则应用固有尺寸作为最终的宽高。
(2)如果没有 CSS 尺寸,则应用 HTML 尺寸作为最终的宽高。
(3)如果有 CSS 尺寸,则最终尺寸由 CSS 属性决定。
(4)如果“固有尺寸”含有固有的宽高比例,同时仅设置了宽度或仅设置了高度,则元素仍然依照固有的宽高比例显示。
(5)如果下面的条件都不合乎,则最终宽度体现为 300 像素,高度为 150 像素。
(6)内联替换元素和块级替换元素应用下面同一套尺寸计算规定。

退出移动版