关于javascript:2022面试官常考的前端面试题

5次阅读

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

Ajax

它是一种异步通信的办法,通过间接由 js 脚本向服务器发动 http 通信,而后依据服务器返回的数据,更新网页的相应局部,而不必刷新整个页面的一种办法。

面试手写(原生):

//1:创立 Ajax 对象
var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// 兼容 IE6 及以下版本
//2:配置 Ajax 申请地址
xhr.open('get','index.xml',true);
//3:发送申请
xhr.send(null); // 谨严写法
//4: 监听申请,承受响应
xhr.onreadysatechange=function(){if(xhr.readySate==4&&xhr.status==200 || xhr.status==304)
          console.log(xhr.responsetXML)
}

jQuery 写法

$.ajax({
  type:'post',
  url:'',
  async:ture,//async 异步  sync  同步
  data:data,// 针对 post 申请
  dataType:'jsonp',
  success:function (msg) { },
  error:function (error) {}})

promise 封装实现:

// promise 封装实现:function getJSON(url) {
  // 创立一个 promise 对象
  let promise = new Promise(function(resolve, reject) {let xhr = new XMLHttpRequest();

    // 新建一个 http 申请
    xhr.open("GET", url, true);

    // 设置状态的监听函数
    xhr.onreadystatechange = function() {if (this.readyState !== 4) return;

      // 当申请胜利或失败时,扭转 promise 的状态
      if (this.status === 200) {resolve(this.response);
      } else {reject(new Error(this.statusText));
      }
    };

    // 设置谬误监听函数
    xhr.onerror = function() {reject(new Error(this.statusText));
    };

    // 设置响应的数据类型
    xhr.responseType = "json";

    // 设置申请头信息
    xhr.setRequestHeader("Accept", "application/json");

    // 发送 http 申请
    xhr.send(null);
  });

  return promise;
}

数组扁平化

ES5 递归写法 —— isArray()、concat()

function flat11(arr) {var res = [];
    for (var i = 0; i < arr.length; i++) {if (Array.isArray(arr[i])) {res = res.concat(flat11(arr[i]));
        } else {res.push(arr[i]);
        }
    }
    return res;
}

如果想实现第二个参数(指定“拉平”的层数),能够这样实现,前面的几种能够本人相似实现:

function flat(arr, level = 1) {var res = [];
    for(var i = 0; i < arr.length; i++) {if(Array.isArray(arr[i]) || level >= 1) {res = res.concat(flat(arr[i]), level - 1);
        }
        else {res.push(arr[i]);
        }
    }
    return res;
}

ES6 递归写法 — reduce()、concat()、isArray()

function flat(arr) {
    return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? flat(cur) : cur), []);
}

ES6 迭代写法 — 扩大运算符(…)、some()、concat()、isArray()

ES6 的扩大运算符(…) 只能扁平化一层

function flat(arr) {return [].concat(...arr);
}

全副扁平化 :遍历原数组,若arr 中含有数组则应用一次扩大运算符,直至没有为止。

function flat(arr) {while(arr.some(item => Array.isArray(item))) {arr = [].concat(...arr);
    }
    return arr;
}

toString/join & split

调用数组的 toString()/join() 办法(它会主动扁平化解决),将数组变为字符串而后再用 split 宰割还原为数组。因为 split 宰割后造成的数组的每一项值为字符串,所以须要用一个 map 办法遍历数组将其每一项转换为数值型。

function flat(arr){return arr.toString().split(',').map(item => Number(item));
    // return arr.join().split(',').map(item => Number(item));
}

应用正则

JSON.stringify(arr).replace(/[|]/g, '') 会先将数组 arr 序列化为字符串,而后应用 replace() 办法将字符串中所有的[] 替换成空字符,从而达到扁平化解决,此时的后果为 arr 不蕴含 [] 的字符串。最初通过JSON.parse() 解析字符串。

function flat(arr) {return JSON.parse("[" + JSON.stringify(arr).replace(/\[|\]/g,'') +"]");
}

类数组转化为数组

类数组是具备 length 属性,但不具备数组原型上的办法。常见的类数组有 arguments、DOM 操作方法返回的后果 (如document.querySelectorAll('div')) 等。

扩大运算符(…)

留神:扩大运算符只能作用于 iterable 对象,即领有 Symbol(Symbol.iterator) 属性值。

let arr = [...arrayLike]

Array.from()

let arr = Array.from(arrayLike);

Array.prototype.slice.call()

let arr = Array.prototype.slice.call(arrayLike);

Array.apply()

let arr = Array.apply(null, arrayLike);

concat + apply

