关于javascript:20道高级前端面试题解析

6次阅读

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

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

解构是 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

代码输入后果

var length = 10;
function fn() {console.log(this.length);
}

var obj = {
  length: 5,
  method: function(fn) {fn();
    arguments[0]();}
};

obj.method(fn, 1);

输入后果:10 2

解析:

  1. 第一次执行 fn(),this 指向 window 对象,输入 10。
  2. 第二次执行 arguments[0],相当于 arguments 调用办法,this 指向 arguments,而这里传了两个参数,故输入 arguments 长度为 2。

说一下 HTTP 和 HTTPS 协定的区别?

1、HTTPS 协定须要 CA 证书, 费用较高; 而 HTTP 协定不须要
2、HTTP 协定是超文本传输协定, 信息是明文传输的,HTTPS 则是具备安全性的 SSL 加密传输协定;
3、应用不同的连贯形式, 端口也不同,HTTP 协定端口是 80,HTTPS 协定端口是 443;
4、HTTP 协定连贯很简略, 是无状态的;HTTPS 协定是具备 SSL 和 HTTP 协定构建的可进行加密传输、身份认证的网络协议, 比 HTTP 更加平安

说一下购物车的逻辑?

//vue 中购物车逻辑的实现
1. 购物车信息用一个数组来存储,数组中保留对象,对象中有 id 和 count 属性

2. 在 vuex 中 state 中增加一个数据 cartList 用来保留这个数组

3. 因为商品详情页须要用到退出购物车性能,所以咱们须要提供一个 mutation, 用来将购物车信息退出 cartList 中

4. 退出购物车信息的时候,遵循如下规定:如果购物车中曾经有了该商品信息,则数量累加,如果没有该商品信息,则新增一个对象

5. 在商品详情页,点击退出购物车按钮的时候,调用 vuex 提供的 addToCart 这个 mutation 将以后的商品信息(id count)传给 addTocart  this.$store.commit("addToCart", {id:  , count:})

// js 中购物车逻辑的实现
1. 商品页点击“退出购物车”按钮,触发事件

2. 事件调用购物车“减少商品”的 Js 程序(函数、对象办法)3. 向 Js 程序传递传递“商品 id”、“商品数量”等数据

4. 存储“商品 id”、“商品数量”到浏览器的 localStorage 中

** 展现购物车中的商品 ******

1. 关上购物车页面

2. 从 localStorage 中取出“商品 Id”、“商品数量”等信息。3. 调用服务器端“取得商品详情”的接口失去购物车中的商品信息(参数为商品 Id)4. 将取得的商品信息显示在购物车页面。** 实现购物车中商品的购买 ******

1. 用户对购物车中的商品实现购买流程,产生购物订单

2. 革除 localStorage 中存储的曾经购买的商品信息

备注 1:购物车中商品存储的数据除了“商品 id”、“商品数量”之外,依据产品要求还能够有其余的信息,例如残缺的商品详情(这样就不必掉服务器接口取得详情了)、购物车商品的过期工夫,超过工夫的购物车商品在下次关上网站或者购物车页面时被革除。备注 2:购物车商品除了存储在 localStorage 中,依据产品的需要不同,也能够存储在 sessionStorage、cookie、session 中,或者间接向服务器接口发动申请存储在服务器上。何种状况应用哪种形式存储、有啥区别请本人剖析。

如果一个构造函数,bind 了一个对象,用这个构造函数创立出的实例会继承这个对象的属性吗?为什么?

不会继承,因为依据 this 绑定四大规定,new 绑定的优先级高于 bind 显示绑定,通过 new 进行结构函数调用时,会创立一个新对象,这个新对象会代替 bind 的对象绑定,作为此函数的 this,并且在此函数没有返回对象的状况下,返回这个新建的对象

10 个 Ajax 同时发动申请,全副返回展现后果,并且至少容许三次失败,说出设计思路

这个问题置信很多人会第一工夫想到 Promise.all,然而这个函数有一个局限在于如果失败一次就返回了,间接这样实现会有点问题,须要变通下。以下是两种实现思路

// 以下是不残缺代码,着重于思路 非 Promise 写法
let successCount = 0
let errorCount = 0
let datas = []
ajax(url, (res) => {if (success) {
         success++
         if (success + errorCount === 10) {console.log(datas)
         } else {datas.push(res.data)
         }
     } else {
         errorCount++
         if (errorCount > 3) {
            // 失败次数大于 3 次就应该报错了
             throw Error('失败三次')
         }
     }
})
// Promise 写法
let errorCount = 0
let p = new Promise((resolve, reject) => {if (success) {resolve(res.data)
     } else {
         errorCount++
         if (errorCount > 3) {
            // 失败次数大于 3 次就应该报错了
            reject(error)
         } else {resolve(error)
         }
     }
})
Promise.all([p]).then(v => {console.log(v);
});

