面试2.2

Browser

DOM事件模型

一:DOM leave1 好比onclick只是一个属性,能够被覆盖,因此一个元素只能有一个onclick事件 写在字符串里至关于运行字符串里的代码javascript

在这里插入图片描述
在这里插入图片描述

二: DOM L2中,事件注册(事件监听队列)css

在这里插入图片描述
**三:**事件触发时传播的方式: 先捕获到最底层, 再冒泡到最上层

  • 冒泡:addEventListener的第三个参数传入 false 或者 不传 参数 儿子,爸爸,爷爷
  • 捕获:addEventListener的第三个参数传入 true 爷爷,爸爸,儿子
    在这里插入图片描述
    冒泡和捕获的执行顺序不受代码顺序控制。只有同一个元素的事件队列才受于代码中的事件绑定顺序有关
  • 阻止冒泡 event.stopPropagation()。stopPropagation,中止传播,不要再告诉父母了,不要再往上执行冒泡事件了
  • 禁止默认效果与阻止冒泡
    aTag.addEventListener("click",function(e){
       e.preventDefault();//禁止默认效果
       e.stopPropagation();//阻止冒泡
    });
    
    复制代码

事件触发通常来讲会按照上面的顺序进行,可是也有特例,若是给一个目标节点同时注册冒泡和捕获事件,事件触发会按照注册的顺序执行。html

// 如下会先打印冒泡而后是捕获
node.addEventListener('click',(event) =>{
    console.log('冒泡')
},false);
node.addEventListener('click',(event) =>{
    console.log('捕获 ')
},true)

复制代码

四:事件委托(事件代理) 事件代理 若是一个节点中的子节点是动态生成的,那么子节点须要注册事件的话应该注册在父节点上前端

<ul id="ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
<script>
    let ul = document.querySelector('##ul')
    ul.addEventListener('click', (event) => {
        console.log(event.target);//li
        console.log(event.currentTarget)//ul
    })
</script>

复制代码

事件代理的方式相对于直接给目标注册事件来讲,有节省内存的优势 event.target和event.currentTarget的区别: event.target是点击到的最底层的那个元素 event.currentTarget是注册事件注册在那个元素上,那个元素就是currentTarget,因此通常是父元素java

跨域

1 jsonp

什么能够发送请求?不光form表单能够发送请求,a标签(须要点击),link标签,script,图片,均可以发送请求。 解决先后端耦合:前端要作的事:事先写好成功和失败的函数。成功了就返回给我一个成功的提示,而后我根据提示执行成功的函数,若是给个人提示是失败,就执行失败的函数node

,不能访问。 真名的名字应该是:动态标签跨域请求!即利用动态标签script进行跨域请求的技术。linux

面试官:说说jsonp: 为何要用jsonp? jsonp要解决的是浏览器的跨域数据访问的问题。(两个不一样域名的网站)。 因为同源策略,不一样域名不能发请求。可是HTML的<script>元素是一个例外,script标签的请求不受域名限制的,而Ajax是受域名限制的。 如何使用jsonp?webpack

请求方:mataotao.com的前端(浏览器),一个网站的前端 响应方:jack.com的后端(服务器),另外一个网站的后端 过程:ios

  1. 请求方动态建立一个<script>标签。src指向响应方,同时传一个查询参数?callback=xxxfn
  2. 由于<script>获得响应后会当即执行响应过来的内容。因此响应方根据查询参数构造形如xxxfn("后台传过来的数据")这样的响应。把要传的数据写在callback函数的参数里。
  3. 请求方浏览器接收到响应后, 就会执行xxxfn('后台传过来的数据')来获得后台传过来的数据,并处理。

这就是jsonpgit

jsonp为何不能用post请求 jsonp是经过动态建立script实现的,而script标签发送的是get请求。(缺点,get不安全) 优缺点: JSONP 使用简单且兼容性不错,可是只限于 get 请求

返回的状态码: 2开头:成功 3开头:重定向 4开头:客户端错误 5开头:服务器错误

Ajax

用 form 能够发get或post或其余请求,可是会刷新页面或新开页面 用 a 能够发 get 请求,可是也会刷新页面或新开页面 用 img 能够发 get 请求,可是只能以图片的形式展现 用 link 能够发 get 请求,可是只能以 CSS、favicon 的形式展现 用 script 能够发 get 请求,可是只能以脚本的形式运行。 上面几个均可以发请求,可是各有缺点。

说说Ajax: Ajax 是JS 能够用直接发起 任意HTTP 请求的技术。

  1. AJAX 经过原生的XMLHttpRequest对象发出 HTTP 请求
  2. 从服务器获取响应数据后,能够局部更新当前网页,而不用刷新。 使用方法:

具体来讲,AJAX 包括如下几个步骤。

  • 建立 XMLHttpRequest 实例
  • 发出 HTTP 请求
  • 接收服务器传回的数据
  • 更新网页数据

面试问题:请使用原生JS发送Ajax请求 通常面试大几率会问这个问题,写不对必定过不了面试

下面四句代码必定要记住:

myButton.addEventListener("click",(e)=>{
  //这四句必定要记住
  let request = new XMLHttpRequest();
  request.onreadystatechange = ()=>{
    request.onreadystatechange = ()=>{
      if(request.readyState ===4){//Ajax状态码为4
        console.log("请求和响应都完毕了");
        if ( request.status>=200&&request.status<300){//响应成功(http状态码)
          console.log(request.responseText);//打印响应的第四部分,字符串
        }else if(request.status>=400){
          console.log("响应失败");
        }
      } 
    }
  }
  request.open('GET','/xxx')//配置request.参数分别为方法和路径
  request.setRequestHeader('content-type','x-www-form-urlencoded')//设置响应头必定要写在
  request.send("a=1&b=2");//发送请求
  //这四句必定要记住
})

复制代码

同源策略和CORS(跨域)

什么是同源策略?formaimglinkscript、均可以跨域发送请求。 可是只有 协议+域名+端口 如出一辙才容许发 AJAX 请求为何要有同源策略? 简单地说就是例如使用form发送请求后,就会刷新页面,因此原页面没有了,就认为是安全的.可是Ajax能够吧响应内容读取了.而且显示在本页面上.因此出现安全性问题。

Ajax没法跨域报的错误:

在这里插入图片描述

CORS的英文Cross-Origin Resource Sharing,即跨域(源,站)资源共享(跨域) 那么如何使用CORS突破同源策略解决Ajax的没法跨域发送请求的问题?

只要服务器端设置响应头就能够实现跨域:

response.setHeader('Access-Control-Allow-Origin','http://mataotao.com:8001')
复制代码

这句话是CORS跨域(突破同源策略)的核心,即容许别的网站(例如http://mataotao.com:8001)跨域向我发Ajax请求,而且容许响应。

为何不使用jsonp,而是用CORS来跨域? CORS相对于JSONP,CORS能够发任意请求,而JSONP只能发送get请求

JSON 和 JS 对象互转

要实现从对象转换为 JSON 字符串,使用 JSON.stringify() 方法:

var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}'
复制代码

要实现从 JSON 转换为对象,使用 JSON.parse() 方法:

var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}
复制代码

Cookie

Cookie 是服务器保存在浏览器的一小段文本信息。浏览器每次向服务器发出请求,就会自动附上这段信息。 Cookie的做用过程:

  1. 第一次登陆的时候,服务器经过 Set-Cookie 响应头设置 Cookie,而后以响应的形式发给浏览器
  2. 浏览器获得 响应中Cookie 以后,以后每次请求这个域名都要带上这个 Cookie
  3. 以后服务器读取当时本身设置的 Cookie 就知道用户的信息(好比用户名,是不是同一个浏览器等)

COokie的做用:

  1. 分辨两个请求是否来自同一个浏览器
  2. 用来保存一些状态信息,例如:保存登陆、购物车等须要记录的信息。

HTTP 回应:Cookie 的生成(服务器端生成cookies)

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

[page content]
复制代码
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly
复制代码

HTTP 请求:Cookie 的发送(浏览器发送Cookie)

浏览器向服务器发送 HTTP 请求时,每一个请求都会带上相应的 Cookie。也就是说,把服务器早前保存在浏览器的这段信息,再发回服务器。这时要使用 HTTP 头信息的Cookie字段。

Cookie: foo=bar
复制代码

上面代码会向服务器发送名为foo的 Cookie,值为bar。

Cookie字段能够包含多个 Cookie,使用分号(;)分隔。

Cookie: name=value; name2=value2; name3=value3
复制代码

下面是一个Http请求的例子。

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
复制代码

读、写、删除、Cookie

  1. document.cookie,前提是该 Cookie 不能有HTTPOnly属性。

  2. document.cookie写入 Cookie 的例子以下。

document.cookie = 'fontSize=14; '
  + 'expires=' + someDate.toGMTString() + '; '
  + 'path=/subdirectory; '
  + 'domain=*.example.com';
复制代码
  1. Cookie 的删除 删除一个现存 Cookie 的惟一方法,是设置它的expires属性为一个过去的日期

session

