关于前端:高级前端一面必会面试题合集

41次阅读

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

let 闭包

let 会产生临时性死区,在以后的执行上下文中,会进行变量晋升,然而未被初始化,所以在执行上下文执行阶段,执行代码如果还没有执行到变量赋值,就援用此变量就会报错,此变量未初始化。

单例模式

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

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

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

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

实现

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

如何依据设计稿进行挪动端适配?

挪动端适配次要有两个维度:

  • 适配不同像素密度, 针对不同的像素密度,应用 CSS 媒体查问,抉择不同精度的图片,以保障图片不会失真;
  • 适配不同屏幕大小, 因为不同的屏幕有着不同的逻辑像素大小,所以如果间接应用 px 作为开发单位,会使得开发的页面在某一款手机上能够精确显示,然而在另一款手机上就会失真。为了适配不同屏幕的大小,应依照比例来还原设计稿的内容。

为了能让页面的尺寸自适应,能够应用 rem,em,vw,vh 等绝对单位。

如何提取高度嵌套的对象里的指定属性?

有时会遇到一些嵌套水平十分深的对象:

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

像此处的 name 这个变量,嵌套了四层,此时如果依然尝试老办法来提取它:

const {name} = school

显然是不见效的,因为 school 这个对象自身是没有 name 这个属性的,name 位于 school 对象的“儿子的儿子”对象外面。要想把 name 提取进去,一种比拟笨的办法是逐层解构:

const {classes} = school
const {stu} = classes
const {name} = stu
name // 'Bob'

然而还有一种更规范的做法,能够用一行代码来解决这个问题:

const {classes: { stu: { name} }} = school

console.log(name)  // 'Bob'

能够在解构进去的变量名右侧,通过冒号 +{指标属性名}这种模式,进一步解构它,始终解构到拿到指标数据为止。

网络劫持有哪几种,如何防备?

⽹络劫持分为两种:

(1)DNS 劫持: (输⼊京东被强制跳转到淘宝这就属于 dns 劫持)

  • DNS 强制解析: 通过批改运营商的本地 DNS 记录,来疏导⽤户流量到缓存服务器
  • 302 跳转的⽅式: 通过监控⽹络出⼝的流量,分析判断哪些内容是能够进⾏劫持解决的, 再对劫持的内存发动 302 跳转的回复,疏导⽤户获取内容

(2)HTTP 劫持: (拜访⾕歌然而⼀直有贪玩蓝⽉的⼴告), 因为 http 明⽂传输, 运营商会批改你的 http 响应内容(即加⼴告)

DNS 劫持因为涉嫌守法,曾经被监管起来,当初很少会有 DNS 劫持,⽽ http 劫持仍然⾮常盛⾏,最无效的方法就是全站 HTTPS,将 HTTP 加密,这使得运营商⽆法获取明⽂,就⽆法劫持你的响应内容。

数字证书是什么?

当初的办法也不肯定是平安的,因为没有方法确定失去的公钥就肯定是平安的公钥。可能存在一个中间人,截取了对方发给咱们的公钥,而后将他本人的公钥发送给咱们,当咱们应用他的公钥加密后发送的信息,就能够被他用本人的私钥解密。而后他伪装成咱们以同样的办法向对方发送信息,这样咱们的信息就被窃取了,然而本人还不晓得。为了解决这样的问题,能够应用数字证书。

首先应用一种 Hash 算法来对公钥和其余信息进行加密,生成一个信息摘要,而后让有公信力的认证核心(简称 CA)用它的私钥对音讯摘要加密,造成签名。最初将原始的信息和签名合在一起,称为数字证书。当接管方收到数字证书的时候,先依据原始信息应用同样的 Hash 算法生成一个摘要,而后应用公证处的公钥来对数字证书中的摘要进行解密,最初将解密的摘要和生成的摘要进行比照,就能发现失去的信息是否被更改了。

这个办法最要的是认证核心的可靠性,个别浏览器里会内置一些顶层的认证核心的证书,相当于咱们主动信赖了他们,只有这样能力保证数据的平安。

map 和 foreach 有什么区别