Loader 和 Plugin 有什么区别

Loader:直译为 ” 加载器 ”。Webpack 将所有文件视为模块,然而 webpack 原生是只能解析 js 文件,如果想将其余文件也打包的话,就会用到loader。所以 Loader 的作用是让 webpack 领有了加载和解析非 JavaScript 文件的能力。Plugin:直译为 ” 插件 ”。Plugin 能够扩大 webpack 的性能,让 webpack 具备更多的灵活性。在 Webpack 运行的生命周期中会播送出许多事件,Plugin 能够监听这些事件,在适合的机会通过 Webpack 提供的 API 扭转输入后果。

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

数组扁平化

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);

HTML5 有哪些更新

1. 语义化标签

  • header:定义文档的页眉(头部);
  • nav:定义导航链接的局部;
  • footer:定义文档或节的页脚(底部);
  • article:定义文章内容;
  • section:定义文档中的节(section、区段);
  • aside:定义其所处内容之外的内容(侧边);

2. 媒体标签

(1)audio:音频

<audio src=''controls autoplay loop='true'></audio>

属性:

  • controls 控制面板
  • autoplay 自动播放
  • loop=‘true’循环播放

(2)video 视频

<video src=''poster='imgs/aa.jpg' controls></video>

属性:

  • poster:指定视频还没有齐全下载结束,或者用户还没有点击播放前显示的封面。默认显示以后视频文件的第一针画面,当然通过 poster 也能够本人指定。
  • controls 控制面板
  • width
  • height

(3)source 标签
因为浏览器对视频格式反对水平不一样,为了可能兼容不同的浏览器,能够通过 source 来指定视频源。

<video>
     <source src='aa.flv' type='video/flv'></source>
     <source src='aa.mp4' type='video/mp4'></source>
</video>

3. 表单

表单类型:

  • email:可能验证以后输出的邮箱地址是否非法
  • url:验证 URL
  • number:只能输出数字,其余输出不了,而且自带高低增大减小箭头,max 属性能够设置为最大值,min 能够设置为最小值,value 为默认值。
  • search:输入框前面会给提供一个小叉,能够删除输出的内容,更加人性化。
  • range:能够提供给一个范畴,其中能够设置 max 和 min 以及 value,其中 value 属性能够设置为默认值
  • color:提供了一个色彩拾取器
  • time:时分秒
  • data:日期抉择年月日
  • datatime:工夫和日期(目前只有 Safari 反对)
  • datatime-local:日期工夫控件
  • week:周控件
  • month:月控件

表单属性:

  • placeholder:提示信息
  • autofocus:主动获取焦点
  • autocomplete=“on”或者 autocomplete=“off”应用这个属性须要有两个前提:

    • 表单必须提交过
    • 必须有 name 属性。
  • required:要求输入框不能为空,必须有值才可能提交。
  • pattern=” ” 外面写入想要的正则模式,例如手机号 patte=”^(+86)?\d{10}$”
  • multiple:能够抉择多个文件或者多个邮箱
  • form=” form 表单的 ID”

表单事件:

  • oninput 每当 input 里的输入框内容发生变化都会触发此事件。
  • oninvalid 当验证不通过时触发此事件。

4. 进度条、度量器

  • progress 标签:用来示意工作的进度(IE、Safari 不反对),max 用来示意工作的进度,value 示意已实现多少
  • meter 属性:用来显示残余容量或残余库存(IE、Safari 不反对)

    • high/low:规定被视作高 / 低的范畴
    • max/min:规定最大 / 小值
    • value:规定以后度量值

设置规定:min < low < high < max

5.DOM 查问操作

  • document.querySelector()
  • document.querySelectorAll()