什么是session?

  1. 服务器经过Cookie发送给客户端一个sessionID
  2. sessionID对应服务器里的一小块内存,这里保存着用户的信息,例如登陆信息,购物车信息等。
  3. 每次用户访问服务器的时候,服务器经过浏览器发送来的cookie里的sessionID去读取对应的内存里的信息,以此来知道用户的隐私信息。

Storage

window.sessionStoragewindow.localStorage接口用于脚本在浏览器保存数据。

基本使用

设置

window.sessionStorage.setItem('key', 'value');
window.localStorage.setItem('key', 'value');
复制代码

获取

window.sessionStorage.getItem('key')
window.localStorage.getItem('key')
复制代码

清除

localStorage.removeItem('key');
window.localStorage.clear()
复制代码

总结

注意只能存字符串类型的。

  1. LocalStorage 跟 HTTP 无关(而cookie是http的一个头)
  2. 发送HTTP请求时 不会带上 LocalStorage 的值
  3. 只有相同域名的页面才能互相读取 LocalStorage(没有同源那么严格)
  4. 每一个域名 localStorage 最大存储量为 5Mb 左右(每一个浏览器不同)
  5. 经常使用场景:记录有没有提示过用户(没有用的信息,不能记录密码)
  6. LocalStorage 永久有效,除非用户主动清理缓存

区别:SessionStorage 在用户关闭页面(会话结束)后就失效。其他的和localstorage同样

Cookie和Storage对比:

在这里插入图片描述

HTTP缓存

HTTP缓存有利于web性能优化。HTTP缓存能够重复利用以前获取的资源而不用反复请求,以达到性能优化的目的。 方法

1 Cache-Control

在响应里设置响应头 Cache-Control: max-age=30 意思就是30秒以内,浏览器再访问相同的URL的时候,就不发请求,直接从内存里拿到已经缓存的main.js。 问题:那么js和css更新了怎么办? 浏览器请求时发现是相同的URL才使用缓存,那么能够设置查询参数,例如第二个版本的js能够写<script src="./main.js?v=2"></script>,来保证URL的不一样,从新获取新的js文件。这样便可以缓存好久,又能够随时更新.(总结:设置查询参数,保证URL的不一样)

Expires

  1. Expires 是之前用来控制缓存的http头,Cache-Control是新版的API。

  2. 如今首选 Cache-Control。

  3. 若是在Cache-Control响应头设置了 "max-age" 或者 "s-max-age" 指令,那么 Expires 头会被忽略。

  4. 响应头设置方式: Expires: Wed, 21 Oct 2015 07:28:00 GMT

  5. Expires 响应头包含日期/时间, 即在此时候以后,响应过时。 注意: 由于过时标准的时间用的是本地时间,因此不靠谱,因此要游侠使用Cache-Control代替Expires

答面试官: 与Cache-Control的区别就是:

  1. Cache-Control设置过时时间长度
  2. Expires 设置过时时间点

MD5是消息摘要算法。用于确保信息传输完整一致。能够判断两次信息传输是否完整一致

ETag

例如

  1. 咱们请求一个js文件。设置的ETage响应头为这个JS文件的MD5值
  2. 那么,下一次请求这个JS的时候,浏览器会把上一次响应的那个ETage的值放到If-None-Match请求头里面发送请求。
  3. 若是MD5同样,说明文件没改过,那么返回304

304 Not Modified: HTTP 304 未改变说明无需再次传输请求的内容,也就是说能够使用缓存的内容。

HTTP 304 :没有响应体

ETag与 Cache-Control的区别

  • 因为CSS的请求是用缓存(Cache-Control)的,因此直接不发请求
  • 而js用的ETag,有请求也有响应,只不过若是MD5同样,那么就不下载响应体。

MVC

MVC是一种代码组织形式,只是组织代码的思想.给面试官将MVC

在这里插入图片描述
MVC处理的逻辑顺序。

MVC就是把代码分为三块

  1. V(view)只负责看得见的东西.
  2. M(model)只负责跟数据相关的操做,不会出现DOM,不会出现任何的html/css操做.例如model里只会有初始化数据库,获取数据方法fetch(),保存数据的方法save()
  3. C(controller)只负责把这些view和model组合起来,找到view,找到model,使用model完成数据修改业务,并修改view的显示 V:视图

M,V,C在代码中能够用对象或者类来表示

webpack

曾使用 webpack3 用 babel-loader 把 ES6 转译为 ES5 用 sass-loader 把 SCSS 转译为 CSS 做用:

  1. 自从出现模块化之后,文件变多。每一个 JS 文件都要发送请求响应,会致使加载速度变慢。Webpack 最主要的目的就是为了解决这个问题,将全部小文件打包成一个或多个大文件。
  2. 可使用各类前端新技术的工具,babel,sass。

