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
代码的执行过程如下:
- 首先进入
async1
,打印出async1 start
; - 之后遇到
async2
,进入async2
,遇到定时器timer2
,退出宏工作队列,之后打印async2
; - 因为
async2
阻塞了前面代码的执行,所以执行前面的定时器timer3
,将其退出宏工作队列,之后打印start
; - 而后执行 async2 前面的代码,打印出
async1 end
,遇到定时器 timer1,将其退出宏工作队列; - 最初,宏工作队列有三个工作,先后顺序为
timer2
,timer3
,timer1
,没有微工作,所以间接所有的宏工作依照先进先出的准则执行。
对对象与数组的解构的了解
解构是 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
解析:
- Foo.a() 这个是调用 Foo 函数的静态方法 a,尽管 Foo 中有优先级更高的属性办法 a,但 Foo 此时没有被调用,所以此时输入 Foo 的静态方法 a 的后果:4
- let obj = new Foo(); 应用了 new 办法调用了函数,返回了函数实例对象,此时 Foo 函数外部的属性办法初始化,原型链建设。
- obj.a() ; 调用 obj 实例上的办法 a,该实例上目前有两个 a 办法:一个是外部属性办法,另一个是原型上的办法。当这两者都存在时,首先查找 ownProperty,如果没有才去原型链上找,所以调用实例上的 a 输入:2
- 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:0
、letter-spacing
、word-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];
}
}