let arr = Array.prototype.concat.apply([], arrayLike);

async/await 如何捕捉异样

async function fn(){
    try{let a = await Promise.reject('error')
    }catch(error){console.log(error)
    }
}

响应式设计的概念及基本原理

响应式网站设计(Responsive Web design)是一个网站可能兼容多个终端,而不是为每一个终端做一个特定的版本。

对于原理:基本原理是通过媒体查问 (@media) 查问检测不同的设施屏幕尺寸做解决。
对于兼容:页面头部必须有 mate 申明的viewport

<meta name="’viewport’" content="”width=device-width," initial-scale="1." maximum-scale="1,user-scalable=no”"/>

Sass、Less 是什么?为什么要应用他们?

他们都是 CSS 预处理器,是 CSS 上的一种形象层。他们是一种非凡的语法 / 语言编译成 CSS。例如 Less 是一种动静款式语言,将 CSS 赋予了动静语言的个性,如变量,继承,运算,函数,LESS 既能够在客户端上运行 (反对 IE 6+, Webkit, Firefox),也能够在服务端运行 (借助 Node.js)。

为什么要应用它们?

  • 构造清晰,便于扩大。能够不便地屏蔽浏览器公有语法差别。封装对浏览器语法差别的反复解决,缩小无意义的机械劳动。
  • 能够轻松实现多重继承。齐全兼容 CSS 代码,能够不便地利用到老我的项目中。LESS 只是在 CSS 语法上做了扩大,所以老的 CSS 代码也能够与 LESS 代码一起编译。

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

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

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

  • 内容的外观不受页面上的 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)内联替换元素和块级替换元素应用下面同一套尺寸计算规定。

代码输入后果

async function async1() {console.log("async1 start");
  await async2();
  console.log("async1 end");
  setTimeout(() => {console.log('timer1')
  }, 0)
}
async function async2() {setTimeout(() => {console.log('timer2')
  }, 0)
  console.log("async2");
}
async1();
setTimeout(() => {console.log('timer3')
}, 0)
console.log("start")

输入后果如下:

async1 start
async2
start
async1 end
timer2
timer3
timer1

代码的执行过程如下:

  1. 首先进入async1,打印出async1 start
  2. 之后遇到async2,进入async2,遇到定时器timer2,退出宏工作队列,之后打印async2
  3. 因为 async2 阻塞了前面代码的执行,所以执行前面的定时器timer3,将其退出宏工作队列,之后打印start
  4. 而后执行 async2 前面的代码,打印出async1 end,遇到定时器 timer1,将其退出宏工作队列;
  5. 最初,宏工作队列有三个工作,先后顺序为timer2timer3timer1,没有微工作,所以间接所有的宏工作依照先进先出的准则执行。

对对象与数组的解构的了解

解构是 ES6 提供的一种新的提取数据的模式,这种模式可能从对象或数组里有针对性地拿到想要的数值。1)数组的解构 在解构数组时,以元素的地位为匹配条件来提取想要的数据的:

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

最终,a、b、c 别离被赋予了数组第 0、1、2 个索引位的值:

数组里的 0、1、2 索引位的元素值,精准地被映射到了左侧的第 0、1、2 个变量里去,这就是数组解构的工作模式。还能够通过给左侧变量数组设置空占位的形式,实现对数组中某几个元素的精准提取:

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

通过把两头位留空,能够顺利地把数组第一位和最初一位的值赋给 a、c 两个变量:

2)对象的解构 对象解构比数组构造略微简单一些,也更显弱小。在解构对象时,是以属性的名称为匹配条件,来提取想要的数据的。当初定义一个对象:

const stu = {
  name: 'Bob',
  age: 24
}

如果想要解构它的两个自有属性,能够这样:

const {name, age} = stu

这样就失去了 name 和 age 两个和 stu 平级的变量:

留神,对象解构严格以属性名作为定位根据,所以就算调换了 name 和 age 的地位,后果也是一样的:

const {age, name} = stu

两栏布局的实现

个别两栏布局指的是 右边一栏宽度固定,左边一栏宽度自适应,两栏布局的具体实现:

  • 利用浮动,将右边元素宽度设置为 200px,并且设置向左浮动。将左边元素的 margin-left 设置为 200px,宽度设置为 auto(默认为 auto,撑满整个父元素)。
.outer {height: 100px;}
.left {
  float: left;
  width: 200px;
  background: tomato;
}
.right {
  margin-left: 200px;
  width: auto;
  background: gold;
}
  • 利用浮动,左侧元素设置固定大小,并左浮动,右侧元素设置 overflow: hidden; 这样左边就触发了 BFC,BFC 的区域不会与浮动元素产生重叠,所以两侧就不会产生重叠。