它们抉择的对象能够是标签,能够是类(须要加点),能够是 ID(须要加 #)

6. Web 存储

HTML5 提供了两种在客户端存储数据的新办法:

  • localStorage – 没有工夫限度的数据存储
  • sessionStorage – 针对一个 session 的数据存储

7. 其余

  • 拖放:拖放是一种常见的个性,即抓取对象当前拖到另一个地位。设置元素可拖放:
<img draggable="true" />
  • 画布(canvas):canvas 元素应用 JavaScript 在网页上绘制图像。画布是一个矩形区域,能够管制其每一像素。canvas 领有多种绘制门路、矩形、圆形、字符以及增加图像的办法。
<canvas id="myCanvas" width="200" height="100"></canvas>
  • SVG:SVG 指可伸缩矢量图形,用于定义用于网络的基于矢量的图形,应用 XML 格局定义图形,图像在放大或扭转尺寸的状况下其图形品质不会有损失,它是万维网联盟的规范
  • 天文定位:Geolocation(天文定位)用于定位用户的地位。‘

总结:(1)新增语义化标签:nav、header、footer、aside、section、article
(2)音频、视频标签:audio、video
(3)数据存储:localStorage、sessionStorage
(4)canvas(画布)、Geolocation(天文定位)、websocket(通信协议)
(5)input 标签新增属性:placeholder、autocomplete、autofocus、required
(6)history API:go、forward、back、pushstate

移除的元素有:

  • 纯体现的元素:basefont,big,center,font, s,strike,tt,u;
  • 对可用性产生负面影响的元素:frame,frameset,noframes;

行内元素有哪些?块级元素有哪些?空 (void) 元素有那些?

  • 行内元素有:a b span img input select strong
  • 块级元素有:div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p

空元素,即没有内容的 HTML 元素。空元素是在开始标签中敞开的,也就是空元素没有闭合标签:

  • 常见的有:<br><hr><img><input><link><meta>
  • 鲜见的有:<area><base><col><colgroup><command><embed><keygen><param><source><track><wbr>

用过 TypeScript 吗?它的作用是什么?

为 JS 增加类型反对,以及提供最新版的 ES 语法的反对,是的利于团队合作和排错,开发大型项目

说一下 data 为什么是一个函数而不是一个对象?

JavaScript 中的对象是援用类型的数据,当多个实例援用同一个对象时,只有一个实例对这个对象进行操作,其余实例中的数据也会发生变化。而在 Vue 中,咱们更多的是想要复用组件,那就须要每个组件都有本人的数据,这样组件之间才不会互相烦扰。所以组件的数据不能写成对象的模式,而是要写成函数的模式。数据以函数返回值的模式定义,这样当咱们每次复用组件的时候,就会返回一个新的 data,也就是说每个组件都有本人的公有数据空间,它们各自保护本人的数据,不会烦扰其余组件的失常运行。

代码输入后果

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.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)])
  .then(res => console.log("result:", res))
  .catch(err => console.log(err));

输入后果如下:

0
Error: 0
1
2
3

能够看到在 catch 捕捉到第一个谬误之后,前面的代码还不执行,不过不会再被捕捉了。

留神:allrace 传入的数组中如果有会抛出异样的异步工作,那么只有最先抛出的谬误会被捕捉,并且是被 then 的第二个参数或者前面的 catch 捕捉;但并不会影响数组中其它的异步工作的执行。

晓得 ES6 的 Class 嘛?Static 关键字有理解嘛

为这个类的函数对象间接增加办法,而不是加在这个函数对象的原型对象上

动静布局求解硬币找零问题

题目形容: 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算能够凑成总金额所需的起码的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1

示例 1:输出: coins = [1, 2, 5], amount = 11
输入: 3
解释: 11 = 5 + 5 + 1

示例 2:输出: coins = [2], amount = 3
输入: -1

实现代码如下:

const coinChange = function (coins, amount) {
  // 用于保留每个指标总额对应的最小硬币个数
  const f = [];
  // 提前定义已知状况
  f[0] = 0;
  // 遍历 [1, amount] 这个区间的硬币总额
  for (let i = 1; i <= amount; i++) {
    // 求的是最小值,因而咱们预设为无穷大,确保它肯定会被更小的数更新
    f[i] = Infinity;
    // 循环遍历每个可用硬币的面额
    for (let j = 0; j < coins.length; j++) {
      // 若硬币面额小于指标总额,则问题成立
      if (i - coins[j] >= 0) {
        // 状态转移方程
        f[i] = Math.min(f[i], f[i - coins[j]] + 1);
      }
    }
  }
  // 若指标总额对应的解为无穷大,则意味着没有一个符合条件的硬币总数来更新它,本题无解,返回 -1
  if (f[amount] === Infinity) {return -1;}
  // 若有解,间接返回解的内容
  return f[amount];
};

JS 隐式转换,显示转换

个别非根底类型进行转换时会先调用 valueOf,如果 valueOf 无奈返回根本类型值,就会调用 toString

字符串和数字

  • “+” 操作符,如果有一个为字符串,那么都转化到字符串而后执行字符串拼接
  • “-” 操作符,转换为数字,相减 (-a, a * 1 a/1) 都能进行隐式强制类型转换
[] + {} 和 {} + []

布尔值到数字

  • 1 + true = 2
  • 1 + false = 1

转换为布尔值

  • for 中第二个
  • while
  • if
  • 三元表达式
  • ||(逻辑或)&&(逻辑与)右边的操作数

符号

  • 不能被转换为数字
  • 能被转换为布尔值(都是 true)
  • 能够被转换成字符串 “Symbol(cool)”

宽松相等和严格相等

宽松相等容许进行强制类型转换,而严格相等不容许