foreach()办法会针对每一个元素执行提供得函数, 该办法没有返回值, 是否会扭转原数组取决与数组元素的类型是根本类型还是援用类型
map()办法不会扭转原数组的值, 返回一个新数组, 新数组中的值为原数组调用函数解决之后的值:

说一下常见的 git 操作

git branch 查看本地所有分支
git status 查看以后状态 
git commit 提交 
git branch -a 查看所有的分支
git branch -r 查看近程所有分支
git commit -am "nit" 提交并且加正文 
git remote add origin git@192.168.1.119: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 下来

常见的 HTTP 申请头和响应头

HTTP Request Header 常见的申请头:

  • Accept: 浏览器可能解决的内容类型
  • Accept-Charset: 浏览器可能显示的字符集
  • Accept-Encoding:浏览器可能解决的压缩编码
  • Accept-Language:浏览器以后设置的语言
  • Connection:浏览器与服务器之间连贯的类型
  • Cookie:以后页面设置的任何 Cookie
  • Host:发出请求的页面所在的域
  • Referer:发出请求的页面的 URL
  • User-Agent:浏览器的用户代理字符串

HTTP Responses Header 常见的响应头:

  • Date:示意音讯发送的工夫,工夫的形容格局由 rfc822 定义
  • server: 服务器名称
  • Connection:浏览器与服务器之间连贯的类型
  • Cache-Control:管制 HTTP 缓存
  • content-type: 示意前面的文档属于什么 MIME 类型

常见的 Content-Type 属性值有以下四种:

(1)application/x-www-form-urlencoded:浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 形式提交数据。该种形式提交的数据放在 body 外面,数据依照 key1=val1&key2=val2 的形式进行编码,key 和 val 都进行了 URL 转码。

(2)multipart/form-data:该种形式也是一个常见的 POST 提交形式,通常表单上传文件时应用该种形式。

(3)application/json:服务器音讯主体是序列化后的 JSON 字符串。

(4)text/xml:该种形式次要用来提交 XML 格局的数据。

webpack 配置入口进口

module.exports={
    // 入口文件的配置项
    entry:{},
    // 进口文件的配置项
    output:{},
    // 模块:例如解读 CSS, 图片如何转换,压缩
    module:{},
    // 插件,用于生产模版和各项性能
    plugins:[],
    // 配置 webpack 开发服务性能
    devServer:{}}
简略形容了一下这几个属性是干什么的。形容一下 npm run dev / npm run build 执行的是哪些文件
通过配置 proxyTable 来达到开发环境跨域的问题,而后又能够扩大和他聊聊跨域的产生,如何跨域
最初能够在聊聊 webpack 的优化,例如 babel-loader 的优化,gzip 压缩等等

什么是原型什么是原型链?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

</body>
<script>
    function Person () {}    var person  = new Person();    person.name = 'Kevin';    console.log(person.name) // Kevin

    // prototype
    function Person () {}    Person.prototype.name = 'Kevin';    var person1 = new Person();    var person2 = new Person();    console.log(person1.name)// Kevin
    console.log(person2.name)// Kevin

    // __proto__
    function Person () {}    var person = new Person();    console.log(person.__proto__ === Person.prototype) // true

    //constructor
    function Person() {}    console.log(Person === Person.prototype.constructor) // true

    // 综上所述
    function Person () {}    var person = new Person()    console.log(person.__proto__ == Person.prototype) // true
    console.log(Person.prototype.constructor == Person) // true
    // 顺便学习一下 ES5 得办法, 能够取得对象得原型
    console.log(Object.getPrototypeOf(person) === Person.prototype) // true

    // 实例与原型
    function Person () {}    Person.prototype.name = 'Kevin';    var person = new Person();    person.name = 'Daisy';    console.log(person.name) // Daisy
    delete person.name;    console.log(person.name) // Kevin

    // 原型得原型
    var obj = new Object();    obj.name = 'Kevin',    console.log(obj.name) //Kevin

     // 原型链
     console.log(Object.prototype.__proto__ === null) //true
     // null 示意 "没用对象" 即该处不应该有值

     // 补充
     function Person() {}     var person = new Person()     console.log(person.constructor === Person) // true
     // 当获取 person.constructor 时,其实 person 中并没有 constructor 属性, 当不能读取到 constructor 属性时, 会从 person 的原型
     // 也就是 Person.prototype 中读取时, 正好原型中有该属性, 所以
     person.constructor === Person.prototype.constructor

     //__proto__
     // 其次是__proto__,绝大部分浏览器都反对这个非标准的办法拜访原型,然而它并不存在于 Person.prototype 中,实际上,它
     // 是来自与 Object.prototype, 与其说是一个属性,不如说是一个 getter/setter, 当应用 obj.__proto__时,能够了解成返回了
     // Object.getPrototypeOf(obj)
     总结:1、当一个对象查找属性和办法时会从本身查找, 如果查找不到则会通过__proto__指向被实例化的构造函数的 prototype     2、隐式原型也是一个对象, 是指向咱们构造函数的原型     3、除了最顶层的 Object 对象没有__proto_,其余所有的对象都有__proto__, 这是隐式原型     4、隐式原型__proto__的作用是让对象通过它来始终往上查找属性或办法,直到找到最顶层的 Object 的__proto__属性,它的值是 null, 这个查找的过程就是原型链