.left{
     width: 100px;
     height: 200px;
     background: red;
     float: left;
 }
 .right{
     height: 300px;
     background: blue;
     overflow: hidden;
 }
  • 利用 flex 布局,将右边元素设置为固定宽度 200px,将左边的元素设置为 flex:1。
.outer {
  display: flex;
  height: 100px;
}
.left {
  width: 200px;
  background: tomato;
}
.right {
  flex: 1;
  background: gold;
}
  • 利用相对定位,将父级元素设置为绝对定位。右边元素设置为 absolute 定位,并且宽度设置为 200px。将左边元素的 margin-left 的值设置为 200px。
.outer {
  position: relative;
  height: 100px;
}
.left {
  position: absolute;
  width: 200px;
  height: 100px;
  background: tomato;
}
.right {
  margin-left: 200px;
  background: gold;
}
  • 利用相对定位,将父级元素设置为绝对定位。右边元素宽度设置为 200px,左边元素设置为相对定位,右边定位为 200px,其余方向定位为 0。
.outer {
  position: relative;
  height: 100px;
}
.left {
  width: 200px;
  background: tomato;
}
.right {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 200px;
  background: gold;
}

浏览器乱码的起因是什么?如何解决?

产生乱码的起因:

  • 网页源代码是 gbk 的编码,而内容中的中文字是 utf-8 编码的,这样浏览器关上即会呈现 html 乱码,反之也会呈现乱码;
  • html网页编码是 gbk,而程序从数据库中调出出现是utf-8 编码的内容也会造成编码乱码;
  • 浏览器不能自动检测网页编码,造成网页乱码。

解决办法:

  • 应用软件编辑 HTML 网页内容;
  • 如果网页设置编码是gbk,而数据库贮存数据编码格局是UTF-8,此时须要程序查询数据库数据显示数据后退程序转码;
  • 如果浏览器浏览时候呈现网页乱码,在浏览器中找到转换编码的菜单进行转换。

实现一个宽高自适应的正方形

  • 利用 vw 来实现:
.square {
  width: 10%;
  height: 10vw;
  background: tomato;
}
  • 利用元素的 margin/padding 百分比是绝对父元素 width 的性质来实现:
.square {
  width: 20%;
  height: 0;
  padding-top: 20%;
  background: orange;
}
  • 利用子元素的 margin-top 的值来实现:
.square {
  width: 30%;
  overflow: hidden;
  background: yellow;
}
.square::after {
  content: '';
  display: block;
  margin-top: 100%;
}

代码输入后果

function Foo(){Foo.a = function(){console.log(1);
    }
    this.a = function(){console.log(2)
    }
}

Foo.prototype.a = function(){console.log(3);
}

Foo.a = function(){console.log(4);
}

Foo.a();
let obj = new Foo();
obj.a();
Foo.a();

输入后果:4 2 1

解析:

  1. Foo.a() 这个是调用 Foo 函数的静态方法 a,尽管 Foo 中有优先级更高的属性办法 a,但 Foo 此时没有被调用,所以此时输入 Foo 的静态方法 a 的后果:4
  2. let obj = new Foo(); 应用了 new 办法调用了函数,返回了函数实例对象,此时 Foo 函数外部的属性办法初始化,原型链建设。
  3. obj.a() ; 调用 obj 实例上的办法 a,该实例上目前有两个 a 办法:一个是外部属性办法,另一个是原型上的办法。当这两者都存在时,首先查找 ownProperty,如果没有才去原型链上找,所以调用实例上的 a 输入:2
  4. Foo.a() ; 依据第 2 步可知 Foo 函数外部的属性办法已初始化,笼罩了同名的静态方法,所以输入:1

说下对 JS 的理解吧

是基于原型的动静语言,次要独特个性有 this、原型和原型链。

JS 严格意义上来说分为:语言规范局部(ECMAScript)+ 宿主环境局部

语言规范局部

2015 年公布 ES6,引入诸多新个性使得可能编写大型项目变成可能,规范自 2015 之后以年号代号,每年一更

宿主环境局部

  • 在浏览器宿主环境包含 DOM + BOM 等
  • 在 Node,宿主环境包含一些文件、数据库、网络、与操作系统的交互等

回流与重绘的概念及触发条件

(1)回流

当渲染树中局部或者全副元素的尺寸、构造或者属性发生变化时,浏览器会从新渲染局部或者全副文档的过程就称为 回流