字符串与数字

转换为数字而后比拟

其余类型与布尔类型

  • 先把布尔类型转换为数字,而后持续进行比拟

对象与非对象

  • 执行对象的 ToPrimitive(对象)而后持续进行比拟

假值列表

  • undefined
  • null
  • false
  • +0, -0, NaN
  • “”

代码输入后果

function a() {console.log(this);
}
a.call(null);

打印后果:window 对象

依据 ECMAScript262 标准规定:如果第一个参数传入的对象调用者是 null 或者 undefined,call 办法将把全局对象(浏览器上是 window 对象)作为 this 的值。所以,不论传入 null 还是 undefined,其 this 都是全局对象 window。所以,在浏览器上答案是输入 window 对象。

要留神的是,在严格模式中,null 就是 null,undefined 就是 undefined:

'use strict';

function a() {console.log(this);
}
a.call(null); // null
a.call(undefined); // undefined

说一下常见的 git 操作

git branch 查看本地所有分支
git status 查看以后状态 
git commit 提交 
git branch -a 查看所有的分支
git branch -r 查看近程所有分支
git commit -am "nit" 提交并且加正文 
git remote add origin [email protected]:ndshow
git push origin master 将文件给推到服务器上 
git remote show origin 显示近程库 origin 里的资源 
git push origin master:develop
git push origin master:hb-dev 将本地库与服务器上的库进行关联 
git checkout --track origin/dev 切换到近程 dev 分支
git branch -D master develop 删除本地库 develop
git checkout -b dev 建设一个新的本地分支 dev
git merge origin/dev 将分支 dev 与以后分支进行合并
git checkout dev 切换到本地 dev 分支
git remote show 查看近程库
git add .
git rm 文件名(包含门路) 从 git 中删除指定文件
git clone git://github.com/schacon/grit.git 从服务器上将代码给拉下来
git config --list 看所有用户
git ls-files 看曾经被提交的
git rm [file name] 删除一个文件
git commit -a 提交以后 repos 的所有的扭转
git add [file name] 增加一个文件到 git index
git commit -v 当你用-v 参数的时候能够看 commit 的差别
git commit -m "This is the message describing the commit" 增加 commit 信息
git commit -a - a 是代表 add,把所有的 change 加到 git index 里而后再 commit
git commit -a -v 个别提交命令
git log 看你 commit 的日志
git diff 查看尚未暂存的更新
git rm a.a 移除文件(从暂存区和工作区中删除)
git rm --cached a.a 移除文件(只从暂存区中删除)
git commit -m "remove" 移除文件(从 Git 中删除)
git rm -f a.a 强行移除批改后文件(从暂存区和工作区中删除)
git diff --cached 或 $ git diff --staged 查看尚未提交的更新
git stash push 将文件给 push 到一个长期空间中
git stash pop 将文件从长期空间 pop 下来

代码输入后果

const promise = Promise.resolve().then(() => {return promise;})
promise.catch(console.err)

输入后果如下:

Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>

这里其实是一个坑,.then.catch 返回的值不能是 promise 自身,否则会造成死循环。

事件流

事件流是网页元素接管事件的程序,”DOM2 级事件 ” 规定的事件流包含三个阶段:事件捕捉阶段、处于指标阶段、事件冒泡阶段。
首先产生的事件捕捉,为截获事件提供机会。而后是理论的指标承受事件。最初一个阶段是工夫冒泡阶段,能够在这个阶段对事件做出响应。
尽管捕捉阶段在标准中规定不容许响应事件,然而实际上还是会执行,所以有两次机会获取到指标对象。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title> 事件冒泡 </title>
</head>
<body>
    <div>
        <p id="parEle"> 我是父元素    <span id="sonEle"> 我是子元素 </span></p>
    </div>
</body>
</html>
<script type="text/javascript">
var sonEle = document.getElementById('sonEle');
var parEle = document.getElementById('parEle');parEle.addEventListener('click', function () {alert('父级 冒泡');}, false);parEle.addEventListener('click', function () {alert('父级 捕捉');}, true);sonEle.addEventListener('click', function () {alert('子级冒泡');}, false);sonEle.addEventListener('click', function () {alert('子级捕捉');}, true);

</script>

当容器元素及嵌套元素,即在 捕捉阶段 又在 冒泡阶段 调用事件处理程序时:事件按 DOM 事件流的程序 执行事件处理程序:

  • 父级捕捉
  • 子级捕捉
  • 子级冒泡
  • 父级冒泡

且当事件处于指标阶段时,事件调用程序决定于绑定事件的 书写程序,按下面的例子为,先调用冒泡阶段的事件处理程序,再调用捕捉阶段的事件处理程序。顺次 alert 出“子集冒泡”,“子集捕捉”。

正文完
 0