面试题汇总

前端面试题(移动适配,闭包,this,HTTP状态吗,排序思路,页面加载,数组去重)

1 请写出一个符合 W3C 规范的 HTML 文件

请写出一个符合 W3C 规范的 HTML 文件,要求

  1. 页面标题为「个人页面」
  2. 页面中引入了一个外部 CSS 文件,文件路径为 /style.css
  3. 页面中引入了另外一个外部 CSS 文件,路径为 /print.css,该文件仅在打印时生效
  4. 页面中引入了另外一个外部 CSS 文件,路径为 /mobile.css,该文件仅在设备宽度小于 500 像素时生效
  5. 页面中引入了一个外部 JS 文件,路径为 /main.js
  6. 页面中引入了一个外部 JS 文件,路径为 /gbk.js,文件编码为 GBK
  7. 页面中有一个 SVG 标签,SVG 里面有一个直径为 100 像素的圆圈,颜色随意
  8. 注意题目中的路径
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>个人页面</title>
    <link rel="stylesheet" href="./style.css">
    <link rel="stylesheet" href="./print.css" media="print">
    <link rel="stylesheet" href="./mobile.css" media="(max-width: 500px)">
    <style> body{ padding:0; margin:0; } </style>
</head>
<body>
    <svg version="1.1" width="100px" height="100px" xmlns="http://www.w3.org/2000/svg">
        <circle cx="50" cy="50" r="50" fill="red"/>
    </svg>
    <script src="./main.js"></script>
    <script src="./gbk.js" charset="GBK"></script>
</body>
</html>
复制代码

2 移动端是怎么作适配的?

2016年腾讯前端面试题: 移动端是怎么作适配的? 回答要点:

  1. meta viewport
  2. 媒体查询
  3. 动态 rem 方案

(能够参考我写的博客 CSS5:移动端页面(响应式) CSS9:动态 REM-手机专用的自适应方案) 答:

2.1作手机端页面首先要加上一个meta标签

<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
复制代码

content="width=device-width表示宽度等于设备宽度,意思就是不要将页面宽度变成980px,用设备宽度. user-scalable=no表示用户不以缩放 initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0 初始缩放倍数,最大缩放倍数,最小缩放倍数,都是1.0,即不能缩放

2.2媒体查询

经过媒体查询,根据不一样条件,使用不一样的css样式。 例如:

<style> @media (max-width: 800px){/*若是媒体知足0到800 之间,那么会应用这里面的样式*/ body{ background-color: red; } } </style>
复制代码

2.3动态rem

由于手机须要兼容不少不一样宽度的手机设备,因此将长度单位依赖于手机设备宽度,使用动态rem方案,那么就能够在不一样手机上实现相同比例的页面缩放而不影响布局。 rem:root em,即<html>font-size. 实现动态rem,主要须要下面两步: 1在<head>标签里加上以下代码,让10rem等于页面宽度

<head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
      <title>动态REM</title>
      <script> var pageWidth = window.innerWidth document.write('<style>html{font-size:'+pageWidth+'px;}</style>') </script>
    </head>
复制代码

2使用sass自动将设计稿的px转换为rem 在scss文件里写这样一个函数:

@function px( $px ){
    @return $px/$designWidth*10 + rem;
    }

    $designWidth : 640; // 640 是设计稿的宽度,你要根据设计稿的宽度填写。设计师的设计稿宽度须要统一
复制代码

就可使用px()函数将像素转化为rem。

3 实现圆角矩形和阴影怎么作?

2017年腾讯前端实习面试题(二面): 用过CSS3吗? 实现圆角矩形和阴影怎么作? (搜索MDN border-radius) 答: 用过。例如阴影,圆角,动画,渐变和过渡 1.圆角: 简写属性border-radius。例如 border-radius: 30px; border-radius: 50%; 半径参数能够是长度单位,也能够是百分比单位。

也能够分别设置四个角

border-top-left-radius:     4px 2px;
border-top-right-radius:    3px 4px;
border-bottom-right-radius: 6px 2px;
border-bottom-left-radius:  3px 4px;
复制代码

半径参数能够是一个或两个,一个参数表明圆形圆角,两个参数是椭圆圆角

2.阴影:

语法: box-shadow:inset x-offset y-offset blur-radius spread-radius color 五个参数分别是:投影方式 X轴偏移量 Y轴偏移量 阴影模糊半径 阴影扩展半径 阴影颜色