上面这些操作会导致回流:

  • 页面的首次渲染
  • 浏览器的窗口大小发生变化
  • 元素的内容发生变化
  • 元素的尺寸或者地位发生变化
  • 元素的字体大小发生变化
  • 激活 CSS 伪类
  • 查问某些属性或者调用某些办法
  • 增加或者删除可见的 DOM 元素

在触发回流(重排)的时候,因为浏览器渲染页面是基于流式布局的,所以当触发回流时,会导致四周的 DOM 元素重新排列,它的影响范畴有两种:

  • 全局范畴:从根节点开始,对整个渲染树进行从新布局
  • 部分范畴:对渲染树的某局部或者一个渲染对象进行从新布局

(2)重绘

当页面中某些元素的款式发生变化,然而不会影响其在文档流中的地位时,浏览器就会对元素进行从新绘制,这个过程就是 重绘

上面这些操作会导致回流:

  • color、background 相干属性:background-color、background-image 等
  • outline 相干属性:outline-color、outline-width、text-decoration
  • border-radius、visibility、box-shadow

留神:当触发回流时,肯定会触发重绘,然而重绘不肯定会引发回流。

display:inline-block 什么时候会显示间隙?

  • 有空格时会有间隙,能够删除空格解决;
  • margin正值时,能够让 margin 应用负值解决;
  • 应用 font-size 时,可通过设置 font-size:0letter-spacingword-spacing 解决;

事件流传机制(事件流)

冒泡和捕捉

说一说前端性能优化计划

三个方面来阐明前端性能优化
一:webapck 优化与开启 gzip 压缩
    1.babel-loader 用 include 或 exclude 来帮咱们防止不必要的转译,不转译 node_moudules 中的 js 文件
    其次在缓存以后转译的 js 文件,设置 loader: 'babel-loader?cacheDirectory=true'    2. 文件采纳按需加载等等    3. 具体的做法非常简单,只须要你在你的 request headers 中加上这么一句:accept-encoding:gzip    4. 图片优化,采纳 svg 图片或者字体图标    5. 浏览器缓存机制,它又分为强缓存和协商缓存二:本地存储——从 Cookie 到 Web Storage、IndexedDB    阐明一下 SessionStorage 和 localStorage 还有 cookie 的区别和优缺点三:代码优化    1. 事件代理    2. 事件的节流和防抖    3. 页面的回流和重绘    4.EventLoop 事件循环机制    5. 代码优化等等

防抖

防抖(debounce):触发高频事件 N 秒后只会执行一次,如果 N 秒内事件再次触发,则会从新计时。相似王者光荣的回城性能,你重复触发回城性能,那么只认最初一次,从最初一次触发开始计时。

核心思想 :每次事件触发就 革除原来的定时器,建设新的定时器。应用 apply 或 call 调用传入的函数。函数外部反对应用 this 和 event 对象;

利用 :防抖常利用于用户进行搜寻输出节约申请资源,window 触发 resize 事件时进行防抖只触发一次。

实现

function debounce(fn, delay) {
    // 利用闭包的原理
    let timer = null;
    return function(...args){if(timer) clearTimeout(timer);
        timer = setTimeout(() => {
            // 扭转 this 指向为调用 debounce 所指的对象
            fn.call(this, ...args);
            // fn.apply(this, args);
        }, delay);
    }
}

哪些状况会导致内存透露

1、意外的全局变量:因为应用未声明的变量, 而意外的创立了一个全局变量, 而使这个变量始终留在内存中无奈被回收
2、被忘记的计时器或回调函数:设置了 setInterval 定时器,而遗记勾销它,如果循环函数有对外部变量的援用的话,那么这个变量会被始终留在内存中,而无奈被回收。3、脱离 DOM 的援用:获取一个 DOM 元素的援用,而前面这个元素被删除,因为始终保留了对这个元素的援用,所以它也无奈被回收。4、闭包:不合理的应用闭包,从而导致某些变量始终被留在内存当中。

手写 bind、apply、call

// call

Function.prototype.call = function (context, ...args) {
  context = context || window;

  const fnSymbol = Symbol("fn");
  context[fnSymbol] = this;

  context[fnSymbol](...args);
  delete context[fnSymbol];
}
// apply

Function.prototype.apply = function (context, argsArr) {
  context = context || window;

  const fnSymbol = Symbol("fn");
  context[fnSymbol] = this;

  context[fnSymbol](...argsArr);
  delete context[fnSymbol];
}
// bind

Function.prototype.bind = function (context, ...args) {
  context = context || window;
  const fnSymbol = Symbol("fn");
  context[fnSymbol] = this;

  return function (..._args) {args = args.concat(_args);

    context[fnSymbol](...args);
    delete context[fnSymbol];   
  }
}

正文完
 0