清除浮动的几种方式
- 父级 div 定义 height
- 结尾处加空 div 标签 clear:both
- 父级 div 定义伪类 :after 和 zoom
- 父级 div 定义 overflow:hidden
- 父级 div 也浮动,需要定义宽度
- 结尾处加 br 标签 clear:both
IE 盒子模型 、W3C 盒子模型
W3C 盒模型:内容(content)、填充( padding )、边界( margin )、 边框( border );
box-sizing: content-box
width = content width;
IE 盒子模型:IE 的 content 部分把 border 和 padding 计算了进去;
box-sizing: border-box
width = border + padding + content width
写出四种方式垂直居中的方式
从浏览器地址栏输入 URL 后发生了什么?
- 浏览器根据请求的 URL 交给 DNS 域名解析,找到真实 IP ,向服务器发起请求;
- .服务器交给后台处理完成后返回数据,浏览器接收文件( HTML、JS、CSS 、图象等)
- 浏览器对加载到的资源( HTML、JS、CSS 等)进行语法解析,建立相应的内部数据结构(如 HTML 的 DOM )
- 载入解析到的资源文件,渲染页面,完成。
cookies , sessionStorage 和 localStorage 的区别
cookie 是网站为了标示用户身份而储存在用户本地终端上的数据(通常经过加密)
cookie数据始终在同源的 http 请求中携带(即使不需要),记会在浏览器和服务器间来回传递(优化点)
sessionStorage 和 localStorage 不会自动把数据发给服务器,仅在本地保存
存储大小:
cookie 数据大小不能超过 4k
sessionStorage 和 localStorage 虽然也有存储大小的限制,但比 cookie 大得多,可以达到 5M 或更大
有期时间:
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据sessionStorage 数据在当前浏览器窗口关闭后自动删除cookie 设置的 cookie 过期时间之前一直有效,即使窗口或浏览器关闭
浏览器缓存
浏览器缓存分为强缓存和协商缓存。当客户端请求某个资源时,获取缓存的流程如下
先根据这个资源的一些 http header 判断它是否命中强缓存,如果命中,则直接从本地获取缓存资源,不会发请求到服务器;
当强缓存没有命中时,客户端会发送请求到服务器,服务器通过另一些 request header验证这个资源是否命中协商缓存,称为 http 再验证,如果命中,服务器将请求返回,但不返回资源,而是告诉客户端直接从缓存中获取,客户端收到返回后就会从缓存中获取资源;
强缓存和协商缓存共同之处在于,如果命中缓存,服务器都不会返回资源;区别是,强缓存不对发送请求到服务器,但协商缓存会。
当协商缓存也没命中时,服务器就会将资源发送回客户端。
当 ctrl+f5 强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存;
当 f5 刷新网页时,跳过强缓存,但是会检查协商缓存;
闭包
闭包就是能够读取其他函数内部变量的函数
闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个
函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域
闭包的特性:
函数内再嵌套函数
内部函数可以引用外层的参数和变量
参数和变量不会被垃圾回收机制回收
优点:能够实现封装和缓存等
缺点:消耗内存、使用不当会内存溢出,
解决方法:在退出函数之前,将不使用的局部变量全部删除
JavaScript 原型,原型链 ? 有什么特点?
- 每个对象都会在其内部初始化一个属性,就是 prototype (原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去 prototype 里找这个属性,这个prototype 又会有自己的 prototype ,于是就这样一直找下去,也就是我们平时所说的原型链的概念
- 特点:JavaScript 对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变当我们需要一个属性的时, Javascript 引擎会先看当前对象中是否有这个属性, 如果没有的,就会查找他的 Prototype 对象是否有这个属性,如此递推下去,一直检索到 Object内建对象
请解释什么是事件委托/事件代理
事件代理( Event Delegation ),又称之为事件委托。是 JavaScript 中常用的绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。使用事件代理的好处是可以提高性能
可以大量节省内存占用,减少事件注册,比如在 table 上代理所有 td 的 click 事件就非常棒
可以实现当新增子对象时无需再次对其绑定
事件模型
冒泡型事件:当你使用事件冒泡时,子级元素先触发,父级元素后触发
捕获型事件:当你使用事件捕获时,父级元素先触发,子级元素后触发
DOM 事件流:同时支持两种事件模型:捕获型事件和冒泡型事件
阻止冒泡:在 W3c 中,使用 stopPropagation() 方法;在 IE 下设置 cancelBubble =true
阻止捕获:阻止事件的默认行为,例如 click - a 后的跳转。在 W3c 中,使用preventDefault() 方法,在 IE 下设置 window.event.returnValue = false
JS实现继承
构造继承
原型继承
实例继承
拷贝继承
原型 prototype 机制或 apply 和 call 方法去实现较简单,建议使用构造函数与原型混合方式
function Parent(){
this.name = 'wang';
}
function Child(){
this.age = 28;
}
Child.prototype = new Parent();//继承了Parent,通过原型
var demo = new Child();
alert(demo.age);
alert(demo.name);//得到被继承的属性
复制代码
谈谈 This 对象的理解
this 总是指向函数的直接调用者(而非间接调用者)
如果有 new 关键字, this 指向 new 出来的那个对象
在事件中, this 指向触发这个事件的对象,特殊的是, IE 中的 attachEvent 中的this 总是指向全局对象 Window
Ajax 原理
Ajax 的原理简单来说是在用户和服务器之间加了—个中间层( AJAX 引擎),通过XmlHttpRequest 对象来向服务器发异步请求,从服务器获得数据,然后用 javascript来操作 DOM 而更新页面。使用户操作与服务器响应异步化。这其中最关键的一步就是从服务器获得请求数据
Ajax 的过程只涉及 JavaScript 、 XMLHttpRequest 和 DOM 。XMLHttpRequest 是ajax的核心机制
如何解决跨域
什么是跨域?
Jsonp
最早的解决方案,利用script标签可以跨域的原理实现。
限制:
需要服务的支持
只能发起GET请求
nginx反向代理
思路是:利用nginx反向代理把跨域为不跨域,支持各种请求方式
缺点:需要在nginx进行额外配置,语义不清晰
CORS
规范化的跨域请求解决方案,安全可靠。
优势:
在服务端进行控制是否允许跨域,可自定义规则
支持各种请求方式
缺点:
会产生额外的请求
** cors解决跨域**
https://www.jianshu.com/p/98d4bc7565b2
谈谈你对 ES6 的理解
新增模板字符串(为 JavaScript 提供了简单的字符串插值功能)
箭头函数 没有this指向 外层作用域的指向就是箭头函数的this指向
for-of (用来遍历数据—例如数组中的值。) for in 是枚举
arguments 对象可被不定参数和默认参数完美代替。
ES6 将promise 对象纳入规范,提供了原生的 Promise 对象。
增加了 let 和 const 命令,用来声明变量。
还有就是引入 module 模块的概念
如何通过 JS 判断一个数组
var arr = [];
arr instanceof Array; // true
复制代码
Array.isArray([]) //true
Array.isArray(1) //false
var arr = [];
arr.constructor == Array; //true
字符串去重
indeof 方法
const str = 'asdfasd'
const ChangeStr = (data) => {
let newstr = ''
for (i in data) {
if (i == data.indexOf(data[i])) {
//indexOf与search方法一样,获取元素下标,没有返回-1
newstr += data[i]
}
}
return newstr
}
//if()里的条件判断,判断data和newstr都可以
console.log(ChangeStr(str))
includes 方法
const str = 'asdfasd'
const ChangeStr = (data) => {
let newstr = ''
for(i in data){
if(!newstr.includes(data[i])){
//es6的新语法,过程是严格判断
newstr += data[i]
}
}
return newstr
}
console.log(ChangeStr(str),'ChangeStr')
// "asdf"
new Set
const str = 'asdfasd'
const ChangeStr = (data) => [...new Set(data)].join('')
//用es6的Set去重,转成数组,再转字符串
console.log(ChangeStr(str), 'ChangeStr')
// "asdf"
数组去重
var arr = [1, 5, 99, 88, 77, 66, 5, 4, 3, 88, 88, 8, 99, 55, 44]
function arrFn(arr) {
let newArr = []
for (let i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) == -1) {
newArr.push(arr[i])
}
}
return newArr
}
console.log(arrFn(arr));
const data = [ 1, 2, 2, 4, 5, 4 ]
const ChangeArr = ( data ) => {
const newarr = []
for ( let i = 0; i < data.length; i++ ) {
// if(newarr.indexOf(data[i])===-1){
//for每个值,用下标判断新数组存不存在
if ( !newarr.includes( data[ i ] ) ) {
//用es6新语法includes判断是否存在
newarr.push( data[ i ] )
}
}
return newarr
}
console.log( ChangeArr( data ), 'ChangeArr' )
// [1, 2, 4, 5]
提取没有重复的元素
let a = [1, 1, 2, 2, 3, 4, 1, 2]
const c = a.filter((item, idx) => {
let b = [...a]
b.splice(idx, 1)//
if (b.indexOf(item) == -1) return item
console.log(b);
})
console.log(c);
数组扁平化
function flatten(arr) {
var res = [];
arr.map(item => {
if(Array.isArray(item)) {
res = res.concat(flatten(item));
} else {
res.push(item);
}
});
return res;
}
3. join & split
和上面的toString一样,join也可以将数组转换为字符串
function flatten(arr) {
return arr.join(',').split(',').map(function(item) {
return parseInt(item);
})
}
SEO 优化
合理的 title 、 description 、 keywords :搜索对着三项的权重逐个减小, title值强调重点即可,重要关键词出现不要超过 2 次,而且要靠前,不同页面 title 要有所不同;description 把页面内容高度概括,长度合适,不可过分堆砌关键词,不同页面description 有所不同;keywords 列举出重要关键词即可
语义化的 HTML 代码,符合 W3C 规范:语义化代码让搜索引擎容易理解网页
重要内容 HTML 代码放在最前:搜索引擎抓取 HTML 顺序是从上到下,有的搜索引擎对抓取长度有限制,保证重要内容一定会被抓取
重要内容不要用 js 输出:爬虫不会执行 js 获取内容
少用 iframe :搜索引擎不会抓取 iframe 中的内容
非装饰性图片必须加 alt
提高网站速度:网站速度是搜索引擎排序的一个重要指标
server 优化
减少HTTP请求,合并文件、雪碧图
减少DNS查询,使用缓存
减少Dom元素的数量
使用CDN
配置ETag,http 缓存的手段
对组件使用Gzip压缩
减少cookie的大小
防抖节流
//防抖
function debounce(fn, delay) {
let timeout = null
return function () {
let arg = arguments
clearTimeout(timeout)
timeout = setTimeout(() => {
fn.apply(this, arg)
}, delay)
}
}
//节流 时间戳
function throttle(fn, delay) {
let old = 0
return function () {
let arg = arguments
let content = this
let now = + new Date()
if (now - old > delay) {
fn.apply(content)
old = now
}
}
}
//节流 定时器
function throttle(fn, delay) {
let timeout = null
return function () {
if (!timeout) {
timeout = setTimeout(() => {
fn.apply(this)
timeout = null
})
}
}
}
promiseAll
不过在使用的过程中需要注意的是,promise.all获得成功的数据是一个数组,并且根据传入参数数据顺序是一致,既p1在前,p2在后。因此在日常开发中,发送多个请求数据时,可以根据不同数据的请求顺序来使用数据,promise.all就能很完美的解决这个问题。
let wake = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time / 1000}秒后醒来`)
}, time)
})
}
let p1 = wake(3000)
let p2 = wake(2000)
Promise.all([p1, p2]).then((result) => {
console.log(result) // [ '3秒后醒来', '2秒后醒来' ]
}).catch((error) => {
console.log(error)
})
promise.race的话,从字面上看的话就是谁的响应速度快的话就谁先返回,不管是成功的回调还是失败的回调数据。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 打开的是 'failed'
})
用js实现vue双向绑定原理
<body>
<input type="text" id="search" />
<span id="content"></span>
</body>
<script>
const obj = {
name: ''
}
Object.defineProperty(obj, 'name', {
set(val) {
console.log(val);
document.getElementById('search').value = val
document.getElementById('content').innerHTML = val
}
})
document.addEventListener('keyup', function (e) {
obj.name = e.target.value
})
</script>
深拷贝
var obj = {
name: '深拷贝',
methods: '递归的方式实现',
sex: {
arr: ['我爱你哦']
}
}
var newObj = {}
function deepCope(newobj, oldobj) {
for (k in oldobj) {
let item = oldobj[k]
if (item instanceof Array) {
newObj[k] = []
deepCope(newObj[k], item)
}
if (item instanceof Object) {
newObj[k] = {}
deepCope(newObj[k], item)
}
else {
newObj[k] = item
}
}
}
deepCope(newObj, oldobj)