4 什么是闭包,闭包的用途是什么?

出处同上(一面二面都问了): 什么是闭包,闭包的用途是什么? JavaScript高程P178 闭包的用途

答:

4.1什么是闭包

闭包是指有权访问另外一个函数做用域中的变量的函数。 例如

function foo(){
  var local = 1
  function bar(){
    local++
    return local
  }
  return bar
}

var func = foo()
func()
复制代码

bar函数能够访问变量local,bar就是一个闭包。

4.2闭包的用途

  1. 模仿块级做用域
    function A(num) {
        //核心代码
       (funnction(){
        for(var i = 0; i<num; i++) {
          num++;
        }
        })()
        //核心代码结束
        console.log(i)//underfined
      }
    复制代码

匿名自执行函数在内部造成了一个闭包,使i变量只有块级做用域。闭包的本质是函数,其实在这里闭包就是那个匿名函数,这个闭包能够获得函数A内部的活动变量,又能保证本身内部的变量在自执行后直接销毁。

  1. 存储变量 闭包的另外一个特色是能够保存外部函数的变量,原理是基于javascript中函数做用域链的特色,内部函数保留了对外部函数的活动变量的引用,因此变量不会被释放
function B(){
   var x = 100;
   return {
       function(){
           return x
       }
   }
 }
var m = B()//运行B函数,生成活动变量 x被m引用
复制代码

运行B函数,生成活动变量 x被m引用, 变量x不会被销毁。 运行B函数,返回值就是B内部的匿名函数,此时m引用了变量x,因此B执行后x不会被释放,利用这一点,咱们能够把比较重要或者计算耗费很大的值存在x中,只须要第一次计算赋值后,就能够经过m函数引用x的值,没必要重复计算,同时也不容易被修改。 3. 封装私有变量

function Person(){
   var name = 'default';
   this.getName:function(){
       return name;
   }
   this.setName:function(value){
       name = value;
   }
}
console.log(Person.getName())//default
console.log(Person.setName('mike'))
console.log(Person.getName())//mike
复制代码

设置了两个闭包函数来操做Person函数内部的name变量,除了这两个函数,在外部没法再访问到name变量,name也就至关因而私有成员。

5 call、apply、bind 的用法分别是什么?

阮一峰的javascript教程--this 深刻浅出 妙用Javascript中apply、call、bind

答:

若是在函数中包含多层的this,this的指向是不肯定的。须要把this固定下来,避免出现意想不到的状况。JavaScript提供了call、apply、bind这三个方法,来切换/固定this的指向。

5.1Function.prototype.call()

函数实例的call方法,能够指定函数内部this的指向(即函数执行时所在的做用域),而后在所指定的做用域中,调用该函数。

var obj = {};

var f = function () {
  return this;
};

f() === window // true
f.call(obj) === obj // true
复制代码

call的第一个参数就是this所要指向的那个对象,后面的参数则是函数调用时所需的参数。

5.2Function.prototype.apply()

apply方法的做用与call方法相似,也是改变this指向,而后再调用该函数。惟一的区别就是,它接收一个数组做为函数执行时的参数。

apply方法的第一个参数也是this所要指向的那个对象,若是设为null或undefined,则等同于指定全局对象。第二个参数则是一个数组,该数组的全部成员依次做为参数,传入原函数。原函数的参数,在call方法中必须一个个添加,可是在apply方法中,必须以数组形式添加

function f(x, y){
  console.log(x + y);
}

f.call(null, 1, 1) // 2
f.apply(null, [1, 1]) // 2
复制代码

5.3Function.prototype.bind()

bind方法用于将函数体内的this绑定到某个对象,而后返回一个新函数

bind方法的参数就是所要绑定this的对象。

var counter = {
  count: 0,
  inc: function () {
    this.count++;
  }
};

var func = counter.inc.bind(counter);
func();
counter.count // 1
复制代码

上面代码中,counter.inc方法被赋值给变量func。这时必须用bind方法将inc内部的this,绑定到counter,不然就会出错。

6 HTTP 状态码

出处同上: 请说出至少 8 个 HTTP 状态码,并描述各状态码的意义。

例如:

状态码 200 表示响应成功。

答:

状态码 202 表示:服务器已接受请求,但还没有处理。 状态码 204 表示:请求处理成功,但没有资源可返回。 状态码 206 表示:服务器已经成功处理了部分 GET 请求。

状态码 301 表示:请求的资源已被永久的分配了新的 URI。 状态码 302 表示:请求的资源临时的分配了新的 URI。