</script>
</html>

应用 clear 属性革除浮动的原理?

应用 clear 属性革除浮动,其语法如下:

clear:none|left|right|both

如果单看字面意思,clear:left 是“革除左浮动”,clear:right 是“革除右浮动”,实际上,这种解释是有问题的,因为浮动始终还在,并没有革除。

官网对 clear 属性解释:“元素盒子的边不能和后面的浮动元素相邻”,对元素设置 clear 属性是为了防止浮动元素对该元素的影响,而不是革除掉浮动。

还须要留神 clear 属性指的是元素盒子的边不能和后面的浮动元素相邻,留神这里“后面的”3 个字,也就是 clear 属性对“前面的”浮动元素是充耳不闻的。思考到 float 属性要么是 left,要么是 right,不可能同时存在,同时因为 clear 属性对“前面的”浮动元素充耳不闻,因而,当 clear:left 无效的时候,clear:right 必然有效,也就是此时 clear:left 等同于设置 clear:both;同样地,clear:right 如果无效也是等同于设置 clear:both。由此可见,clear:left 和 clear:right 这两个申明就没有任何应用的价值,至多在 CSS 世界中是如此,间接应用 clear:both 吧。

个别应用伪元素的形式革除浮动:

.clear::after{content:'';  display: block;   clear:both;}

clear 属性只有块级元素才无效的,而::after 等伪元素默认都是内联程度,这就是借助伪元素革除浮动影响时须要设置 display 属性值的起因。

柯里化

题目形容: 柯里化(Currying),又称局部求值(Partial Evaluation),是把承受多个参数的函数变换成承受一个繁多参数(最后函数的第一个参数)的函数,并且返回承受余下的参数而且返回后果的新函数的技术。核心思想是把多参数传入的函数拆成单参数(或局部)函数,外部再返回调用下一个单参数(或局部)函数,顺次解决残余的参数。

实现代码如下:

function currying(fn, ...args) {
  const length = fn.length;
  let allArgs = [...args];
  const res = (...newArgs) => {allArgs = [...allArgs, ...newArgs];
    if (allArgs.length === length) {return fn(...allArgs);
    } else {return res;}
  };
  return res;
}

// 用法如下:// const add = (a, b, c) => a + b + c;
// const a = currying(add, 1);
// console.log(a(2,3))

async/await 如何捕捉异样

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

什么是 CSRF 攻打?

(1)概念

CSRF 攻打指的是 跨站申请伪造攻打,攻击者诱导用户进入一个第三方网站,而后该网站向被攻打网站发送跨站申请。如果用户在被攻打网站中保留了登录状态,那么攻击者就能够利用这个登录状态,绕过后盾的用户验证,假冒用户向服务器执行一些操作。

CSRF 攻打的 实质是利用 cookie 会在同源申请中携带发送给服务器的特点,以此来实现用户的假冒。

(2)攻打类型

常见的 CSRF 攻打有三种:

  • GET 类型的 CSRF 攻打,比方在网站中的一个 img 标签里构建一个申请,当用户关上这个网站的时候就会主动发动提交。
  • POST 类型的 CSRF 攻打,比方构建一个表单,而后暗藏它,当用户进入页面时,主动提交这个表单。
  • 链接类型的 CSRF 攻打,比方在 a 标签的 href 属性里构建一个申请,而后诱导用户去点击。

说一下 HTML5 drag API

  • dragstart:事件主体是被拖放元素,在开始拖放被拖放元素时触发。
  • darg:事件主体是被拖放元素,在正在拖放被拖放元素时触发。
  • dragenter:事件主体是指标元素,在被拖放元素进入某元素时触发。
  • dragover:事件主体是指标元素,在被拖放在某元素内挪动时触发。
  • dragleave:事件主体是指标元素,在被拖放元素移出指标元素是触发。
  • drop:事件主体是指标元素,在指标元素齐全承受被拖放元素时触发。
  • dragend:事件主体是被拖放元素,在整个拖放操作完结时触发。

如何进攻 XSS 攻打?

能够看到 XSS 危害如此之大,那么在开发网站时就要做好进攻措施,具体措施如下:

  • 能够从浏览器的执行来进行预防,一种是应用纯前端的形式,不必服务器端拼接后返回(不应用服务端渲染)。另一种是对须要插入到 HTML 中的代码做好充沛的本义。对于 DOM 型的攻打,次要是前端脚本的不牢靠而造成的,对于数据获取渲染和字符串拼接的时候应该对可能呈现的恶意代码状况进行判断。
  • 应用 CSP,CSP 的实质是建设一个白名单,通知浏览器哪些内部资源能够加载和执行,从而避免恶意代码的注入攻打。
  1. CSP 指的是内容安全策略,它的实质是建设一个白名单,通知浏览器哪些内部资源能够加载和执行。咱们只须要配置规定,如何拦挡由浏览器本人来实现。
  2. 通常有两种形式来开启 CSP,一种是设置 HTTP 首部中的 Content-Security-Policy,一种是设置 meta 标签的形式
  • 对一些敏感信息进行爱护,比方 cookie 应用 http-only,使得脚本无奈获取。也能够应用验证码,防止脚本伪装成用户执行一些操作。

代码输入后果

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 捕捉;但并不会影响数组中其它的异步工作的执行。

对 WebSocket 的了解

WebSocket 是 HTML5 提供的一种浏览器与服务器进行 全双工通信 的网络技术,属于应用层协定。它基于 TCP 传输协定,并复用 HTTP 的握手通道。浏览器和服务器只须要实现一次握手,两者之间就间接能够创立持久性的连贯,并进行双向数据传输。

WebSocket 的呈现就解决了半双工通信的弊病。它最大的特点是:服务器能够向客户端被动推动音讯,客户端也能够被动向服务器推送音讯。

WebSocket 原理:客户端向 WebSocket 服务器告诉(notify)一个带有所有接收者 ID(recipients IDs)的事件(event),服务器接管后立刻告诉所有沉闷的(active)客户端,只有 ID 在接收者 ID 序列中的客户端才会解决这个事件。

WebSocket 特点的如下:

  • 反对双向通信,实时性更强
  • 能够发送文本,也能够发送二进制数据‘’
  • 建设在 TCP 协定之上,服务端的实现比拟容易
  • 数据格式比拟轻量,性能开销小,通信高效
  • 没有同源限度,客户端能够与任意服务器通信
  • 协定标识符是 ws(如果加密,则为 wss),服务器网址就是 URL
  • 与 HTTP 协定有着良好的兼容性。默认端口也是 80 和 443,并且握手阶段采纳 HTTP 协定,因而握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

Websocket 的应用办法如下:

在客户端中:

// 在 index.html 中间接写 WebSocket,设置服务端的端口号为 9999
let ws = new WebSocket('ws://localhost:9999');
// 在客户端与服务端建设连贯后触发
ws.onopen = function() {console.log("Connection open."); 
    ws.send('hello');
};
// 在服务端给客户端发来音讯的时候触发
ws.onmessage = function(res) {console.log(res);       // 打印的是 MessageEvent 对象
    console.log(res.data);  // 打印的是收到的音讯
};
// 在客户端与服务端建设敞开后触发
ws.onclose = function(evt) {console.log("Connection closed.");
}; 

正文完
 0