状态码 400 表示:请求报文中存在语法错误。 状态码 401 表示:发送的请求须要有经过 HTTP 认证的认证信息。 状态码 403 表示:对请求资源的访问被服务器拒绝了。 状态码 404 表示:服务器上没法找到请求的资源。

状态码 500 表示:服务器端在执行请求时发生了错误。 状态码 503 表示:服务器暂时处于超负债或正在进行停机维护,如今没法处理请求。

7 写出一个 HTTP post 请求的内容

出处同上: 请写出一个 HTTP post 请求的内容,包括四部分。 其中 第四部分的内容是 username=ff&password=123 第二部分必须含有 Content-Type 字段 请求的路径为 /path

看个人博客HTTP入门(一):在Bash中curl查看请求与响应

答: 请求:

1 POST /path HTTP/1.1
2 Host: www.baidu.com
2 User-Agent: curl/7.20.0 (x86_64-unknown-linux-gnu) libcurl/7.20.0 zlib/1.2.8
2 Accept: */*
2 Content-Length: 24
2 Content-Type: application/x-www-form-urlencoded
3 
4 username=ff&password=123
复制代码

响应:

1 HTTP/1.1 200 OK
2Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
2Content-Length: 2443
2Content-Type: text/html(百度返回的时候百度的数据长度和内容的格式)
2Etag: "5886041d-98b"
2Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
3
4<!DOCTYPE html> ...
复制代码

1234567890

8 请说出至少三种排序的思路

这三种排序的时间复杂度分别为

O(n*n) O(n log2 n) O(n + max)

答:

O(n*n) 冒泡排序:遍历整个数组,依次比较相邻两个元素,将小的排在前面,大的排后面,这样一遍循环下来就能够将最大的元素排到最后,除去已经排过的最大的数,而后再次循环以上操做,直到最后一个为止。

O(n log2 n) 快速排序:以第一个元素为基准,比这个元素小的元素排在左边,比这个元素大的排右边,再以该元素左边和右边的第一个元素为基准,在子区间重复以上的操做,直到只有一个数字排序为止。

O(n + max) 基数排序:首先根据个位数的数值,将须要排序的一串数值分配到0-9的桶中。接着将这些桶中的数值从新串起来,造成新的数列。接着根据十位数、百位数直至最高位重复以上操做。

9 页面从输入URL到页面加载显示完成的过程

著名前端面试题:

一个页面从输入 URL 到页面加载显示完成,这个过程当中都发生了什么? 这一题是在挖掘你的知识边界,因此你知道多少就要答多少。

能够先查阅一些资料再查,可是不要把本身不懂的东西放在答案里,面试官会追问的。

知乎上:从输入 URL 到页面加载完成的过程当中都发生了什么 答:

  1. DNS解析 DNS解析的过程就是浏览器查找域名对应的 IP 地址;
  2. TCP链接 浏览器根据 IP 地址向服务器发起 TCP 链接,与浏览器创建 TCP 三次握手: (1)主机向服务器发送一个创建链接的请求(您好,我想认识您); (2)服务器接到请求后发送赞成链接的信号(好的,很高兴认识您); (3)主机接到赞成链接的信号后,再次向服务器发送了确认信号(我也很高兴认识您),自此,主机与服务器二者创建了链接。
  3. 发送HTTP请求 浏览器根据 URL 内容生成 HTTP 请求报文。HTTP请求报文是由三部分组成: 请求行, 请求报头和请求正文,其中包含请求文件的位置、请求文件的方式等等。
  4. 服务器处理请求并返回HTTP报文

服务器接到请求后,回想客户端发送HTTP响应报文。HTTP响应报文也是由三部分组成: 状态码, 响应报头和响应报文。服务器会根据 HTTP 请求中的内容来决定如何获取相应的 HTML 文件,并将获得的 HTML 文件发送给浏览器。

  1. 浏览器解析渲染页面 浏览器是一个边解析边渲染的过程。在浏览器尚未彻底接收 HTML 文件时便开始渲染、显示网页。在执行 HTML 中代码时,根据须要,浏览器会继续请求图片、CSS、JavsScript等文件,过程同请求 HTML 。

  2. 关闭TCP链接或继续保持链接

(1)主机向服务器发送一个断开链接的请求(不早了,我该走了);

(2)服务器接到请求后发送确认收到请求的信号(知道了);

(3)服务器向主机发送断开通知(我也该走了);

(4)主机接到断开通知后断开链接并反馈一个确认信号(嗯,好的),服务器收到确认信号后断开链接;

10 如何实现数组去重

著名面试题: 如何实现数组去重? 假设有数组 array = [1,5,2,3,4,2,3,1,3,4] 你要写一个函数 unique,使得 unique(array) 的值为 [1,5,2,3,4] 也就是把重复的值都去掉,只保留不重复的值。

要求:

不要作多重循环,只能遍历一次 请给出两种方案,一种能在 ES 5 环境中运行,一种能在 ES 6 环境中运行(提示 ES 6 环境多了一个 Set 对象) 从 JavaScript 数组去重谈性能优化 也谈JavaScript数组去重 答:

ES5: 思路:核心是构建了一个 hash 对象来替代 indexOf. 注意在 JavaScript 里,对象的键值只能是字符串,所以须要 var key = typeof(item) + item 来区分数值 1 和字符串 '1' 等状况。 只循环一遍

function unique(arr) {
  var ret = []
  var hash = {}
  for (var i = 0; i < arr.length; i++) {
    var item = arr[i]
    var key = typeof(item) + item
    if (hash[key] !== 1) {
      ret.push(item)
      hash[key] = 1
    }
  }
  return ret
}
复制代码

ES6:ES2015引入了一种叫做Set的数据类型。顾名思义,Set就是集合的意思,它不容许重复元素出现。 若是重复添加同一个元素的话,Set中只会存在一个。包括NaN也是这样

function unique(array) {
   return Array.from(new Set(array));
}
复制代码

JS题目总结:原型链/new/json/MVC/Promise

1原型链相关

P4oVZ8.png
解读: 上图中,Object,Function,Array,Boolean都是构造 函数

第一个框: object是实例对象,他的模板对象(原型对象)在Object()构造函数里面. 构造函数.prototype指向的是原型对象,即模板对象. 由构造函数构造出来的实例对象.__proto__也指向的是原型对象,即模板对象. 因此true.

第二个框: fn是一个实例函数,是由用来构造出函数构造函数造出来的. 因此fn.__proto__ === Function.prototype

任何构造函数.prototype都是一个对象. 由于fn.__proto__ === Function.prototype 因此fn.__proto__.__proto__ === Object.prototype等价于 Function.prototype.__proto__ === Object.prototype 等价于 一个对象.__proto__ === Object.prototype 因此是true

第三个框同理.

第四个框比较难理解: 一个实例函数是由用来构造出函数构造函数造出来的.

Object,Function,Array都是一个实例函数,函数也是一种类型,就像String是一种类型,Number是一种类型同样,函数这个类型里的实例函数由函数的构造函数造出来!很难理解 因此实例函数.__proto__===构造函数.prototype 实例函数的构造函数就是Function

有点鸡生蛋蛋生鸡的感受.

第五个框同理

2面向对象,new,原型链相关

function fn(){
    console.log(this)
}
new fn()
复制代码

new fn() 会执行 fn,并打印出 this,请问这个 this 有哪些属性?这个 this 的原型有哪些属性? 答: 这个this就是new建立的新对象. this(这个新对象)有__protot__属性,它指向fn构造函数的原型即fn.prototype 这个原型(即fn.prototype)有两个属性:

  1. construct :它的值是构造函数fn
  2. __proto__: 它指向Object.prototype

解读:

P5Ctu8.png

  1. fn()是构造函数
  2. new fn()就是一个构造函数new出来的新对象. 他的自有属性为空,共有属性为空,由于都没有设置 由于他的自有属性为空,因此他只有一个__proto__指向构造函数.prototype(即原型)了. 共有属性为空,因此他的原型就是只有constructor指向构造函数和__proto__指向Object.prototype(由于原型自己就是对象类型,因此指向对象的构造函数) 例子:

P5U2pd.png

P5aqUO.png

3 json

JSON 和 JavaScript 是什么关系? JSON 和 JavaScript 的区别有哪些?

关系:JSON 是一门抄袭/借鉴 JavaScript 的语言,同时也是一种数据交互格式,JSON 是 JavaScript 的子集(或者说 JSON 只抄袭了一部分 JavaScript 语法,并且没有新增任何原创的语法)

区别:JSON 不支持函数、undefined、变量、引用、单引号字符串、对象的key不支持单引号也不支持不加引号、没有内置的 Date、Math、RegExp 等。 而 JavaScript 全都支持。

4 MVC

前端 MVC 是什么?(10分) 请用代码大概说明 MVC 三个对象分别有哪些重要属性和方法。(10分)

答一:

MVC 是什么 MVC 是一种设计模式(或者软件架构),把系统分为三层:Model数据、View视图和Controller控制器。 Model 数据管理,包括数据逻辑、数据请求、数据存储等功能。前端 Model 主要负责 AJAX 请求或者 LocalStorage 存储 View 负责用户界面,前端 View 主要负责 HTML 渲染。 Controller 负责处理 View 的事件,并更新 Model;也负责监听 Model 的变化,并更新 View,Controller 控制其余的全部流程。

答二: MVC就是把代码分为三块

V(view)只负责看得见的东西. M(model)只负责跟数据相关的操做,不会出现DOM,不会出现任何的html/css操做.例如model里只会有初始化数据库,获取数据方法fetch(),保存数据的方法save() C(controller)只负责把这些view和model组合起来,找到view,找到model,使用model完成数据修改业务,并修改view的显示 V:视图 M:数据 C:控制器

MVC是一种代码组织形式,不是任何一种框架,也不是任何一种技术,只是组织代码的思想,要作的就是V和M传给C,C去统筹 在js里,MVC分别由三个对象去担任三个职责

代码一:

window.View = function(xxx){
    return document.querySelector(xxx);
}
复制代码
window.Model = function(object){
    let resourceName = object.resourceName;
    return {
        init: function () { 
        },
        fetch: function () { 
        },
        save: function (object) {
        }
    }
}
复制代码
window.Controller = function(options){
    var init = options.init;
    let object = {
        view:null,
        model:null,
        init:function(view,model){
            this.view = view;
            this.model = model;
            this.model.init();
            init.call(this,view,model);
            this.bindEvents();
        },
        bindevnets:function(){},
    };

    for (let key in options) {
        if(key !=='init'){
            object[key] = options[key]
        }
    };
    return object;
}
复制代码

代码二:

var model = {
    data: null,
    init(){}
    fetch(){}
    save(){}
    update(){}
    delete(){}
}
view = {
    init() {}
    template: '<h1>hi</h1'>
}
controller = {
    view: null,
    model: null,
    init(view, model){
        this.view = view
        this.model = model
        this.bindEvents()
    }
    render(){
        this.view.querySelector('name').innerText = this.model.data.name
    },
    bindEvents(){}
}
复制代码

5 ES5类,原型链,构造函数,new

如何在 ES5 中如何用函数模拟一个类?(10分)

答一:

使用原型对象,构造函数,new来模拟类.

  1. 将公共属性放到原型对象里,而且将构造函数的prototype属性指向原型对象.
  2. 私有属性(自有属性)放到构造函数里去定义.
  3. 将实例化的对象的__proto__指向原型对象. 这样当构造函数建立一个实例化的对象的时候,就即拥有本身的私有变量和方法,也有公有的变量和方法了,实例化出来的对象的私有方法和变量修改都不会互相有影响,只有在修改公有的变量和方法的时候是对全部实例生效的

答二: ES 5 没有 class 关键字,因此只能使用函数来模拟类。

function Human(name){
    this.name = name
}
Human.prototype.run = function(){}

var person = new Human('frank')
复制代码

上面代码就是一个最简单的类,Human 构造函数建立出来的对象自身有 name 属性,其原型上面有一个 run 属性。

Promise

用过 Promise 吗?举例说明。 若是要你建立一个返回 Promise 对象的函数,你会怎么写?举例说明。

答:

用过Promise

答一: 用过 Promise,好比 jQuery 或者 axios 的 AJAX 功能,都返回的是 Promise 对象。

$.ajax({url:'/xxx', method:'get'}).then(success1, error1).then(success2, error2)

答二: 用过.例如使用jQuery的Ajax()发送请求,成功或失败后的回调函数,就是使用promise封装的

function success(responseText){
    console.log("成功")
    console.log(responseText);//responseTex
}
function fail(request){
    console.log("失败")
    console.log(request);
}
myButton.addEventListener("click",(e)=>{
    //使用ajax
    $.ajax({
        method:"post",
        url:"/xxx",
        data:"username=mtt&password=1",
        dataType:'json'//预期服务器返回的数据类型,若是不写,就是响应里设置的
    }
    ).then(success,fail)//$.ajax()返回一个promise
})
复制代码

写Promise

function xxx(){
    return new Promise((f1, f2) => {
        doSomething()
        setTimeout(()=>{
           if(success){
               f1();
           }else{
               f2();
           }
        },3000)
    })
}


调用方法:
xxx().then(success, fail)
复制代码

或者:

function asyncMethod(){
    return new Promise(function (resolve, reject){
        setTimeout(function(){
            成功则调用 resolve
            失败则调用 reject
        },3000)
    })
}
复制代码

能够看看个人博客__使用Promise封装Ajax

相关文章
相关标签/搜索