整理

1.前端安全问题有哪些,如何防范
主要有XSS攻击和CSRF攻击
xss:跨站脚本攻击,在网页里植入一段恶意代码,在该网站的作用域下执行了这段代码
防范:
1.在服务端设置对cookie的保护,也就是设置httponly,防止用户通过document.cookie来读取cookie
2.对用户的输入进行编码和解码,以及转义和过滤用户的输入内容,过滤掉用户输入的dom属性以及style iframe script等等

CSRF: 跨站请求伪造,用户登录了一个目标网站,诱使用户访问一个攻击页面,利用用户对目标网站的信任,发起伪造请求。
防范:
1.使用验证码或者anti-csrf-token
token大概流程
用户登录网页,服务端生成一个token,放在用户的session或者浏览器cookie中
然后给表单一个附带token参数
提交表单的时候检查 表单的token是否与用户 的token一致

2.什么时候不要使用箭头函数?
在需要动态上下文的场景

1.定义对象的方法

const calculator = {
    array: [1, 2, 3],
    sum: () => {

        console.log(this === window); // => true
        return this.array.reduce((result, item) => result + item);
    }
};

console.log(this === window); // => true

// Throws "TypeError: Cannot read property 'reduce' of undefined"
calculator.sum();

注意这里使用箭头函数定义calculator对象里的方法 this指向是window

不使用箭头函数

const calculator = {
    array: [1, 2, 3],
    sum() {
        console.log(this === calculator); // => true
        return this.array.reduce((result, item) => result + item);
    }
};
calculator.sum(); // => 6

this指向正确的指向了 calculator

2.定义原型上的方法

function Cat(name) {
    this.name = name;
}

Cat.prototype.sayCatName = () => {
    console.log(this === window); // => true
    return this.name;
};

const cat = new Cat('Mew');
cat.sayCatName(); // => undefined

不使用箭头函数

function Cat(name) {
    this.name = name;
}

Cat.prototype.sayCatName = function () {
    console.log(this === cat); // => true
    return this.name;
};

const cat = new Cat('Mew');
cat.sayCatName(); // => 'Mew'

3.定义事件的回调函数
常见的 DOM 事件回调函数(event listenner)绑定

const button = document.getElementById('myButton');
button.addEventListener('click', () => {
    console.log(this === window); // => true
    this.innerHTML = 'Clicked button';
});

不使用箭头函数

const button = document.getElementById('myButton');
button.addEventListener('click', function() {
    console.log(this === button); // => true
    this.innerHTML = 'Clicked button';
});

4.定义构造函数
使用箭头函数会报 Message不是一个构造函数

const Message = (text) => {
    this.text = text;
};
// Throws "TypeError: Message is not a constructor"
const helloMessage = new Message('Hello World!');

不使用箭头函数

const Message = function(text) {
    this.text = text;
};
const helloMessage = new Message('Hello World!');
console.log(helloMessage.text); // => 'Hello World!'

3.webpack.load的原理
loader相当于是源码的一个转换元件
是使用node.js运行的
把源文件作为参数,返回新的资源函数

4.let和const
let是更完美的var
1.let声明的变量具有块级作用域
2.let声明的全局对象 不是全局对象的属性 但仍然可以用 window.变量名的方式访问
3.形如for(let i=0; …) 每次循环的时候会为i创建一个新的绑定
4.let声明的变量只有在控制流到达该变量被执行的代码时才会被装载,在此之前调用会报错

const
const定义的常量 不可以重新赋值
const定义的变量 可以改变这个变量的属性

const obj = {a:1, b:2}
obj.a = 3
obj = {} // 重新赋值 会报错 
console.log(obj.a) // 3

5.box-sizing
box-sizing的作用?
设置css的盒子模型为标准模型还是ie模型
标准模型的的宽只计算content的宽 而ie模型还包括padding和border

box-sizing的三个值
content-box 只计算content的宽
padding-box 宽度为content+padding的宽
border-box 宽度为content+padding+border

6.h5标签语义化和seo
标签语义化 有利于 seo 方便搜索引擎更容易读懂网页表达的意思
例如 标题使用h1-h6
列表使用ul、ol
需要强调的文字使用 strong等等

7.git 如何批量删除分支

git branch  | grep ‘branchName’ | xargs git branch -D

举例
假设我们创建了很多分支
$ git branch
brabch
branch2
branch3
branch4
chucklu_zhCN

git branch查看分支
以bra开头的是我们需要删除的分支
使用命令逐个删除太麻烦
$ git branch | grep ‘bra‘
brabch
branch2
branch3
branch4

于是就有了我们的 git branch | grep ‘branchName’ | xargs git branch -D

解释一下
grep 可以用于在文件或流中查找匹配的结果
xargs 将前命令的执行结果作为参数传递给后一条命令
| 连接两个命令

这条语句的意思是 :
列出本地所有的分支
搜索含有branchName的分支
将搜索结果逐个传个删除分支的函数

8.创建对象的几种方法
1.工厂方法

function createPerson (name) {
	// 1.原料
	var obj = new Object()
	// 2.加工
	obj.name = name
	obj.showName = function () {
		alert(this.name)
	}
	// 3.出场
	return obj
	
}
var  man = createPerson('小明')
man.showName() // 小明

工厂方式的优点
解决了创建类似对象的问题,把实例化放在函数内部来做
缺点:无法区分是哪个对象产生的实例

2.构造函数的方法
有参数的 写法

function CreatePerson (name)  {
	this.name = name
	this.showNmae = function () {
		alert(this.name)
	}
}
var person  = new CreatePerson("小明")
person.showName() // 小明

不传参的写法

function CreateSong ()  {
}
var person = new CreateSong()
person.name = '小明'
person.showName = function () {
	alert(person.name)
}
person.showName() // 小明

构造函数的优点:
它的每个实例都会被视作一个特定的类型,这点是工厂方法所不及的
缺点
每个属性和方法都需要在实例上重新创建一次

3.字面量方式

var person = {
	name: '小明',
	showName: function () {
		alert(this.name)
	}
}
person.showName()  // 小明

4.原型方法

function Person () {
}
Person.prototype.name = '小明'
Person.prototype.showName = function () {
	alert(this.name)
}

原型方法的优点:
它所有的实例都共享它的属性和方法
缺点:
但是共享也是它的缺点,实例一般是有自己的单独属性的

5.混合方法
混合方法使用构造方法定义实例的属性 而使用原型定义共享的方法和 属性

function CreatePerson (name) {
	this.name = name
}
CreatePerson.prototype.showName = function () {
	alert(this.name)
}

var person1 = new CreatePerson('小明') 
person1.showName() // 小明

var person2 = new CreatePerson('小明') 
person2.showName() // 小明
console.log(person1.showName === person2.showName) // true

总结
方法使用原型定义
属性看情况,如果属性不可变,那么定义到原型上,否则用构造函数的
方法定义

9.浏览器渲染的过程(原理)
1.html解析成dom 树形结构
2.css解析成cssOM
3.dom和cssOM整合成render tree
4.显卡绘制在屏幕上(绘制的过程就依照回流与重绘)

10.路由
什么是路由?
根据不同的url显示不同的页面和内容

使用场景?
spa单页面应用 因为单页面应用前后端分离,后端不会向前端提供路由

实现路由的方法
h5 history api (见上)

路由的优缺点
优点:相比后端路由每次访问新页面都要向服务器发送请求,这个过程还有延迟,前端路由访问新页面只用改变一下路径,
没有延迟,对用户体验是一个提升

缺点:
浏览器前进后退都会重新发送请求,没有合理利用缓存
无法在前进后退的时候记住当前滚动条的位置

11.script标签的defer和async
defer是等html解析完成后再执行脚本 如果有多个defer 按次序执行
async是在脚本加载完成后立即执行 执行顺序与加载顺序无关

12.同源与跨域
什么是浏览器同源策略?
限制一个源的脚本与文档与另外一个源的交互,用来隔离恶意文件

什么样叫同源?
协议名、主机名和端口号相同

ttp://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域)

http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)

http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)

http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)

http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/

一个url的组成 (协议)://(主机名):(端口号)/(文件路径)/(文件名 )

什么是跨域?
指浏览器不能执行其他网站的脚本,它是由浏览器同源策略造成的,是浏览器对脚本的安全措施

跨域的解决方案
jsonp
原理: 客户端通过script标签的src属性向服务端发送请求,服务端返回一个js形式的数据内容,客户端通过执行函数接收数据内容。
缺点:①只能发送GET请求,复杂的请求内容无法提交。
②必须保证服务端返回的数据内容能被js处理

CORS
优点:①支持多种请求方式
②支持主域名不同的情况的跨域
③数据包装简单

cors方法是在服务器php文件里添加header(‘Access-Control-Allow-Origin:*’)
服务端代理
简单了解一下
1、在localhost:81/a.html中,向同源下的某个代理程序发出请求

$.ajax({
    url:'/proxy.php?name=hello&info=information',   //服务器端的代理程序
    type:'GET',
    success:function (){}
})

然后再代理程序里 proxy.php中,向非同源下的服务器发出请求,获得请求结果,将结果返回给前端。



简述一下过程
发起一个ajax,向同源的某个代理程序发出请求,这个代理程序向非同源的服务器发送请求,获得请求结果,将结果返回给前端。

h5的postMessage

//     http://test.com/index.html

Frame Color
// http://test.com/index.html通过postMessage()方法向跨域的iframe页面http://lsLib.com/lsLib.html传递消息 window.function(){ window.frames[0].postMessage('getcolor','http://lslib.com'); }

test.com上面的页面向lslib.com发送了消息,那么在lslib.com页面上如何接收消息呢,监听window的message事件就可以

// http://lslib.com/lslib.html

window.addEventListener('message',function(e){
                if(e.source!=window.parent) return;
                var color=container.style.backgroundColor;
                window.parent.postMessage(color,'*');
            },false);
           

简单概括一下步骤
test页面 使用window.frames[0].postMessage(data, "目标网址")
然后目标网址通过window.addEventLIstener(‘message’, func) 监听message事件

13.原型
原型是什么?
原型是一个普通对象,几乎所有对象都有原型,原型能够定义方法和属性,构造函数创建的对象可以引用原型上的方法

如何查看原型?

function Test () {
}
// 1.使用prototype (显示原型)
Test.protoType

//2. __proto__ (隐式原型)
var p = new Test()
p.__proto__

/ /3.es6推荐使用  Object.getPrototypeOf()
Object.getPrototypeOf(p)

顺便补充 一下 isPrototypeOf()

 	function A(){ }
 	
            var a = new A();
            //通过A创建一个对象a,所以a的__proto__是指向A.prototype的
            console.log(A.prototype.isPrototypeOf(a));
            //A.__proto__是指向Object.prototype的
            console.log(Object.prototype.isPrototypeOf(A));
            //由于A.prototype的__proto__是指向Object.prototype的,所以a也就含有Object.prototype咯
            console.log(Object.prototype.isPrototypeOf(a));

闭包是什么?
当一个内部函数被外部函数以外的变量引用的时候,就形成了闭包
例如:



闭包的特性?
封闭性: 外部无法访问闭包内部的数据
持久性:一般来说,函数调用完毕,会被注销,而闭包的外部函数被调用后,闭包结构依然存在

什么场景需要闭包?
如果想封装一个私有变量或者私有方法可以使用闭包

闭包的作用?
保存私有变量,对外提供接口,但外部不能直接访问这个变量

闭包的缺点?
消耗内存,因为不会被垃圾回收机制回收,使用不当,会造成内存泄漏

什么是垃圾回收机制?
1.当某个变量不再被引用就会被垃圾回收
2.当两个变量相互引用,但不被第三个变量引用, 也会被回收

垃圾回收机制的方式?
1.标记清除:变量进入环境,给它一个进入标记,离开环境,给它一个清除标记。垃圾回收器会过滤,保留进入环境的变量,剩余被清除
2.计数清除:变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象。

开发过程中遇到的内存泄露情况,如何解决的?
内存泄漏:内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。C#和Java等语言采用了自动垃圾回收方法管理内存,几乎不会发生内存泄露。
什么情况会发生?
1.当页面中元素被移除或替换时,若元素绑定的事件仍没被移除

解决办法

或者使用事件委托

var fans = document.getElementById('fans')
    fans.onclick = function (e) {
        if (e.target.id === 'fan') {
            console.log('sdad')
        }
    }

2.闭包引起内存泄漏

function outer() {
    var fan = document.getElementById('fan')
    fan.onclick = function () {
        console.log('click')
    }
}

在函数内部定义函数,引用的时候外爆形成了闭包

解决办法

将回调函数定义在外部

function outer() {
    var fan = document.getElementById('fan')
    fan.onclick = handle
}

function handle() {
    console.log('dh')
}

outer()

或者在定义事件处理函数的外部函数中,删除对dom的引用

function outer() {
    var fan = document.getElementById('fan')
    fan.onclick = function () {

    }
    fan = null
}

参考 https://www.cnblogs.com/redpen/p/8242196.html
如何创建闭包?
1.函数作为参数传递
2.函数作为返回值

 var a = 200
    // 函数作为返回值
    function F1() {
        var a = 100
        return function () {
            console.log(a)
        }
    }
    var f1 = F1() // a为100

    // 函数作为参数传递
    function F2(fn) {
        var a = 300
        fn()
    }
    F2(f1) //  a还是 100

14.错误监控
前端错误监控分为 即时运行错误(代码错误)资源加载错误

错误监控的方式
即时运行错误
try …catch
window.onerror

资源加载错误
object.onerror : img标签、script标签都可以添加onerror事件,用来捕获资源加载错误;
performance.getentries: 可以获取到所有已经加载的资源的加载时间,间接拿到加载失败的资源
举例说明
浏览器打开一个网站,在Console控制台下
输入

performance.getentries().foreach(item => {
	console.log(item.name) // 打印加载成功的资源名字
})

// 再输入查找img标签
document.getElementsByTagName(‘img’)

// 对比这俩数组就能间接知道加载失败的资源

跨域js运行错误可以捕获吗?错误提示?怎么解决?
可以捕获 显示script error 解决跨域问题见上

上报错误的方式
1.采用ajax上报
2.采用img对象上报 (推荐)
只需要动态创建一个img对象即可

(new Image()).src = ‘xxxx’

在浏览器的network里就可以 看到啦

15.dom事件

// dom 0级事件
element.onclick = function () {
}

// dom 2级事件
element.addeventListener(‘click’, function () {})

dom的事件模型: 事件冒泡和事件捕获

什么是事件冒泡和捕获呢?
事件冒泡: 事件从一个具体的元素开始,逐级向上传递直到window
事件捕获: 事件从window开始,逐级向下传递到具体的元素, ie不支持捕获

以下面的例子为例




         example


         
click

事件冒泡的过程为 div =》 body =》 html =》 document
事件捕获的过程 document =》 html =》 body =》 div

事件流: 事件捕获阶段 处于目标阶段 事件冒泡阶段
还是以上面的例子
在这里插入图片描述

event对象常见的方法
e.stopPropagation()
e.preventDefault()
e.target()// 返回触发事件的元素 例如li
e.currentTarget() // 返回绑定事件的元素 例如ul
e.stopImmediatePropagation() 和 e.stopPropagation()区别
假如说我给btn绑定了两个click事件 ,回调函数分别打印1和2
使用e.stopImmediatePropagation() 只会打印1 除了阻止冒泡 ,还会 停止当前节点后续同类的事件

自定义事件的写法


// 创建自定义事件
var e = document.createEvent('HTMLEvents')
// 自定义事件另一种写法  var e = new Event('HAHA')
// 初始化事件
e.initEvent('HAHA', false, true) // 三个参数  事件名称 是否冒泡  是否阻止浏览器默认行为
// 监听事件
elem.addEventListener('HAHA', function () {
	alert('触发事件!')
}
// 触发自定义事件
elem.dispatchEvent(e)

ie8及以下浏览器不支持createEvent怎么办呢?

虽然ie8不支持createEvent,但是ie8有onpropertychange事件
当dom元素的属性值发生变化会触发
也就是说,我们给dom设置一个属性a ,监听onpropertychange事件,判断变化的属性是不是a
是的话就执行自定义事件
代码如下:

请使用IE8或更低版本的浏览器测试

什么是事件委托?
事件委托指的是,不在事件的发生地设立监听函数,而是在事件发生地的父元素或者祖先元素设置监听器函数,这样可以大大提高性能,因为可以减少绑定事件的元素

实现一个通用事件绑定的函数
支持传三个或者四个参数
传三个参数的时候为普通的绑定事件
传四个参数为事件代理

 function delegate(elem, type, selector, fn) {
    if (fn == null) {
        fn = selector
        selector = null
    }
    if (elem.addEventListener) {
        elem.addEventListener(type, _handle)
    } else {
        elem.attachEvent('on' + type, _handle)
    }
    function _handle(e) {
       var  e = e || window.Event
        var target = e.target || e.srcElement
        if (!selector) {
            fn.call(target, e)
        } else if (matchSelector(target, selector)) {
            console.log(this) // ul
            fn.call(target, e)
        }
    }

    function matchSelector(elem, selector) {
        // use id
        if (selector.charAt(0) === '#') {
            return elem.id === selector.slice(1)
        } else if (selector.charAt(0) === '.') { // use class
            return (" "  + elem.className +" ").indexOf(" " + selector.slice(1) + " ") > 0
        } else { // use tagname
            return elem.tagName.toLowerCase() === selector.toLowerCase()
        }
    }
}

var wrap = document.getElementById('wrap')
    delegate(wrap, 'click', 'li', function (e) {
        console.log(e.target.innerHTML)
    })
    var d = document.getElementById('d')
    delegate(d, 'mouseover', function (e) {
        console.log(e.target.id)
    })

DOM事件级别?
dom0级事件 elem.onclick = function () {}
dom2级事件 elem.addEventListener(‘click’, func, false)
dom3级事件 elem.addEventListener(‘keyup’, func, false)

16.本地建立的http server 为什么只能在同一个wifi下访问
没有 公网ip 所以不能被外网访问 是个局域网

17.回流与重绘
回流
浏览器根据每个盒子模型的样式来计算,样式包括盒子的尺寸、布局、显隐,并根据计算结果将元素放在它该出现的位置,这个过程 叫回流

重绘
当盒子模型的颜色、字体大小等等不影响布局,只影响外观的属性, 浏览器将这些属性绘制出来,呈现在页面上,这个过程叫重绘

什么情况下会触发重绘与回流?
对dom结构的添加、删除 (回流+重绘)
仅修改dom元素的字体、颜色等等 (只触发重绘,因为不需要调整布局)
dom元素位置改变 (回流+重绘)
浏览器resize事件 (回流+重绘)

总结:影响盒子尺寸、布局、显隐就会触发 回流
只影响 盒子的外观 支出法重绘
回流是一定会触发重绘的!

如何避免回流 与 重绘?
1.使用cssText
设置style属性改变结点样式的话,每一次设置都会触发一次reflow
使用cssText一次性改变样式或者直接切换元素的className
cssText只触发一次

var left  = 5,
	top = 5
	fff = 5  // cssText里拼接top会失效 不知道原因
	// 不好的写法
el.style.left = left + 'px'
el.style.top = top  + 'px'	

// 好的写法
el.style.cssText += "; left: " + left + "px; top: " + fff + "px;";

2.使用documentFragment进行缓存,那么就只用一次回流与重绘

// 不好的写法 触发了两次回流与重绘
var p, t
p = document.createElement('div')
t = document.createNodeText('我是1')
p.appendChild(t)
document.body.appenChild(p)

p = document.createElement('div')
t = document.createNodeText('我是2')
p.appendChild(t)
document.body.appenChild(p)


// 好的写法
var p, t, frag
frag = document.createDocumentFragment()
p = document.createElement('div')
t = document.createNodeText('我是1')
p.appendChild(t)
frag.appenChild(p)

p = document.createElement('div')
t = document.createNodeText('我是2')
p.appendChild(t)
frag.appenChild(p)

document.body.appendChild(frag)

3.使用cloneNode和replaceChild
思想和上述的documentFragment类似

var oldNode = document.getElementById('targetId')
clone = oldNode.cloneNode(true) // 深拷贝
// 操作克隆的节点
...
// 操作完毕后
oldNode.parentNode.replaceChild(clone, oldNode)

4.不要经常访问会导致回流的属性,如果一定要访问,最好缓存

// 不好的写法
for(循环) {
	el.style.left = el.offsetLeft + 5 + "px";
	el.style.top = el.offsetTop + 5 + "px";
}

// 好的写法
var left = el.offsetLeft,
	top = el.offsetTop,
	e = el.style; 
	for (循环) { 
	left += 10; 
	top += 10; 
	e.left = left + "px"; 
	e.top = top + "px"; 
}

5.需要使用动画的元素,使用绝对定位或者fixed

6.尽量不使用table布局

18.数组去重
第零种方法 (效率最低 一个一个对比)

var arr = [1, 1, '1', '2',2,2, '1']

    function unique(arr) {
      var _arr = arr.slice()
      for (var i = 0; i < _arr.length; i++) {
          for (var j = i + 1; j < _arr.length; j++) {
              if (_arr[i] === _arr[j]) {
                  _arr.splice(j, 1) // splice会修改原数组 返回被删除或者添加的元素
                  j--
              }
          }
      }
      return _arr
  }

  console.log(unique(arr))

第一种写法
利用下标

function unique (arr) {
        var res = arr.filter(function (item, index, array) {
            // 参数array就是传入的arr 
            // 数组和字符串都有indexOf方法
            return array.indexOf(item) === index // 如果不重复 那么 这两者一定是相等  
        })
        return res
    }

    var a = [1, 1, '1', '2', 1]
    console.log(unique(a)) // [ 1, '1', '2']

上面的写法可能还不满意 复杂度高

第二种 写法 sort
先排序然后与相邻的对比

  function unique(a) {
        // a.concat() 是为了不改变当前数组 我习惯用slice了
        // 对a的副本sort 相同的值应该是相邻的 [1, 1, 1, 2, 2, 3, 4]
        console.log(a.concat().sort())
        return a.slice().sort().filter(function (item, index, arr) {
            return !index || item !== arr[index - 1]
        })
    }

    var a = [1, 1, 3, 2, 1, 2, 4];
    console.log(unique(a))

这种 写法的缺点是只能针对值全部是Number类型,如果String类型混进去了 ,由于toStirng方法 字符串‘1’和 数字1会被认为相等

修改一下

var a = [1, 1, '1', '2', 2,2]
    function unique(arr) {
        var _arr  = arr.slice().sort()
        var res = []
        for (var i = 0; i < _arr.length; i++) {
             if (!i || _arr[i] !== _arr[i - 1]) {
                 res.push(_arr[i])
             }
        }
        return res
    }
    console.log(unique(a))

第三种写法 es6

 function unique(a) {
      // Array.from类数组转数组 set的一个特性元素不能重复
      return Array.from(new Set(a))
  }
  let a = [{name: "hanzichi"}, {age: 30}, new String(1), new Number(1), 1, '1', 1, 1]; //  [object, object, String,  Number, 1, '1']
  console.log(unique(a))

第四种写法
借用对象的属性进行区分
时间最快 牺牲了空间

    var a = [1, 1, '1', '2',2,2, '1']
    function unique(arr) {
        var res = []
        var obj = {}
        var type
        for (var i = 0; i < arr.length; i++) {
            type = typeof arr[i]
           if (!obj[arr[i]]) {
               obj[arr[i]] = [type]
               res.push(arr[i])
           } else if (obj[arr[i]].indexOf(type) < 0) {
                obj[arr[i]].push(type)
                res.push(arr[i])
           }
        }
        return res
    }
    console.log(unique(a))

19.深拷贝 浅拷贝
浅拷贝
复制的是指向某个对象的指针,而不是复制对象本身,新旧对象公用一块内存
深拷贝
创建一个和旧对象一模一样的对象, 新旧对象不公用内存,修改也不会相互影响

举个例子

// 浅拷贝  修改obj2.b , obj1.b也会改变
 let obj1 = {a: 1, b: 2}
    let obj2 = obj1
    obj2.b = 3
    console.log(obj1.b) // 3
// 深拷贝 修改不会相互影响
    let obj1 = {a: 1, b: 2}
    let obj2 = {a: obj1.a, b: obj1.b}
    obj2.b = 3
    console.log(obj1.b) // 2

实现深拷贝的方法
1.如上 一个一个复制

2.es6提供的一个object.assign方法

    let obj1 = {a: 1, b: 2}
    let obj2 = Object.assign({}, obj1)
    obj2.b = 3
    console.log(obj1.b) // 2

3.使用JSON的方法
缺点是只有JSON格式的对象才能使用

    let obj1 = {test: {a:1}}
    let obj2 =  JSON.parse(JSON.stringify(obj1))
    obj2.test.a = 2
    console.log(obj1.test.a) // 1

4.jquery中提供了$.extend()

var $ = require('jquery');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1); // true代表深拷贝
console.log(obj1.b.f === obj2.b.f); // false

5.lodash库提供了一个_.cloneDeep

var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);  // false

20.如何合成雪碧图
1.gulp中可以使用一个插件 gulp.spritesmith
参考https://www.cnblogs.com/qianlitiaotiao/p/5054231.html
2.webpack同样可以使用一个插件 webpack.spritesmith
https://www.cnblogs.com/myfirstboke/p/8743966.html
3.有一些网站提供 在线合成

21.做了哪些代码优化
html:
1.代码语义化
2.尽量不适用iframe框架
3.避免使用重定向
例如window.location.href='hello.html';

css:
1.布局代码写在前面
2.删除空样式
3.不滥用浮动、字体
4.选择器性能优化
5.避免使用id做选择器

js:
代码压缩,减少重复代码 webpack.optimize.uglifyJsPlugin
webpack插件进行压缩

HtmlWebpackPlugin打包合并 html
MiniCssExtractPlugin打包css
uglifyJsPlugin压缩代码

图片优化:
使用雪碧图,或者图片用webP格式(有在线转化器)
图片懒加载

减少dom操作:
缓存已经 访问过的节点
“离线更新”节点 如上 使用documentFragment或者cloneNode + replaceChild
将一些事件放在DOMContentLoaded里去尽早的执行
事件节流

其他:
1.cookie优化
如果这个网站不需要cookie,把他的expires设为0或-1,关闭的同时清理掉cookie
将cookie的大小减到最小
设置合理的过期时间
获取 cookie
document.cookie

设置cookie

   function setCookie(name, value, day) {
        if (day !== 0)  { // 设置为0 即为关闭浏览器立即清除
            var expires = day * 24 * 60 * 60 * 1000;
            var date = new Date(+new Date()+expires);
            document.cookie = name + '=' + value + ';expires=' + date.toUTCString()
        } else {
            document.cookie = name + '=' + value
        }
    }
    setCookie('hello', 'nihao', 1)

删除cookie setCookie('hello', '', -1)

修改
重复赋值就可以覆盖掉上一个

cookie的格式

document.cookie = "cookieName=mader; expires=Fri, 31 Dec 2017 15:59:59 GMT; path=/mydir; domain=cnblogs.com; max-age=3600; secure=true";

cookieName=mader :name=value,cookie的名称和值

expires=Fri, 31 Dec 2017 15:59:59 GMT: expires,cookie过期的日期,如果没有定义,cookie会在对话结束时过期。日期格式为 new Date().toUTCString()

path=/mydir: path=path (例如 ‘/’, ‘/mydir’) 如果没有定义,默认为当前文档位置的路径。

domain=cnblogs.com: 指定域(例如 ‘example.com’, ‘.example.com’ (包括所有子域名), ‘subdomain.example.com’) 如果没有定义,默认为当前文档位置的路径的域名部分。

max-age=3600: 文档被查看后cookie过期时间,单位为秒

secure=true: cookie只会被https传输 ,即加密的https链接传输

封装cookie的使用方法

var cookieUtils = {
        set: function (name, value, expires, path, domain, secure) {
            var cookieText = ''
            cookieText += encodeURIComponent(name) + '=' + encodeURIComponent(value)
            if (expires > 0) {
                var day = new Date(+new Date() + expires * 24 * 60 *60 * 1000)
                cookieText += '; expires=' + day.toUTCString()
            }
            if (path) {
                cookieText += '; path=' + path
            }
            if (domain) {
                cookieText += '; domain=' + domain
            }
            if (secure) {
                cookieText += '; secure'
            }
            document.cookie = cookieText
        },
        get: function (name) {
            var cookieName = encodeURIComponent(name) + '='
            var cookieStart = document.cookie.indexOf(cookieName)
            var cookieValue = ''
            if (cookieStart > 0) {
                var cookieEnd = document.cookie.indexOf(';', cookieStart)
                if (cookieEnd < 0) {
                    cookieEnd = document.cookie.length
                }
                cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd))
            }
            return cookieValue
        },
        unset: function (name) {
            this.set(name, '', -1)
        }
    }


    cookieUtils.set('first', 'name', 1)

    console.log(cookieUtils.get('first'))
    cookieUtils.unset('first')

参考 https://www.cnblogs.com/lxf1117/p/6435612.html

2.使用cdn加速
cdn的原理 就是在不同的地点缓存内容,然后将用户的请求定向到最近的缓存服务器上

3.使用dns预解析

head中添加了以下代码(用以DNS预解析):


                                 



22.HTTP和HTTPS
HTTP: 超文本协议,是用来提供一种 发布和接受html的方法
HTTPS: 超文本传输安全协议,提供一个身份验证,保护交换数据的隐私和完整性

HTTP协议的特点?
简单快速: 输入URI就可以访问某个资源了?(图片、网页等 每个资源的URI是固定的)
灵活: 可以传输任何数据类型
无连接:连接一次就会断开,不会保持连接
无状态: 例如客户端向服务端发起请求,http建立连接,请求结束,断开,客户端 再发起一个请求,http不会保存这个状态,无法判断是否和上次连接相同

HTTP报文组成部分
请求报文:
请求行
请求头
空行
请求体

响应报文 :
状态行
响应头
空行
响应体

HTTP方法:
GET:获取资源
POST: 传输资源
PUT: 更新资源
DELETE: 删除资源
HEAD: 获取报文头部

POST和GET区别
1.浏览器点击后退,post会再次发送请求,而 get不用
2.浏览器会主动缓存get请求,而不会缓存post
3.get没有post安全,因为请求的参数直接暴露到url上

HTTP状态码
1xx 请求接受,继续处理
2xx 请求成功接受
3xx 重定向
4xx 客户端错误
5xx 服务端错误

200 请求成功
301 请求的页面已转向新的url
304 表示请求资源没有修改, 可以直接使用浏览器缓存.
404  找不到  服务器上不存在客户机所请求的资源
500  服务器内部错误

持久连接?
1.HTTP1.0采用的 请求-应答 模式,每个请求/应答 客户端和服务端会 建立一个连接,请求完毕就断开
2.HTTP1.1支持持久连接,使用的keep-alive模式,使客户端和服务端的连接持续有效,当出现了后续请求,避免了重新建立连接

管线化?
举个例子,使用持久连接的响应如下
请求1 响应1 请求2 响应2 请求3 响应3
而管线化是将请求打包,一次传输,也会将响应打包,一次传输
请求1 请求2 请求3 响应1 响应2 响应3

管线化的特点?
1.管线化基于持久连接,所以只有 HTTP1.1支持
2.只有GET和HEAD请求可以使用管线化,POST使用有限制
3.管线化不会影响响应的顺序

cookie是什么?
本身是用来客户端与服务端通信用的
但是它有本地存储的功能,所以被拿来做缓存
使用document.cookie的方法来操作它

cookie的缺点?
1.存储量较小 只有4kb
2.每次请求都需要携带,影响性能

cookie和locationStorage/sessionStorage的区别?
1.cookie存储量只有4kb 后两者存储量为5M
2.每次请求cookie会被携带 而后两者不会
3.cookie一般需要封装才能使用 而后两者有locationStorage.getItem(key) setItem(key, value)两个api

cookie是否会被覆盖?
会被覆盖,如果写入一个重名的cookie,就会将之前的cookie覆盖掉

封装一个对cookie增删改查的函数

前置知识:
cookie在生成时会被指定一个expires值,代表cookie的生存周期,超过了这个周期,cookie会被自动清理掉
有些页面将expires值设置为0或者负数,这样在关闭浏览器的同时,会自动清理cookie

cookie同样也满足同源策略
虽然网站images.google.com与网站www.google.com同属于Google,但是域名不一样,二者同样不能互相操作彼此的Cookie。
问题来了 举个例子:
访问 zhidao.baidu.com 再访问wenku.baidu.com还需要重新登陆百度账号吗?
解决办法: 设置document.domain = ‘baidu.com’;
让页面属于这个基础域名下(那么此页面和任何二级域名为baidu.com的)

function setCookie (key, value,iDay) {
	var oDate =  new Date()
	oDate.setDate(oDate.getDate() + iDay) // 将当前的天数加上cookie保存的天数就是cookie过期的天数
	document.cookie = key + '=' + value + ';expires=' + oDate
}

function removeCookie (key) {
	setCookie(key, '', -1) // 设置expiress时间为负数就可以删除
}

function getCookie(key) {
	var cookieArr = document.cookie.split(';')
	for (var i = 0; i < cookieArr.length; i++) {
		var arr  =cookieArr[i].split('=')
		return arr[0] === key ? arr[1] : ''
	}
	return false
}

如何保存登录状态?
可以把登录信息保存在cookie中,并控制cookie的保存时间,下次访问直接验证cookie中的登录信息即可,
但是这样不安全,密码暴露在cookie中
所以还有一种方案是将密码加密后保存到cookie中,需要验证的时候,先解密再验证。

cookie由哪几部分组成?
由变量名和值组成,还有一个有效日期,是以变量=值的方式保存的

如果把ajax请求来的数据放在localStorage中,调用的时候直接去localStorage中取是否可行?
这样取到的数据不具有实时性,只是我们之前请求来的数据,而不是当前最新的数据

HTTP1.0和1.1的区别?

  1. http1.0是非持久连接,每次请求都会为客户端与服务端创建一个连接,完成后就中断连接,而1.1支持持久连接,一次连接可以传多个请求和响应。
  2. http1.0只有16个状态码,对错误的描述不够详细。而1.1对错误的描述更具体了,增加了24个状态码

HTTP和HTTPS的区别?
1.HTTPS协议需要申请证书
2.HTTP运行在tcp上,所有传输内容都是明文,而HTTPS是运行在SSL/TLS(加密解密)上,SSL/TLS运行在tcp上,所有传输内容加密
3.HTTPS有效防止了运营商劫持

tcp
tcp是一种面向连接的协议,通信双方发送数据前需要先建立一个连接,这个连接就是在客户端和服务端内存里保存一份关于对方的信息,如ip地址,端口号
当tcp接收到另一端数据时,它会发送一个确认,一般会延迟一会,ACK是累积的,一个确认字号N的ACK代表所有直到N的的字节(不包括N)都成功接收了。这样的好处是如果某个ACK丢失了,后续ACK足以确认前面的报文。
ACK 确认号
RST 重置连接
SYN 初始化序列号
FIN 报文发送方已经结束向对方发送数据

为什么建立连接需要三次握手?
目的是 客户端和服务端都需要确认双方的发送、接收功能正常

第一次握手 客户端向服务端发送一个包,服务端收到,这样能确认客户端发送以及服务端接收都是正常的

第二次握手 服务端向客户端发送包,客户端收到,客户端能确定 客户端发送接受以及服务端接受、发送都是正常的

第三次握手 客户端向服务端发包,服务端收到, 服务端就能确定 客户端发送、接收以及客户端接收、发送都是正常的

为什么要四次挥手?
第一次挥手 当有一方要关闭连接,会发送指令告诉对方,我要断开了
第二次挥手 对方会返回一个ACK,然后一方连接断开
第三次挥手 但是另一方的连接还可以继续传输数据,等发送完所有数据,会发送一个FIN来关闭这一方的连接
第四次挥手 接收到FIN的一方会返回一个ACK确认关闭

参考 https://blog.csdn.net/csdnnews/article/details/86570658

建立tcp连接和断开连接的过程?
建立连接需
要三次握手:
1.客户端的tcp向服务端tcp发送一个连接请求报文
2.服务端接受到请求报文后,若同意请求,向客户端发送一个确认报文。
3.客户端接受到确认报文,还要向服务端给出确认

断开连接四次挥手:
1.客户端打算断开连接,发送一个连接释放报文
2.服务端接受连接释放报文,随即发出确认
3.若服务端没有数据需要传输,通知tcp释放连接
4.客户端接受到连接释放报文,必须发出确认才会断开

23.如何实现响应式图片
1.手动绑定一个resize事件,然后在不同的size下加载不同的图片 (不推荐)
2.给图片添加srcset方法
这个属性是用来让浏览器根据不同的宽高、像素来加载不同的图片
属性格式:图片地址 宽度描述w 像素密度描述x,多个资源之间用逗号分隔


  1. 使用svg矢量图

24.如何判断是否为一个数组
constructor 属性返回对创建此对象的数组函数的引用。

var a = []
// 1. instanceof
a instanceof Array

// 2.constructor
a.constructor === Array

// 3. isPrototypeOf
Array.prototype.isPrototypeOf(a)
// 4 . getPrototypeOf
Object.getPrototypeOf(a) === Array.prototype
// 5. Array.isArray 方法
Array.isArray(a)

25.unicode和utf-8
unicode是字符集
utf-8是编码规则

utf-8是对unicode字符集进行编码的一种编码方式

26.null 和 undefined的区别
1.
null表示对象的值为空
undefined表示变量we赋值或者值不存在

2.typeof null 的结果是Object
typeof undefined 结果是undefined

补充几个容易混淆的东西

 console.log(null == undefined) // true
 console.log(null === undefined) // false

29.如何让js文件延迟加载
1.将js文件放在最底部
2.给js文件加上defer=“defer” 或者async=“async”属性
3.动态创建一个 script元素

//这些代码应被放置在标签前(接近HTML文件底部)

4.使用jQuery的getScript方法

$.getScript("xxx.js",function(){ //  回调函数,成功获取文件后执行的函数  
      console.log("脚本加载完成")  
});

30.document.write和innerHTML的区别
前者只能重绘整个页面
后者可以只重绘一小部分页面

31.闭包的几个题目

function fun(n,o) {
  console.log(o)
  return {
    fun:function(m){
      return fun(m,n);
    }
  };
}
var a = fun(0);  a.fun(1);  a.fun(2);  a.fun(3);//undefined,?,?,?
var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
var c = fun(0).fun(1);  c.fun(2);  c.fun(3);//undefined,?,?,?
//问:三行a,b,c的输出分别是什么?

答案 a打印结果分别是 undefined 0 0 0
b undefined 0 1 2
c undefined 0 1 1

32.创建函数的几种方法
1.函数声明

function fn1(){}

2.函数表达式

var fn1=function (){}

这种方式创建的其实是匿名函数

3.有名字的函数表达式

var fn1=function xxcanghai(){};

采用此种方法创建的函数在函数外层只能使用fn1不能使用xxcanghai的函数名

4.使用Function构造

console.log(Function('alert(1)'))

打印结果 也是匿名函数

anonymous() {
alert(1)
}

33.关于变量提升的题目

  function Foo ()  {
        getName = function () {
            alert(1)
        }
        console.log(this) // window
        return this
    }
        Foo.getName = function () {
            alert(2)
        }
        Foo.prototype.getName = function () {
            alert(3)
        }
        var getName = function () {
            alert(4)
        }
        function getName() {
            alert(5)
        }

//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

我们首先根据变量提升来重新排列一下:
要记住 函数表达式的提升会被拆成两部分,声明部分提升,赋值并没有提升
函数声明本身会被提升

所以重排后的顺序为

    function Foo ()  {
        getName = function () {
            alert(1)
        }
        console.log(this) // window
        return this
    }
    
    var getName

    function getName() {
        alert(5)
    }

    Foo.getName = function () {
        alert(2)
    }
    Foo.prototype.getName = function () {
        alert(3)
    }
    getName = function () {
        alert(4)
    }

第一问
Foo.getName();结果显而易见是2

第二问
getName()
这里变量声明提升 然后给getName赋值为

 function () {
        alert(4)
    }

所以答案是4

第三问
Foo().getName();
先调用了Foo函数,执行的过程遇到第一行getName由于在当前函数的作用域内没有找到定义,所以到父级作用域也就是window中找到了getName的声明,然后赋值

 function () {
            alert(1)
        }

将之前的alert(4)给覆盖了
而Foo()调用的结果为return this 这里this指向window
所以是window.getName 答案是1

第四问
getName();
window对象的getName已经被替换成了alert(1) 所以答案是1

第五问
new Foo.getName(); 根据符号的优先级 .优先级大于 New
所以先执行Foo.getName() 答案是2

第六问
new Foo().getName();
括号优先级最大 所以先执行 new Foo() 将Foo作为构造函数了
在构造函数内没有找到getName方法 所以到原型上找 于是答案为3

第七问
new new Foo().getName();由优先级 所以 真正的执行顺序为 new ((new Foo()).getName())
答案同上还是3

34.git管理代码
上传代码
github上创建仓库
打开git bash
cd进入你的项目文件夹
git init 初始化
git add .
git commit -m “注释修改内容”
git remote add origin “建立与远程仓库的连接”
git push -u origin master
输入账号密码就可以push到仓库了
如果这里报了莫名其妙的错误 ssh可能会报错 使用https,但是要清理掉之前的连接 git remove rm origin

下载仓库的代码
cd 进入你想要放置代码的文件夹
git clone https/ssh
如果本地已经有对应仓库的文件夹
直接git pull即可获取最新的代码

git branch xx
git checkout xx 切换到xx分支
git push origin xx 将新的分支提交到仓库
…修改代码…
使用git status可以查看哪个文件被修改
git diff xxx.html 可以查看xxx.html被修改的具体内容 (对txt修改不显示的哦)
依然可以使用git commit -m “添加修改注释”
git push -u origin xx 将修改后的代码提交到xx分支

团队中的流程
git branch dev 创建一个名字叫dev的分支 我们一般不会直接在master上修改代码
git checkout dev 切换到dev分支
代码编写
git add 目录/文件/.(.代表目录下的全部文件)名 编写完添加到本地代码库
git commit -m “注释”
这个时候有一些改变了没有提交的代码会变红色,在你 切换到master之前,应该暂存当前dev的开发一下到栈里。
git stash
一天任务完成
git push origin dev 将本地分支提交到远程仓库

如果需要别人的分支代码
git pull origin 分支名
尽量不要使用rebase 和merge不一样 被合并的分支就没了

如果要继续之前的工作
git stash pop 回到dev开发,要从stash中取出暂存的状态

如果需要合并到master
git checkout master
git merge dev
git push

总结流程如下:
git clone URL
(master branch now)
git branch dev
(new dev bransh to develop)
git checkout dev
(switch dev bransh now)
(…coding …add … delete…modify…)
git add ./src ./res
(just add src and res in the local reposity)
git stash
(push the status into git stack,as some files modified but not add and committed)
git checkout master
git pull
(update the code from server .)
git checkout dev
git rebase master
(rebase from master.)
(solve the conflict code)
git checkout master
git merge dev
(merge the code from dev)
git push
(upload the new code to server)
git checkout dev
git stash pop
(ok, continue coding ,man )

如果不小心在master分支改动了代码怎么办?
git status
(you will the modification is red)
git stash
(temporary store the modification into stack)
git status
(no red file now, as the branch rallback to the latest commit)
git pull
(update the code from the server)
(if you want to save the modification, you need still step on following steps)
git checkout dev
git rebase master
(update the code base on master)
git stash pop
(pop the stored code out)

最常见的冲突是内容冲突:你修改了一个函数的实现,而远程仓库版本跟你的不一样,当主版本和你的修改合并时,这段代码的修改到底听谁的,所以就冲突了。通常出现在git pull与git merge的过程中
冲突文件标识
<<<<< ========= >>>>>>
解决办法 直接修改冲突的文件
当处理完所有冲突后,执行git add与git commit即可。

项目模块依赖管理 使用的npm

35.手写事件模型和事件代理(委托)

IE和W3C不同绑定事件解绑事件的方法有什么区别?
w3c下绑定事件的方法为 element.addEventListener(‘click’,handle, false)
三个参数分别为 事件名,处理函数, 事件是否在捕获或者冒泡阶段执行
ie下的绑定事件方法为 elemetn.attachEvent(‘onclick’, handle)

w3c解绑事件方法为 element.removeEventListener(‘click’, handle, false)
ie element.detachEvent(‘onclick’, handle)

w3c的事件对象和ie的事件对象的区别?
w3c的事件对象e = arguments.callee.caller.arguments[0]
argments.callee就是函数体本身
arguments.callee.caller就是调用这个函数体的另一个函数体
举个例子

function  a(){
    b();
}

function  b(){
    alert(b  ===  arguments.callee) 
    alert(b.caller  ===  a)
    alert(arguments.callee.caller  ===  a)

}
a();
执行结果是三个 true

假如有个点击函数 elem.onclick = function (e) {}
那么arguments.callee.caller就是这个click函数
arguments.calleee.caller.arguments[0] 也就是它的第一个参数 e

ie的事件对象e则是 window.event

事件代理的原理?
利用了事件冒泡

事件代理的优缺点?
优点:
1.大量节省内存,减少事件的注册,例如可以在ul上代理所有li的点击事件
2.可以实现在新增子元素的时候,无需再对其进行事件绑定,对于动态部分来说很实用

缺点:
如果都使用事件代理,有可能会出现事件误判,也就是不该触发事件的元素被绑定了事件

实现一个兼容浏览器的事件代理

  • 1
  • 2
  • 3

实现事件模型
即写一个类或是一个模块,有两个函数,一个bind一个trigger,分别实现绑定事件和触发事件,核心需求就是可以对某一个事件名称绑定多个事件响应函数,然后触发这个事件名称时,依次按绑定顺序触发相应的响应函数

实现:创建一个类或是匿名函数,在bind和trigger函数外层作用域创建一个字典对象,用于存储注册的事件及响应函数列表,bind时,如果字典没有则创建一个,key是事件名称,value是数组,里面放着当前注册的响应函数,如果字段中有,那么就直接push到数组即可。trigger时调出来依次触发事件响应函数即可。

不过还有很多细节,比如触发响应函数时的上下文应该是什么,触发响应函数的参数列表应该是什么,如果要求把调用trigger的参数列表都传到响应函数中还要考虑到吧arguments对象转化为纯数组才行等等。

    function Emitter() {
        this._listener = {};//_listener[自定义的事件名] = [所用执行的匿名函数1, 所用执行的匿名函数2]
    }

    //注册事件
    Emitter.prototype.bind = function(eventName, callback) {
        var listener = this._listener[eventName] || [];//this._listener[eventName]没有值则将listener定义为[](数组)。
        listener.push(callback);
        this._listener[eventName] = listener; // 将push了值的listener赋值给原先的_listener 
        // 相当于给_listener数组push了一个叫eventName的对象 eventName是key 他的数组是value
    }

    //触发事件
    Emitter.prototype.trigger = function(eventName) {
               var args = Array.prototype.slice.call(arguments, 1); // 类数组转数组 args为获得除了eventName后面的参数(注册事件的参数)
        var listener = this._listener[eventName];

        if(!Array.isArray(listener)) return;  // 自定义事件名不存在
        listener.forEach(function(callback) {
            try {
                callback.apply(this, args);
            }catch(e) {
                console.error(e);
            }
        })
    }
    //实例
    var emitter = new Emitter();
    emitter.bind("myevent", function(arg1, arg2) {
        console.log(arg1, arg2);
    });

    emitter.bind("myevent", function(arg1, arg2) {
        console.log(arg2, arg1);
    });

    emitter.trigger('myevent', "a", "b");
    // 打印 结果 a b
    //          b a

如何派发事件广播(自定义事件)
ie下的例子:

 // ctrl + alt + i 自动对齐
    document.attachEvent('diyEvent', function (e) {
        console.log('hi')
        alert(e.eventType)
    })
    var event = document.createEventObject()
    event.eventType = 'diy'
    document.fireEvent('diyEvent', event)

高级浏览器(chrome,firefox等)的例子:

//document上绑定自定义事件diyEvent
document.addEventListener('diyEvent', function (e) {
      alert(e.eventType)
  })
    var event = document.createEvent('HTMLEvents')
// 事件名 是否阻止冒泡 是否阻止默认行为
    event.initEvent('diyEvent', true, true)
    event.eventType = 'diy'
    document.dispatchEvent(event)

36.实现Function.bind方法
bind方法的作用?
bind会创建一个新函数,新函数与被调用的函数有相同的函数体,当新函数被调用时,this会指向bind的第一个参数,这个参数不能被重写
举个简单例子来证实bind改变了this指向

 window.value = 1
    var foo = {
       value: 2
    }
    function bar() {
       if (arguments[0] !== undefined) {
           console.log(this.value, arguments[0])
       } else {
           console.log(this.value)
       }

    }
    // 普通函数调用
    bar() // 1 this指向window
    // bind
    var bindFoo = bar.bind(foo, 'ha') // this指向foo
    bindFoo() // 2 'ha'

实现bind方法需要满足三个需求
1.可以改变this指向
2.可以传参
3.作为构造函数时,指定的this失效,但是参数依然生效

  Function.prototype.myBind = function (context) {
      var self = this
      // 实现可以传参的功能 获取myBind函数从第二个参数到最后一个参数,第一参数是指向
      var args = Array.prototype.slice.call(arguments, 1)

      var fbound =  function () {
          // 这个arguments是作为返回值的函数传入的参数
          var bindArgs = Array.prototype.slice.call(arguments)
          // 当作为构造函数时,this 指向实例,self 指向绑定函数,因为下面一句 `fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为 绑定函数的 prototype,此时结果为 true,当结果为 true 的时候,this 指向实例。
          // 当作为普通函数时,this 指向 window,self 指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的 context。
          self.apply(this instanceof self ? this : context, args.concat(bindArgs))
      }
      fbound.prototype = this.prototype
      return fbound
  }


37.快速排序
原理:从数组中找到一个基准,重新排序,将小于基准的放到前面,大于基准的放到后面,基准就处于数组中间,
然后递归的将小于基准的数组和的大于基准的数列同样分别找到基准,继续以上操作

function quicksort(arr) {
      console.time('快速排序耗时')
      if (arr.length < 1)
          return arr
      var pivotIndex = Math.floor(arr.length / 2)
      var pivot = arr.splice(pivotIndex, 1)[0] // 从数组中添加/删除项目,返回删除的参数
      var left = []
      var right = []
      for (var i = 0; i < arr.length; i++) {
          if (arr[i] < pivot) {
              left.push(arr[i])
          } else {
              right.push(arr[i])
          }
      }
      console.timeEnd('快速排序耗时')
      return quicksort(left).concat([pivot], quicksort(right))
  }
  var arr =[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
  console.log(quicksort(arr))

38.将url的查询参数拆解为对象

function getQueryObject(url) {
      url = url ? url : window.location.href;
      var search = url.substring(url.lastIndexOf("?") + 1);  // substring() 方法用于提取字符串中介于两个指定下标之间的字符。提取了最后一个?之后的字符
      var obj = {}; //  存放拆分的参数
      var reg = /([^?&=]+)=([^?&=]*)/g;
      search.replace(reg, function (rs, $1, $2) { // $1 $2 为匹配到的第一个和第二个
          var name = decodeURIComponent($1);
          var val = decodeURIComponent($2);
          val = String(val);
          obj[name] = val;
          // console.log(rs)
          return rs;
      });
      return obj;
  }
  console.log(getQueryObject('https://www.baidu.com/s?wd=replave&rsv_spt=1&rsv_iqid=0x8bd0f7600000dde2&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=baiduhome_pg&rsv_enter=1&oq=substring&rsv_t=b8d1egcIQNsMr9XE8gAah54EFJq6ZzaVvS%2B3Ar%2B%2Bjne4uOjLvU0wAuHanXSluDFmrF51&inputT=7639&rsv_pq=8dc75d6b0001804b&rsv_sug3=68&rsv_sug1=67&rsv_sug7=100&rsv_sug2=0&rsv_sug4=7640'))

39.水平垂直居中

html部分
子元素

1.absolute + margin:auto
适用于子元素宽高不固定

    

2.absolute + 负的margin
适用于子元素宽高固定


3.absolute + transform
transform是css3属性 ie9之前版本兼容不好


4.flex
ie不兼容 移动端推荐使用


5.table-cell

    

字体垂直居中
单行文本垂直居中
line-height = height

多行文本垂直居中
父元素高度不固定:高度只能由文本撑开,只需要设置padding-top的值等于padding-bottom即可

 
    
这是多行文本垂直居中, 这是多行文本垂直居中, 这是多行文本垂直居中, 这是多行文本垂直居中。

父元素高度固定
设置父级div为display:table 子元素为table-cell 然后给子元素设置vertical-align:middle

这是固定高度多行文本垂直居中, 这是固定高度多行文本垂直居中, 这是固定高度多行文本垂直居中, 这是固定高度多行文本垂直居中。

40.自适应布局
三栏布局
左右宽度固定 中间自适应





这几种方法的优缺点:
1.float 兼容比较好 缺点是需要清除浮动
2.position 比较快捷 缺点是脱离文档流 实际使用不是特别好相对于其他的方法
3.flex 比较完美的方法 除了低版本浏览器不兼容
4.grid 网格布局 代码量比较简单

上下高度固定 中间自适应同上









两栏布局
方法也可以借用上面的



41.函数节流
例如我们给搜索框搜索的内容绑定了一个事件,搜索的内容发生了变化,就会发起请求,而用户在输入的过程,已经发出了多次请求,为了提高性能,需要函数节流来减少发起请求的次数 让用户在输入字符的这个短时间内只发送一次请求

function debounce(func, delay) {
    var timer
    return function () {
        if (timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(function () {
            console.log(this) // window
            func.apply(this, arguments)
        }, delay)
    }
}

n=0;
function resizehandler(){
    console.log(++n);
}

// window.onresize = resizehandler
    window.onresize = debounce(resizehandler, 500)

42.移动端自适应
在head里添加meta

    

width=device-width表示网页的宽度等于设备屏幕的宽度
user-scalable=no 不允许用户缩放
以下分别为初始、最大 、最小缩放比例
initial-scale=1.0,
maximum-scale=1.0,
minimum-scale=1.0

使用百分比布局

响应式页面实现
1.媒体查询
一般写在css的最底下

// 屏幕 < 300px
@media screen and (max-width: 300px) {
    body {
         background-color:red;
    }
}
// 300px < 屏幕 < 600px
@media screen and (min-width: 300px) and (max-width:600px) {
    body {
         background-color:green;
    }
}
// 屏幕 >600px
@media screen and (min-width: 600px) {
    body {
         background-color:blue;
    }
}


  1. Bootstrap栅格布局

3.使用em和rem作为单位
em相对于父元素大小来变化
rem相对于html根节点的大小来变化

当根节点html和父元素的字体大小相同 em和rem相等 (自己测试的)

43.题目
1.
传入一个string类型的参数,然后将string的每个字符间加个空格返回,例如:
spacify(‘hello world’) // => ‘h e l l o w o r l d’
答案

function spacify(str) {
    return str.split('').join(' ')
}
console.log(spacify('hello world'))

如何把这个方法放入String对象上面?

String.prototype.spacify = function () {
        return this.split('').join(' ')
    }
    console.log('hello world'.spacify())

定义一个log方法代理conosle.log,并且支持传参,参数数量不定?

    function log() {
        return console.log.apply(console, arguments)
    }
    log('ho', 'llo')

每一个log消息添加一个"(app)"的前辍?

    function log() {
        var args = Array.prototype.slice.call(arguments)
        args.unshift('(app)')
        return console.log.apply(console, args)
    }
    log('ho', 'llo')

以下两个打印结果为?

var User = {
  count: 1,

  getCount: function() {
    return this.count;
  }
};
console.log(User.getCount());

    var func = User.getCount;
    console.log(func());

分别输出 1和undefined
因为User.getCount中的this执行User
而打印的func()是在window中执行,this指向window,而window并没有count这个属性 所以返回undefined

要保证每次输出1怎么办呢?
修改为

var func = User.getCount.bind(User);

undefined和undecalerd有什么区别?
undefined是js的一种语言类型
undeclaerd是js语法错误的一种报错结果

全局变量和局部变量的区别?
全局变量是在当前页面的window作用域下都可以调用
局部变量只能在当前的方法的作用域内调用

window.loaction.reload()作用是?
刷新页面

44.内存泄漏是什么?什么情况发生
当一个变量不需要被使用了而它依然存在 这就是内存泄漏

什么情况下发生?
1.setTimeout第一参数非函数的时候
2.闭包

45.iframe的缺点
1.阻塞主页面的onLoad事件
2.不利于seo
3.影响页面的并行加载

并行加载:同一时间内对同一域名下的请求
浏览器并行加载数量有限制,iframe和主页面一般来说又是同一域名

怎么解决呢?
使用js动态设置iframe的src加载的内容


 document.getelementbyid("fram").src="a2.html" 

46.盒子模型
盒子模型有两种,一种是w3c,另一种是ie盒子
w3c的盒子模型是包括margin、border、padding、content
width = content的宽
ie盒子和w3c的区别就是width = content的宽 + padding + border

可以通过 box-sizing来设置是哪种盒子
content-box 是w3c盒子模型
border-box 是ie模型

js如何获取盒模型的宽高?
elem.style.width/height 只能获取内联样式的宽高

elem.currentStyle.width/height 仅ie支持 能够比较准确的获取内联、style标签、引入的样式表

window.getComputedStyle(elem).width/height 火狐和chrome支持 和上面的 类似

elem.getBoundingClientRect().width/height 用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left、width、height 6个属性

47.定位
绝对定位absolute:相对于最近的一个定位不为static的父元素来定位
相对定位relative: 相对于自身的位置进行定位
fixed: 相对于浏览器窗口来定位

绝对定位和float一样会脱离文档流,如果有多个层叠加,我们可以使用z-index来控制叠加的顺序

48.样式的引入
1.link引入
写在head标签里


  1. @import方法

3.内联样式
直接在相应的元素标签上style=“xxxxx…”

49.display

块级元素 block
 

59.作用域
作用域: 是指对某一变量或者方法具有访问权限的代码空间 ,也就是变量和函数起作用的区域,包括全局作用域与函数作用域。

全局作用域任何地方都能访问到的对象具有全局作用域
例如:
1.最外层的函数和变量
2.没有定义就直接赋值的变量
3.window对象的属性

作用域链在查找变量或者方法的时候 ,会从 自身 作用域开始找起,如果没有找到,再向上一级 作用域中查找 ,如果还是没有找到,依旧向上查找 ,直到全局作用域,这种层层查找就形成了 作用域链

变量提升?
在全局作用域下 变量定义、函数声明会被提升,先用undefined来赋值
在函数作用域下 变量声明、函数声明、this、arguments会被提升

this的指向问题
看个例子

    var name = 'C'
    var a = {
        name: 'A',
        fn: function () {
            console.log(this.name)
        }
    }

    a.fn() // this指向a 打印A
    a.fn.call({name: 'B'}) // this 指向{name: 'B'}  打印B
    var fn1 = a.fn 
    fn1() // this指向window 打印C

this的指向在 定义的时候无法确定,只有在执行的时候确认

//  作为构造函数
    function Foo(name) {
        this.name = name
    }
    var f = new Foo('hello') //指向构造函数Foo

    // 作为对象的属性
    var obj = {
        name: 'A',
        fn: function () {
            console.log(this.name)
        }
    }
    obj.fn()  // 指向这个对象 obj

    // 作为普通函数
    function fn() {
        console.log(this) // 指向window
    }

    // call bind apply
    function fn2(name, age) {
        console.log('name: ' + name, 'age: ' + age)
        console.log(this)
    }
    fn2.call({x:100}, 'zhangsan', 16) // 指向第一个参数 {x:100}

什么是自由变量?
在当前作用域 下没有定义的变量

动态创建10个 a标签,点击 会弹出相应的标签内容

 // 错误写法 只会弹出10 原因是循环中的点击事件处理函数找不到i 向上一级作用域(全局作用域)找 此时i为10
    var i,a
    for (i = 0; i < 10; i++) {
        a =  document.createElement('a')
        a.innerHTML = i + '
' a.addEventListener('click', function (e) { e.preventDefault() alert(i) }) document.body.appendChild(a) }

正确写法

var i, a
    for (i = 0; i < 10; i++) {
        (function (i) {
            a = document.createElement('a')
            a.innerHTML = i + '
' a.addEventListener('click', function (e) { e.preventDefault() alert(i) }) document.body.appendChild(a) })(i) }

实现一个判断是否是第一次输入的函数

function isFirstInput(val) {
        var _input = []
        return function (val) {  // 这里不用闭包无法保存_input数组的值  不用闭包 每次执行这个函数_input会先变为空数组
            if (_input.indexOf(val) >= 0) {
                return false
            } else {
                _input.push(val)
                return true
            }
        }
    }

    var input = isFirstInput()
    console.log(input('hi'))
    console.log(input('hello'))
    console.log(input('hello'))

60.异步
同步和异步的区别?
同步会阻塞代码执行例如alert,而异步不会例如setTimeout

例如

  console.log(1)
    setTimeout(function () {
        console.log(2)
    }, 0)
    setTimeout(function () {
        console.log(3)
    },200)
    console.log(4)

打印顺序为1 4 2 3

前端需要异步的场景?
1.定时任务 setTimeout 、setInterval
setTimeout只会执行一次
setInterval会周期性的执行
2.请求
ajax、或者动态创建的img
3.事件绑定

61.js内置函数常用api
date

Date.now() // 返回当前时间的毫秒数
    var date = new Date()
    var year = date.getFullYear() + '年'
    var month = date.getMonth() + 1 + '月'
    var day = date.getDate() + '日'
    var hour = date.getHours() + '时'
    var miniute = date.getMinutes() + '分'
    var second = date.getSeconds() + '秒'
    console.log(year + month + day + hour + miniute + second)

Array

    // forEach
    var arr = [1, 2, 3]
    arr.forEach(function (item, index) {
        console.log(index, item)
    })

    // every 用于判断数组中所有的元素是否都满足一个条件
    var every = arr.every(function (item, index) {
       if (item >= 0) {
           return true
       }
    })
    console.log(every)

    // some 判断数组中所有元素,只要有一个满足条件
    var some = arr.some(function (item, index) {
        if (item > 2) {
            return true
        }
    })
    console.log(some)

    var arr2 = [1,3,5,4,3,2]
    // sort 排序 注意会改变原数组
    var sort = arr2.sort(function (a, b) {
        return a - b // 从小到大  b - a 从大到小
    })
    console.log(sort, arr2)

    // map 将所有元素重新组装 返回一个新的数组   不会改变原来的数组
    var map = arr.map(function (item, index) {
        return '[map]' + item
    })
    console.log(map, arr)

    // filter 过滤出满足条件的元素 返回一个新数组 不会改变原来的数组
    var filter = arr.filter(function (item, index) {
        return item > 1
    })
    console.log(filter, arr)

对象
遍历 for in

var obj = {
    a: 1,
    b: 2,
    c: 3
}

for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        console.log(key, obj[key])
    }
}

编写一个20xx-xx-xx格式化日期的函数

    function formatDate() {
        var date = new Date()
        var year =  date.getFullYear()
        var month = _pad(date.getMonth() + 1)
        var day =  _pad(date.getDate())
        var hour = _pad(date.getHours())
        var minutes = _pad(date.getMinutes())
        var seconds = _pad(date.getSeconds())

        function _pad(num) {
            return num > 10 ? num : '0' + num
        }

        return '现在是 ' +  year +  '-' +  month +  '-' + day + ' ' + hour + ':' + minutes + ':' + seconds
    }

    console.log(formatDate())

获取一个长度为10 的 随机数组成的 字符串

    // 获取一个长度为10的随机数 的 字符串
    function getRandom() {
        var random = Math.random()
        random += '0000000000'
        random = random.slice(0, 10)
        return random
    }

    console.log(getRandom())

实现一个能遍历数组也能遍历对象的forEach函数

function myForEach(obj, fn) {
    if (obj instanceof Array) {
        obj.forEach(function (item, index) {
            fn(item, index)
        })
    } else {
        for (var key in obj) {
            fn(key, obj[key])
        }
    }
}

var arr =  [1, 2, 3]
myForEach(arr, function (item, index) {
    console.log(item, index)
})

var obj = {
    a: 1,
    b: 2,
    c: 3
}

myForEach(obj, function (key, value) {
    console.log(key, value)
})

如果要使用.的方式来调用呢?(写在Object原型上)

Object.prototype.myForEach = function (fn) {
    if (this instanceof Array) {
        this.forEach(function (item, index) {
            fn(item, index)
        })
    } else if (this instanceof Object) {
        for (var key in this) {
            if (this.hasOwnProperty(key)) // 不加这个判断 obj上会多一个继承的myForEach方法 会把这个方法名也当成一个key
            fn(key, this[key])
        }
    }
}

var arr =  [1, 2, 3]

arr.myForEach(function (item, index) {
    console.log(index, item)
})

var obj = {
    a: 1,
    b: 2,
    c: 3
}

obj.myForEach(function (key, value) {
    console.log(key, value)
})

return如果没有特别声明 默认返回的是undefined

var i = 0;
function fn(){
	i++;
	if(i < 10){
		fn();
	}else{
		return i;
	}
}

var result = fn();
console.log(result);

result打印结果的是undefined而不是10
修改 return fn()就可以得到正确的结果了

62.DOM
dom的本质?
可以理解为浏览器把拿到的html,结构化为一个浏览器可以识别,并且js可以操作的模型

dom常见操作有哪些?
获取节点

获取property、attribute

获取父元素 子元素

新增节点

删除节点

dom是哪种数据结构?
树形结构 dom树

63.BOM

// 判断浏览器
    var user = navigator.userAgent
    console.log(user.indexOf('Chrome') > 0)

    // screen整个屏幕
    console.log(screen.width, screen.height)

    // location
    // https://mp.csdn.net/postedit/77389373?cid=99&a=b#mid=100
    console.log(location.href) // 获取完整的url
    console.log(location.protocol) // 获取协议名 http:
    console.log(location.hostname) // 主域名 mp.csdn.net
    console.log(location.pathname) // 路径 /postedit/77389373
    console.log(location.search) // 查询内容 ?cid=99&a=b
    console.log(location.hash) // hash #mid=100
    // 完整的url  protocol://hostname[:port]/pathname/[;params][?search]#hash

    // url和uri
    // uri是统一资源标识符 url统一资源定位符  可以将url看做uri的一种方法

64.call、apply、bind区别
三者的作用: 改变函数执行的上下文
call和apply第一个参数相同,决定this的指向,call的后续参数,是传入函数的值;而apply第二个参数是数组,这个数组也就是函数的参数

   var obj = {} // 和这个对象没什么关系 只是表面this指向了它
   function foo(a, b, c) {
       console.log(b)
   }
    foo.call(obj, 1, 2, 3)  // 打印2
    foo.apply(obj, [1, 2, 3]) // 打印2

bind和前两者的区别,bind会返回上下文被改变的函数,但不会立即执行;而前两者是直接执行函数;
bind的参数和call相同。

var a = {
    name: 'van',
    fn: function () {
        console.log(this.name)
    }
}

    a.fn.bind(a) // 没有打印
    a.fn.bind(a)() //  打印van
    a.fn.call(a) // 打印van
    a.fn.apply(a) // 打印

65.ajax
手写一个ajax?

    var xhr = new XMLHttpRequest()
    xhr.open('GET', '/api') // 还有第三个参数 控制异步还是同步 默认true异步
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                alert(xhr.responseText)
            }
        }
    }
    xhr.send()

ajax的四个过程(原理)?
实例化:new一个XMLHttpRequest()的实例,在IE低版本浏览器中是ActiveXObject()。使用if语句判断即可。
open: 第一个参数是请求类型,第二个参数是请求的路径,第三个参数是是否使用异步机制
onreadystatechange通过判断readyState的交互状态以及status的交互状态来触发onreadystatechange事件。
send: 发送请求

Ajax的优缺点
优点:
1.减轻服务器的压力,按需加载资源,减少冗余请求
2.实现 了局部刷新
3.基于xml标准化,被浏览器广泛支持
缺点:
1.由于是局部刷新,浏览器前进后退按钮是没有用的
2.对移动设备兼容不太好

通过哪个属性得到data?
xhr的responseText和responseXML。后者是XML解析了的。
jquery是通过success里的形参

为什么传统的网页需要整个页面刷新?
在ajax之前都是php、java开发的,服务端渲染,前端有变化,服务端要刷新页面

异步刷新实现原理:
当xmlHttpRequest对象的readyState更新时,就会自动执行onreadystatechange绑定的js事件(体现异步),在该事件中操作DOM更新html页面(体现局部刷新)。
下面是一个小例子 ajax向我们自定义的一个json文件发起请求

// test.json
{
  "say": "hello"
}

// 

2.动态创建js

function loadScript(url, callback){ 
var script = document.createElement_x("script") 
script.type = "text/javascript"; 
if (script.readyState){ //IE 
script.onreadystatechange = function(){ 
if (script.readyState == "loaded" || 
script.readyState == "complete"){ 
script.onreadystatechange = null; 
callback(); 
} 
}; 
} else { //Others: Firefox, Safari, Chrome, and Opera 
script.onload = function(){ 
callback(); 
}; 
} 
script.src = url; 
document.body.appendChild(script); 
} 

event-loop
事件轮询,js实现异步的具体解决方案
事件轮询的过程:
1.同步代码, 直接执行,
2.异步函数,先放在异步队列中,分三种情况,如果是例如setTimeout但是没有设置延时事件,可以直接放入异步队列中。 如果有延时时间,需要等延时时间过后才会放入。再例如ajax,只有等加载完返回的内容之后,才放入队列
3.待同步代码执行完后,轮询 执行异步队列中的函数
轮询执行的意思是 同步代码执行完,会查看异步队列中有没有异步函数,有的话,就拿来执行,执行完又会查看异步队列,如此反复轮询

promise
promise的三种状态?
Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已完成)

异常捕获

    function loadImg(src) {
        var promise = new Promise(function (resolve, reject) {
            var img = document.createElement('img')
            img.onload =  function () {
                resolve(img)
            }
            img.onerror = function () {
                reject('图片加载失败')  // 写一个不存在的src会走这一步
            }
            img.src = src
            document.body.appendChild(img)
        })
        return promise
    }

    var src = 'https://www.slurp-ramen.com/wp-content/uploads/2017/06/hello2.png'
    var result = loadImg(src)
    result.then(function (img) {
        console.log(1, img.width) // img对象的属性 width height
        return img  // 不return下面的height会报img不存在的错误
    }).then(function (img) {
        console.log(2, img.height)
    }).catch(function (err) {
        // 统一捕获异常 分为语法报错 throw Error  和 逻辑失败的情况 src不存在等等
        console.log(err)
    })

promise 放在try catch里面有什么结果?
Promise 对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止,也即是说,错误总会被下一个catch语句捕获

promise的串联
先加载src1后加载src2
关键是要return result2
整理_第4张图片

Promise的all和race方法
整理_第5张图片

async和await
asycn和await es7提案中

使用await必须有async标识
await后面必须跟上promise实例
需要安装babel-polyfill

并不是取代了promise 而且还使用了promise,完全同步的写法。没有回调函数。
任何写法的改变 都改变不了js的单线程、异步的本质

虚拟DOM
vdom是什么?为什么存在?
虚拟dom ,用js模拟dom结构, dom变化的对比放在js层来做,提高重绘性能
dom操作影响性能,减少dom操作
基本的dom

整理_第6张图片

js模拟的dom
整理_第7张图片

核心api是什么?

整理_第8张图片
patch函数两种情况 初次渲染 和 后续渲染 (第二个 渲染修改过的节点 没有修改的不做操作)

diff算法
什么是diff算法
是linux的基础命令
在命令行使用diff a.text b.text 会返回两个文件的区别 (linux

window 下面 可以使用 git diff

vdom为什么要使用diff算法
dom操作耗费性能,必须减少dom操作
找出本次dom需要更新的节点更新,其他不更新
这个找出的过程就需要diff算法

diff算法实现流程
diff实现 patch(container, vnode) patch(vnode, newVnode)

Vue三要素?
响应式: vue如何监听到data的每个属性变化?
什么是响应式?
修改data后,vue立刻监听到
data属性被代理到vm上
核心是 Object.defineProperty


    

{{name}}

{{age}}

注:jq-load2.html、jq-load3.html与jq-load.html代码基本一致,只在#container的div里展示的内容不一样。

jq-load.js:

$('nav a').on('click', function(e) {         
 e.preventDefault(); // 阻止链接跳转
 var url = this.href; // 保存点击的地址

 $('nav a.current').removeClass('current');  
 $(this).addClass('current');           

 $('#container').remove();             
 $('#content').load(url + ' #container').fadeIn('slow'); // 加载新内容,url地址与该地址下的选择器之间要有空格,表示该url下的#container
});

注:此种方法用到了一些html5里面的新标记,在js中创建它们不再赘述。

第二种:

如果网页的左侧有一个列表,点击列表使右侧的内容进行切换,如果右侧的内容过多,不适合做选项卡,这时候用.load()局部刷新最好不过了。上代码。

user.html:



  
    个人中心
    
    
    
  
  
    
  • 用户中心
  • 账户信息
  • 交易记录
  • 消息中心
user.js: $(function(){ $(".userMenu").on("click", "li", function(){ var sId = $(this).data("id"); //获取data-id的值 window.location.hash = sId; //设置锚点 loadInner(sId); }); function loadInner(sId){ var sId = window.location.hash; var pathn, i; switch(sId){ case "#center": pathn = "user_center.html"; i = 0; break;        case "#account": pathn = "user_account.html"; i = 1; break; case "#trade": pathn = "user_trade.html"; i = 2; break; case "#info": pathn = "user_info.html"; i = 3; break;        default: pathn = "user_center.html"; i = 0; break; } $("#content").load(pathn); //加载相对应的内容 $(".userMenu li").eq(i).addClass("current").siblings().removeClass("current"); //当前列表高亮 } var sId = window.location.hash; loadInner(sId); }); user_center.html:
用户中心 ……

判断{}{}? [][]? null==undefined?

 // 以下全是false
    console.log([] == [])
    console.log({} == {})
    console.log(NaN == NaN)

中间固定,两边自适应
1浮动加负边距




    
    中间固定宽度,两边自适应布局-浮动加负边距
    


    

测试居中

2.flex




    
    中间固定宽度,两边自适应布局-弹性盒子模型
    


    

测试剧中

jQuery的.extend,.fn.extend区别
$.extend(obj);是为了扩展jquery本身,为类添加新的方法
$.fn.extend(obj);给JQUERY对象添加方法。

  $.extend({

        add:function(a,b){

            return a+b;
        }

    })

    $.add(5,8) //return  13  直接通过$.来调用

//
$.fn.extend({

    clickwhile:function(){

        $(this).click(function(){

             alert($(this).val()) 

        })

    }

})

$('input').clickwhile();//当点击输入框会弹出该对象的Value值  通过jquery对象.来实现

手写一个递归函数(考察arguments.callee,以及arguments的解释)

求函数阶乘

function factorial (num){
      if(num<=1){
            return 1;
      }else{
      return arguments.callee(num-1)*num;
    }
}

arguments.callee是指向正在执行的函数的指针,可以用它来实现对函数的递归调用。
标识符arguments是指向实参对象的引用,实参对象是一个类数组,可以通过数字下标访问传入函数的实参值。(省略的实参都是undefined,多出的参数自动省略。)
注意:arguments.callee只能用于非严格模式下,在严格模式下,不能通过脚本访问arguments.callee。可以使用命名函数表达式来解决。
格式:var 变量=(函数f);//即把函数赋值给了另一个变量,函数的名字f仍然有效,所以递归调用可以照样完成。

var factorial=(function f(num){
        if(num<=1) {return 1;
        }else{
              return f(num-1)*num;
        }
});

实现一个暴露内部变量,而且外部可以访问修改的函数(get和set,闭包实现)

var person=(function(){
    var name='xiaoming';
    return{
        getName:function(){
            return name;
        },
        setName:function(newName){
            name=newName;
            return newName;
        }
    };
})();
console.log(person.name);
console.log(person.getName());
console.log(person.setName('xiaohua'));

前后端分离的意义以及对前端工程化的理解
Q1:
1、项目一开始制作前端页面时,不再需要后台配置服务器环境。
2、前端不需要向后台提供模板,或是后台在前端html中嵌入后台代码。
3、后台没有时间提供接口时,前端可以将数据先写死或者调用本地的json文件即可。
4、页面的增加和路由的修改可以在前端实现,开发更加灵活。
5、通过前端路由配置,我们可以实现页面的按需加载,无需一开始加载页面便加载网站的所有资源,服务器也不再需要解析前端页面。
6、通过目前主流的MVC框架,我们可以非常快速的定位及发现问题的所在,客户端问题不再需要后台人员参与及调试,代码重构及可维护性强。
Q2:
完整的前端工程体系应该包括:
1、统一的开发规范;
2、组件化开发;
3、构建流程。

手写类式继承并解释。
写一个组合继承 说一下借用 构造函数继承 和原型链继承的 缺点
再说一下es6的class继承

js轮播实现思路
图片轮播的原理就是图片排成一行,然后准备一个只有一张图片大小的容器,对这个容器设置超出部分隐藏(overflow:hidden),在设定定时器或点击左右方向键来让这些图片整体左移或右移,这样呈现出来的效果就是图片在轮播。
代码
http://www.cnblogs.com/zhuzhenwei918/p/6416880.html?utm_source=tuicool&utm_medium=referral

(==)和(!=)运算规则

1、当两个操作数类型相同时,直接比较,相等返回true,不相等返回false。
2,、当两个操作数类型不同时,先转换成相似类型再进行比较。
转换规则:
1)操作数是布尔值,比较之前先转换为数值。false转换为0,true转换为1。
2)操作数是字符串和数值,比较之前先将字符串转换为数值。
3)操作数是对象和非对象,调用对象的valueof()方法,用得到的基本类型值进行比较或按照前面的规则进行转换。
比较规则:
1)nullundefined
2)比较相等性之前,不能将null或者undefined转换成其他任何值。
3)有一个操作数为NaN,则
结果为false,!=结果为true。NaN!=NaN
4)两个操作数都是对象,仅当两个操作数指向同一个对象时返回true,否则,返回false。

用promise手写ajax

// ajax函数将返回Promise对象:
function ajax(method, url, data) {
    var request = new XMLHttpRequest();
    return new Promise(function (resolve, reject) {
        request.onreadystatechange = function () {
            if (request.readyState === 4) {
                if (request.status === 200) {
                    resolve(request.responseText);
                } else {
                    reject(request.status);
                }
            }
        };
        request.open(method, url);
        request.send(data);
    });
}


var log = document.getElementById('test-promise-ajax-result');
var p = ajax('GET', '/api/categories');
p.then(function (text) { // 如果AJAX成功,获得响应内容
    log.innerText = text;
}).catch(function (status) { // 如果AJAX失败,获得响应代码
    log.innerText = 'ERROR: ' + status;
});

js写一个树的遍历
!!!

72.归并排序
具体算法描述如下:

<1>.把长度为n的输入序列分成两个长度为n/2的子序列;
<2>.对这两个子序列分别采用归并排序;
<3>.将两个排序好的子序列合并成一个最终的排序序列。

function  mergeSort(arr) {
    var len = arr.length
    if (len < 2) {
        return arr
    }
    var middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle)
    return merge(mergeSort(left), mergeSort(right))
}

function merge(left, right) {
    var result = []
    while (left.length && right.length) {
        if (left[0] < right[0]) {
            result.push(left.shift())  // shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
        } else {
            result.push(right.shift())
        }
    }

    while(left.length) {
        result.push(left.shift())
    }
    while(right.length) {
        result.push(right.shift())
    }
    return result
}

var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(mergeSort(arr));

参考https://juejin.im/post/57dcd394a22b9d00610c5ec8#heading-10

原生js实现jquery里面的insertAfter
insertAfter

//某个元素后插入
    insertAfter: function (newElement, targetElement) {
        targetElement=SeeUtils.getElObj(targetElement);
        if(targetElement==null){
            return void(0);
        }

        var parent = targetElement.parentNode;
        // 如果最后的节点是目标元素,则直接添加
        if (parent.lastChild == targetElement) {
            if(typeof newElement === 'string'){
                var temp = document.createElement('div');
                temp.innerHTML = newElement;
                // 防止元素太多 进行提速
                var frag = document.createDocumentFragment();
                while (temp.firstChild) {
                    frag.appendChild(temp.firstChild);
                }
                parent.appendChild(frag);
            }else{
                parent.appendChild(newElement)
            }
        } else {
            if(typeof newElement === 'string'){
                var temp = document.createElement('div');
                temp.innerHTML = newElement;
                // 防止元素太多 进行提速
                var frag = document.createDocumentFragment();
                while (temp.firstChild) {
                    frag.appendChild(temp.firstChild);
                }
                parent.insertBefore(frag, targetElement.nextSibling);
            }else{
                //如果不是,则插入在目标元素的下一个兄弟节点 的前面
                parent.insertBefore(newElement, targetElement.nextSibling);
            }
        }
    },

insertBefore方法实现:

 //某个元素前插入
    insertBefore:function(newElement, targetElement){
        targetElement=SeeUtils.getElObj(targetElement);
        if(targetElement==null){
            return void(0);
        }
        var parent = targetElement.parentNode;
        // 如果最后的节点是目标元素,则直接添加
        if(typeof newElement === 'string'){
            var temp = document.createElement('div');
            temp.innerHTML = newElement;
            // 防止元素太多 进行提速
            var frag = document.createDocumentFragment();
            while (temp.firstChild) {
                frag.appendChild(temp.firstChild);
            }
            parent.insertBefore(frag, targetElement);
        }else{
            parent.insertBefore(newElement, targetElement);
        }
    },

73. 去除空格?
1.正则表达式
去除所有空格: str = str.replace(/\s*/g,"");

去除两头空格: str = str.replace(/^\s*|\s*$/g,"");

2.trim()方法
var str = ‘sfa faf a ’
console.log(’|’ + str.trim() + ‘|’)

url的正则?

var match = /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?$

**邮箱的正则 **

var reg = /^(\w)+(\.\w+)*@(\w)+((\.\w{2,3}){1,3})$/;
 var email = "[email protected]";
 console.log(reg.test(email));  // true  

如何获取当前浏览器URL中查询字符串中的参数?

function showWindowHref() {
    var sHerf = window.location.href
    var args = sHerf.split('?')
    if (args[0] === sHerf)  return// 不带参数
    var arr = args[1].split('&')
    var obj = {}
    for (var i = 0; i < arr.length; i++) { // key=value形式的参数
        var arg = arr[i].split('=')
        obj[arg[0]] = arg[1]
    }
    return obj
}
var href = showWindowHref()
    console.log(href)

怎样添加、移除、移动、复制、创建和查找节点?
1)创建新节点

createDocumentFragment() //创建一个DOM片段
  createElement() //创建一个具体的元素
  createTextNode() //创建一个文本节点

2)添加、移除、替换、插入
  appendChild() //添加
  removeChild() //移除
  replaceChild() //替换
  insertBefore() //插入

3)查找
  getElementsByTagName() //通过标签名称
  getElementsByName() //通过元素的Name属性的值
  getElementById() //通过元素Id,唯一性

比较typeof与instanceof?
相同点:JavaScript 中 typeof 和 instanceof 常用来判断一个变量是什么类型的。

typeof的定义和用法:返回值是一个字符串,用来说明变量的数据类型。
typeof只能辨别值类型string number boolean undefined 对引用类型只能区分function 其他引用类型返回的是object null也返回object

Instanceof定义和用法:instanceof 用于判断一个变量是否属于某个对象的实例。

判断一个字符串中出现次数最多的字符,统计这个次数?

var str = 'asdfssaaasasasasaa';
var json = {};
for (var i = 0; i < str.length; i++) {
    if(!json[str.charAt(i)]){
       json[str.charAt(i)] = 1;
    }else{
       json[str.charAt(i)]++;
    }
};
var iMax = 0;
var iIndex = '';
for(var i in json){
    if(json[i]>iMax){
         iMax = json[i];
         iIndex = i;
    }
}        
console.log('出现次数最多的是:'+iIndex+'出现'+iMax+'次');

74.jquery相关
jQuery 库中的 $() 是什么?
 $() 函数是 jQuery() 函数的别称。
 $() 函数用于将任何对象包裹成 jQuery 对象,就可以使用jquery对象的一些方法。
 可以将一个选择器字符串传入 $() 函数,它会返回一个包含所有匹配的 DOM 元素数组的 jQuery 对象。
 
如何找到所有 HTML select 标签的选中项?

$('[name=selectname] :selected')

JQuery有几种选择器?
(1)、基本选择器:#id,class,element,*;

(2)、层次选择器:parent > child,prev + next ,prev ~ siblings

(3)、基本过滤器选择器::first,:last ,:not ,:even ,:odd ,:eq ,:gt ,:lt

(4)、内容过滤器选择器: :contains ,:empty ,:has ,:parent

(5)、可见性过滤器选择器::hidden ,:visible

(6)、属性过滤器选择器:[attribute] ,[attribute=value] ,[attribute!=value] ,[attribute^=value] ,[attribute$=value] ,[attribute*=value]

(7)、子元素过滤器选择器::nth-child ,:first-child ,:last-child ,:only-child

(8)、表单选择器: :input ,:text ,:password ,:radio ,:checkbox ,:submit 等;

(9)、表单过滤器选择器::enabled ,:disabled ,:checked ,:selected

$(document).ready()方法和window.onload有什么区别?
(1)、window.onload方法是在网页中所有的元素(包括元素的所有关联文件)完全加载到浏览器后才执行的。

(2)、$(document).ready() 方法可以在DOM载入就绪时就对其进行操纵,并调用执行绑定的函数。

如何用jQuery禁用浏览器的前进后退按钮?


写出一个简单的$.ajax()的请求方式?

$.ajax({
    url:'http://www.baidu.com',
    type:'POST',
    data:data,
    cache:true,
    headers:{},
    beforeSend:function(){},
    success:function(){},
    error:function(){},
    complete:function(){}
}); 

jquery实现的一个简单todo-list

    实现extend方法
    jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象

     var obj1 = {a: 'obj2',b:'2'};
        var obj2 = {a: 1, name: 'obj3'};
        var obj3 = {a: 3, hah: 'hah'}
        function extend() { // 参数没写死 所以支持传多个参数
            var  len = arguments.length
            var  target = arguments[0] || {}
            if (typeof target !== 'object' && typeof target !== 'function') { // 如果传入的参数是字符串、数字、布尔值等等
                target = {}
            }
    
            if (len === 1) { // 只有一个参数
                target = this
                i--
            }
            for (var i = 1; i < len; i++) {
                var source = arguments[i]
                for (var key in source) {
                    if (Object.prototype.hasOwnProperty.call(source, key)) {
                        target[key] = source[key]
                    }
                }
            }
            return target
        }
    
        console.log(extend(obj1, obj2, obj3)) // 相同的key会被后者覆盖  
    

    实现拖拽功能,比如把5个兄弟节点中的最后一个节点拖拽到节点

    • 1
    • 2
    • 3
    • 4
    • 5
    li { width: 100px; height: 100px; list-style: none; margin: 50px 0; border: 1px solid #000; } function drag(elem) { elem.addEventListener('dragstart', function (e) { e.dataTransfer.setData('text', this.id) }) elem.addEventListener('dragover', function (e) { e.preventDefault() }) elem.addEventListener('drop', function (e) { var data = e.dataTransfer.getData('text') ul.insertBefore(document.getElementById(data), e.target) }) }

    单页面应用实现路由 的方法
    不管是vue还是react还是angular
    1.hash方法 通过location.hash和hashchange事件

    
    
    
        
        Title
        
    
    
    
    
    
    
    
    
    1. h5的 history api

    和上面类似 主要使用了history的 pushstate和replaceState
    参考https://www.cnblogs.com/zhuzhenwei918/p/7421430.html

    编写分页器组件的时候,为了减少服务端查询次数,点击“下一页”怎样能确保还有数据可以加载(请求数据不会为空)?
    第一次发送两个请求,一个正常请求需要的数据,第二个是请求 total也就是总数,
    第一个请求带上start和length参数,start是从第几条开始,length就是每页查询几条数据,每次发送请求的时候可以计算start + length * 页数 < total,小于的话就没有下一页,大于就还有数据

    requireJS的基本原理
    requireJS是使用创建script元素,通过指定script元素的src属性来实现加载模块的。

    题目
    Promise本身是同步的,他的then方法和catch方法是异步的

        setTimeout(function() {
            console.log(1)
        }, 0);
    
        new Promise(function executor(resolve) {
            console.log(2);
            for( var i=0 ; i<10000 ; i++ ) {
                i == 9999 && resolve();
            }
            console.log(3);
        }).then(function() {
            console.log(4);
        });
    
        console.log(5);
    

    打印结果 2 3 5 4 1

    如何对网站的文件和资源进行优化?

    1.将需要频繁加载的多个图片合成为1个单独的图片,需要加载时可以采用:background:url(…) no-repeat x-offset y-offset或者background-position的形式加载即可将这部分图片加载的HTTP请求缩减为1个;
    2.将静态资源压缩,最小化;
    3.浏览器对于同一个域名的请求是有并发限制的,所以将资源放在多个域名下;
    4.图片延迟加载;
    5.使用 CDN 托管,Content Delivery Network,即内容分发网络。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度;

    浏览器 Js是怎么解析的?什么时候执行的?
    解析过程中遇到js标签会下载解析执行
    JavaScript解析引擎就是能够“读懂”JavaScript代码,并准确地给出代码运行结果的一段程序

    css3实现360度旋转

    
    
    
        
        Title
        
    
    
    
    效果一:360°旋转
    效果二:放大
    效果三:旋转放大
    效果四:上下左右移动

    position:absolute和float属性的异同

    共同点:对内联元素设置float和absolute属性,可以让元素脱离文档流,并且可以设置其宽高。

    不同点:float仍会占据位置,absolute会覆盖文档流中的其他元素。

    兼容问题
    1.不同浏览器的margin和padding不同
    解决办法*{margin:0;padding:0;}

    2.ie6双倍边距问题

    会出现实际margin大于设置的margin
    解决办法 添加 _display:inline

    3.设置较小高度标签(一般小于10px),在IE6,IE7中高度超出自己设置高度
    解决办法 给超出高度的元素添加overflow:hidden或者设置一个小于高度的line-height

    4.IE6下图片的下方有空隙
    解决方法:给img设置display:block;

    5.左侧div浮动left,右边DIV可以接着横向排列,形成典型一列固定,第二列自适应,IE6出现之间3px间隙
    对左侧left的盒子补上_margin-right: -3px;

    6.图片默认有间距
    几个img标签放在一起的时候,有些浏览器会有默认的间距,加了问题一中提到的通配符也不起作用。
    解决: 使用float属性为img布局

    1. 标签最低高度设置min-height不兼容
      因为min-height本身就是一个不兼容的CSS属性,所以设置min-height时不能很好的被各个浏览器兼容
      如果我们要设置一个标签的最小高度200px,需要进行的设置为:{min-height:200px; height:auto !important; height:200px; overflow:visible;}

    8.IE ol的序号全为1, 不递增
    解决: li设置样式{display: list-item}

    CSS hack的原理
    可以针对不同的浏览器来应用不同的CSS。

    跨域请求资源的方法:
    (1)、porxy代理

    定义和用法:proxy代理用于将请求发送给后台服务器,通过服务器来发送请求,然后将请求的结果传递给前端。

    实现方法:通过nginx代理;

    注意点:1、如果你代理的是https协议的请求,那么你的proxy首先需要信任该证书(尤其是自定义证书)或者忽略证书检查,否则你的请求无法成功。

    (2)、CORS 【Cross-Origin Resource Sharing】

    定义和用法:是现代浏览器支持跨域资源请求的一种最常用的方式。

    使用方法:一般需要后端人员在处理请求数据的时候,添加允许跨域的相关操作。如下:

    res.writeHead(200, {
    “Content-Type”: “text/html; charset=UTF-8”,
    “Access-Control-Allow-Origin”:‘http://localhost’,
    ‘Access-Control-Allow-Methods’: ‘GET, POST, OPTIONS’,
    ‘Access-Control-Allow-Headers’: ‘X-Requested-With, Content-Type’
    });
    (3)、jsonp

    定义和用法:通过动态插入一个script标签。浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行(没有阻塞的情况下)。

    特点:通过情况下,通过动态创建script来读取他域的动态资源,获取的数据一般为json格式。

    实例如下:

    缺点:

    1、这种方式无法发送post请求(这里)

    2、另外要确定jsonp的请求是否失败并不容易,大多数框架的实现都是结合超时时间来判定。

    解释下浏览器是如何判断元素是否匹配某个 CSS 选择器?

    浏览器先产生一个元素集合,这个集合往往由最后一个部分的索引产生(如果没有索引就是所有元素的集合)。然后向上匹配,如果不符合上一个部分,就把元素从集合中删除,直到真个选择器都匹配完,还在集合中的元素就匹配这个选择器了。

    css动画和js动画的优缺点
      CSS3的动画

    优点:
    1.在性能上会稍微好一些,浏览器会对CSS3的动画做一些优化(比如专门新建一个图层用来跑动画)
    2.代码相对简单
    缺点:
    1.在动画控制上不够灵活
    2.兼容性不好
    3.部分动画功能无法实现(如滚动动画,视差滚动等)
      JavaScript的动画

    优点:
    1.控制能力很强,可以单帧的控制、变换
    2.兼容性好,写得好完全可以兼容IE6,且功能强大。
    缺点:
    计算没有css快,另外经常需要依赖其他的库。
     结论

    所以,不复杂的动画完全可以用css实现,复杂一些的,或者需要交互的时候,用js会靠谱一些

    有哪些隐藏内容的方法(同时还要保证屏幕阅读器可用)
    答:

    display:none或者visibility:hidden,overflow:hidden。

    1.display:none;的缺陷
    搜索引擎可能认为被隐藏的文字属于垃圾信息而被忽略
    屏幕阅读器(是为视觉上有障碍的人设计的读取屏幕内容的程序)会忽略被隐藏的文字。
    2.visibility: hidden ;的缺陷
    隐藏的内容会占据他所应该占据物理空间
    3.overflow:hidden;一个比较合理的方法
    例:.texthidden { display:block; overflow: hidden; width: 0; height: 0; }
    将宽度和高度设定为0,然后超过部分隐藏,就会弥补上述一、二方法中的缺陷,也达到了隐藏内容的目的

    img设置属性title和alt的区别?
    alt 如果无法显示图像, 浏览器将显示替代文本.
    tiltle为元素提供附加的提示信息,用于鼠标滑到元素上的时候显示。

    如果网页内容需要多语言,要怎么做?
      答: 采用统一编码utf-8模式

    *data-属性的作用
    data-为前端开发者提供自定义的属性,这些属性集可以通过对象的dataset属性获取

    js有几种函数调用方式?
    方法调用模型 var obj = { func : function(){};} obj.func()
    函数调用模式  var func = function(){} func();
    apply/ call调用模式

    ** 如果在同一个元素上绑定了两个click事件, 一个在捕获阶段执行, 一个在冒泡阶段执行. 那么当触发click条件时, 会执行几个事件? 执行顺序是什么?**

    绑定在目标元素上的事件是按照绑定的顺序执行的!!!

    构造函数里定义function和使用prototype.func的区别?
    直接调用function,每一个类的实例都会拷贝这个函数,弊端就是浪费内存
    prototype.func 把函数写到原型上 所有的实例共享,节省了内存。

    var obj = {a : 1}; (function (obj) { obj = {a : 2}; })(obj); //问obj怎么变?
    答: 外部的obj不变. 因为匿名函数中obj传入参数等于是创建了一个局部变量obj, 里面的obj指向了一个新的对象 . 如果改成(function () { obj = {a : 2}; })(obj); 就会变了

    var obj = { a:1, func: function() { (function () { a=2; }(); }} ; obj.fun() //a 怎么变? 匿名函数里的this 是什么?

    答: obj里的a不会变. 匿名函数里的this指向全局对象window. 这等于是给window加了一个名为a的属性

    用原生js封装一个能获取元素到页面最上方和最左侧的函数,再用JQ封装一个同样的函数
    原生:

    function offset(obj){
     var l = 0;
     var t = 0;
     while(obj){
     l+=obj.offsetLeft;
     t+=obj.offsetTop;
     obj = obj.offsetParent;
     }
     return {left:l,top:t};
    }
    jQuery:
    
    $().offset().left;$().offset().top
    

    浏览器页面有哪三层构成,分别是什么,作用是什么?
    浏览器页面构成:结构层、表示层、行为层
    分别是:HTML、CSS、JavaScript+

    请说明下面各种情况的执行结果,并注明产生对应结果的理由。
    function doSomething() {

    alert(this);

    }

    ① element.onclick = doSomething,点击element元素后。 // element

    ② element.onclick = function() {doSomething()}, 点击element元素后。 // wido

    ③ 直接执行doSomething()。** // window

    image和canvas在处理图片的时候有什么区别?
    答:

    image加载图片
    canvas绘制图片

    响应式布局的时候,轮播图使用两张不同的图片去适配大屏幕和超小屏幕,还是一张图片进行压缩适配不同终端,说明原因?
    最好使用两张不同大小的图片去适配大屏幕和超小屏幕,这样可以针对不同设备的屏幕大小,来加载响应的图片,减少超小屏幕设备的网络流量消耗,加快响应速度,同时防止图片在大屏幕下分辨率不够导致失真的问题。

    alert(1&&2),alert(1||0)
    具体我不记得了反正就这两个,我以为考的是纯粹的与运算和或运算,后来发现太天真了

    alert(1&&2)的结果是2
    只要“&&”前面是false,无论“&&”后面是true还是false,结果都将返“&&”前面的值;
    只要“&&”前面是true,无论“&&”后面是true还是false,结果都将返“&&”后面的值;
    alert(0||1)的结果是
    只要“||”前面为false,不管“||”后面是true还是false,都返回“||”后面的值
    只要“||”前面为true,不管“||”后面是true还是false,都返回“||”前面的值。

    mouseenter和mouseover的区别

    输出结果
    var baz=3;
    var bazz={
    baz: 2,
    getbaz: function() {
    return this.baz
    }
    }
    console.log(bazz.getbaz())
    var g=bazz.getbaz;
    console.log(g()) ;
    //第一个输出是2,第二个输出是3,这题考察的就是this的指向,函数作为对象本身属性调用的时候this指向对象,作为普通函数调用的时候就指向全局了

    写出position不同值和区别
    突然想到还有inherit,当时忘记了,后来面试的时候又重新问了我一下

    absolute: 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定。(不占位)
    relative: 生成相对定位的元素,相对于其正常位置进行定位。因此,”left:20” 会向元素的 LEFT 位置添加 20 像素。(占位)
    static:默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)inherit:规定应该从父元素继承 position 属性的值。
    fixed:生成绝对定位的元素,相对于浏览器窗口进行定位。元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定。

    什么是响应式布局
    一个网站能够兼容多个终端

    小贤是一条可爱的小狗(Dog),它的叫声很好听(Wow),每次看到主人的时候就会乖乖叫一声(Yelp),从这段描述可以得到以下对象:

    function Dog(){
        this.wow = function(){
            alert('Wow');
        }
        this.yelp = function(){
            this.wow();
        }
    }
    

    小芒和小贤一样,原来也是一条可爱的小狗,可是突然有一天疯了(MadDog),一看到人就会每隔半秒叫一声(wow)地不停交换(yelp)。请根据描述,按示例的形式用代码来实现(提示关键字:继承,原型,setInterval)

    function Maddog () {
        this.yelp = function () {
            var me = this;
            setInterval(function () {
                me.wow();
            }, 500);
        };
    }
    Maddog.prototype = new Dog();
    var bbb = new Maddog();
    bbb.yelp();
    

    同版本的jQuery.js文件和jQuery.min.js有何不同?
    相同:这两个文件提供相同的jQuery的功能,即在函数调用上没有区别。
    不同:jQuery.js文件,适合让程序员阅读。jQuery.min.js文件,通过压缩和删除所有的空格,以节省带宽和空间,使得文件更小,用于网络传输,不适合程序员阅读。
    何时使用jquery.js,何时使用jquery.min.js?
    开发调试场景下:用jQuery.js文件,因为你想调试,能够看到javascript代码。
    生产部署环境下:用jQuery.min.js文件,可减少网络宽度,加快网页加载速度。

    **在jQuery中," " 符 号 代 表 什 么 ? ∗ ∗ 在 j Q u e r y 中 , " "符号代表什么?** 在jQuery中," "jQuery""符号是一个jQuery的别名,默认的jQuery类库以$开头。

    为何要使用jQuery.noConflict()?
    有很多类似jQuery一样的类库,如MooTools, Backbone, Sammy, Cappuccino, Knockout 。这些类库中,有的也使用了$符号,如果同时使用,则会导致命名冲突。

    为了解决这个冲突,需要用到jQuery.noConflict(),这样就不依赖$这个默认符号了。例如:

    jQuery.noConflict();
    (function($){

    })(jQuery);

    同一个页面中,能否加载多个个document.ready事件?
    可以。

    整理_第13张图片

    整理_第14张图片

    .javascript的本地对象,内置对象和宿主对象
    本地对象为array obj regexp等可以new实例化
    内置对象为gload Math 等不可以实例化的
    宿主为浏览器自带的document,window 等

    .写出几种IE6 BUG的解决方法
    1.双边距BUG float引起的 使用display
    2.3像素问题 使用float引起的 使用dislpay:inline -3px
    3.超链接hover 点击后失效 使用正确的书写顺序 link visited hover active
    4.Ie z-index问题 给父级添加position:relative
    5.Png 透明 使用js代码 改
    6.Min-height 最小高度 !Important 解决’
    7.select 在ie6下遮盖 使用iframe嵌套
    8.为什么没有办法定义1px左右的宽度容器(IE6默认的行高造成的,使用over:hidden,zoom:0.08 line-height:1px)

    js 字符串操作函数
      我这里只是列举了常用的字符串函数,具体使用方法,请参考网址。

    concat() – 将两个或多个字符的文本组合起来,返回一个新的字符串。

    indexOf() – 返回字符串中一个子串第一处出现的索引。如果没有匹配项,返回 -1 。

    charAt() – 返回指定位置的字符。

    lastIndexOf() – 返回字符串中一个子串最后一处出现的索引,如果没有匹配项,返回 -1 。

    match() – 检查一个字符串是否匹配一个正则表达式。

    substr() 函数 – 返回从string的startPos位置,长度为length的字符串

    substring() – 返回字符串的一个子串。传入参数是起始位置和结束位置。

    slice() – 提取字符串的一部分,并返回一个新字符串。

    replace() – 用来查找匹配一个正则表达式的字符串,然后使用新字符串代替匹配的字符串。

    search() – 执行一个正则表达式匹配查找。如果查找成功,返回字符串中匹配的索引值。否则返回 -1 。

    split() – 通过将字符串划分成子串,将一个字符串做成一个字符串数组。

    length – 返回字符串的长度,所谓字符串的长度是指其包含的字符的个数。

    toLowerCase() – 将整个字符串转成小写字母。

    toUpperCase() – 将整个字符串转成大写字母。

    怎样添加、移除、移动、复制、创建和查找节点?
    1)创建新节点

    createDocumentFragment() //创建一个DOM片段
      createElement() //创建一个具体的元素
      createTextNode() //创建一个文本节点

    2)添加、移除、替换、插入
      appendChild() //添加
      removeChild() //移除
      replaceChild() //替换
      insertBefore() //插入

    3)查找
      getElementsByTagName() //通过标签名称
      getElementsByName() //通过元素的Name属性的值
      getElementById() //通过元素Id,唯一性
      querySelector()
      querySelectorAll()

    判断str中出现最多的字符

        var str = 'asdfssaaasasasasaa';
        function f(str) {
            var result = {} // key为字符 value为出现次数
            for (var i = 0; i < str.length; i++) {
                if (!result[str.charAt(i)]) { // 返回指定位置的字符。
                    result[str.charAt(i)] = 1
                } else {
                    result[str.charAt(i)]++
                }
            }
    
            var max = 0
            var index = ''
            for (var k in result) {
                if (result[k] > max) {
                    max = result[k]
                    index = k
                }
            }
            console.log('出现次数最多的是:'+index+'出现'+max+'次');
        }
        f(str)
    
    

    Array相关的属性和方法
    constructor

    var arr = [],
        obj = {},
        fun = function () {
    
        }
        myConstructor(arr)
        console.log(arr.constructor) // ƒ Array() { [native code] }
        console.log(obj.constructor) // ƒ Object() { [native code] }
        console.log(fun.constructor) // ƒ Function() { [native code] }
    
    

    length
    prototype

    concat() 连接两个或更多的数组,并返回结果。
    join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
    pop() 删除并返回数组的最后一个元素。
    shift() 删除并返回数组的第一个元素
    push() 向数组的末尾添加一个或更多元素,并返回新的长度。
    unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
    reverse() 颠倒数组中元素的顺序。
    slice() 从某个已有的数组返回选定的元素
    sort() 对数组的元素进行排序

    splice() 删除元素,并向数组添加新元素。
    语法:arrayObject.splice(index,howmany,item1,…,itemX)
    index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
    howmany:必需。要删除的项目数量。如果设置为 0,则不会删除项目。
    item1, …, itemX:可选。向数组添加的新项目。

    求数组的最值
    最大值

    var arr = [3,43,23,45,65,90];
    var max = Math.max.apply(null,arr);
    console.log(max);
    // 90
    

    // 最小值

    var arr = [3,43,23,45,65,90];
    var min = Math.min.apply(null,arr);
    console.log(min);
    // 3
    

    冒泡排序

    var arr = [3, 1, 4, 6, 5, 7, 2];
    
    function bubbleSort(arr) {
        var len = arr.length;
        for (var i = len; i >= 2; --i) {
            for (var j = 0; j < i - 1; j++) {
                if (arr[j + 1] < arr[j]) {
                    var temp;
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        return arr;
    }
    

    不使用reverse实现数组反转

    方法一:
    
    var arr = [1,2,3,4];
    var arr2 = [];
    while(arr.length) {
        var num = arr.pop(); //删除数组最后一个元素并返回被删除的元素
        arr2.push(num);
    }
    console.log(arr2);
    // [4, 3, 2, 1]
    方法二:
    
    var arr = [1,2,3,4];
    var arr2 = [];
    while(arr.length){
        var num = arr.shift(); //删除数组第一个元素并返回被删除的元素
        arr2.unshift(num);
    }
    console.log(arr2);
    

    Math对象的常用方法

    Math.PI:返回圆的周长与其直径的比值(圆周率π)
    Math.abs():返回数字的绝对值

    Math.ceil():返回大于等于数字参数的最小整数(取整函数),对数字进行上舍入

    Math.floor():返回小于等于数字参数的最大整数,对数字进行下舍入

    Math.round():返回数字最接近的整数,四舍五入

    Math.max():返回数个数字中较大的值

    Math.min():返回数个数字中较小的值

    Math.random():返回0和1之间的伪随机数

    有一个长度为100的数组,求前20个元素之和

    r = arr.slice(0,20).reduce(function(x,y){ // reduce() 方法接收一个函数作为累加器,
        return x+y;
    });
    alert(r);
    

    随机生成100-300的整数

     var x = 300;     
        var y = 100;     
        var rand = parseInt(Math.random() * (x - y + 1) + y);     
       console.log(rand);   
    

    实现一个js方法,将下面的数据根据年龄(age)从小到大排序

    var data = [{"name":"张三","age":"23岁"},{"name":"李四","age":"21岁"},{"name":"王五","age":"33岁"}];
    function compare(property){
        return function(a,b){
            var value1 = a[property];
            var value2 = b[property];
            if(value1 > value2){
            return 1;
            }else if(value1 < value2){
            return -1;
            }else{
            return 0;
        };
        }
    }
    console.log(data.sort(compare("age")))
    

    什么是DOM和BOM
    dom是文档对象模型(Document Object Model)的简称。DOM把整个页面规划成由节点层级构成的文档,DOM方法和属性你可以访问,修改,删除,添加页面元素
    BOM是browser object model的缩写,简称浏览器对象模型,BOM提供了独立于内容而与浏览器窗口进行交互的对象。

    jsonp为什么不是真正的ajax
    Ajax的核心是通过XMLHttpRequest获取数据,而JSONP的核心则是动态添加

    “==”与“===”的不同

    “==”只要数值相同类型不必相同,“===”类型和数值都要相同
    

    用js实现千位分隔符?

    str = 12345678;
    newStr = str.split("").reverse().join("").replace(/([0-9]{3})/g,"$1,").split("").reverse().join("");
    

    常见的网页图像格式有 ico、jpg、png、gif,说说他们各自的应用场景
    ico:一般作为网页的标题上面的图标出现,文件 favicon.ico一般存放在网站根目录
    jpg:非常适合作为储存像素色彩丰富的图片、例如照片等等
    png:分为 png-8 以及 png-24 两种格式
    png-8 的特性很接近 gif ,支持 256 色以及透明背景的特性
    PNG-24 则支持了多达 160 万个色彩
    gif:非常适合用来表现图标、 UI接口、线条插画、文字等部分的输出,也可用来展示小的动画。

    输出结果

    var a = 1,b =2;
    console.log(a+++b)

    
    var result = (function(){
        return 1;
    },function(){
        return "2"
    })()
    console.log(typeof result)
    
    
    var a = 2;
    setTimeout(function(){
       a--;
    });
    a++
    console.log(a);
    题目还是比较简单,最终输出的是3.
    
    变态的来了
    
    问1:如果外面的a++循环一百万次呢,顺序如何?
    
    ②***JavaScript
    var x = 1;
    (function(){
        console.log(x);
        var x = 2;  
    })();
    

    怎样理解this
    this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
    箭头函数的this呢?
    箭头函数中的this指向的是定义时的this,而不是执行时的this。
    对this的理解
    原题是让选择正确的调用方法,也比较简单,正确选项长这样

    var opt = {
    name:“Amy”,
    say:function(){return this.name}
    }
    扩展开始

    问1:怎么理解函数中的this
    指向调用函数的对象

    问2:箭头函数的this呢
    额。不改变this指向,函数外部指向哪里就是哪里

    问3:setTimeout函数里面的呢
    指向全局

    问4:我把上面的增加一个name2:this.name输出什么?
    undefined…(更确切地说,根据执行环境不同,输出结果也不同。这里的this指向全局,浏览器中的window.name其实是存在的,一般来说是空字符串)

    我把say方法改成这样会如何
    say:function(){
    setTimeout(function(){return this.name})
    }
    问5:改成这样呢
    say:function(){
    setTimeout(()=>{return this.name})
    }

    上下文
    函数挂载在一个对象上,作为对象的一个属性,就称它为对象的方法。当通过这个对象来调用函数时,该对象就是此次调用上下文(context),也就是该函数的this的值

    实现一个clearfix(清除浮动)代码:

    .clearfix:after{
        content:".";
        display:block;
        height:0;
        clear:both;
        visiblity:hidden;
    }
    .clearfix{
        zoom:1;
    }
    

    content是用来干嘛的,这就看你对伪类了解的是不是够深了,:after一般加在父元素上,为期内容添加后续,content你写个小点或者让他为空都可以,相当于添加一个空的内容
    display:block;让他能为块级元素,这样可以设置宽和高,接下来把它的高度height设置为0,visiblity:hidden;内容隐藏掉,再clear:both掉,把前几个兄弟元素加注在父元素上的浮动影响清除掉
    zoom这个属性是ie专有属性,除了设置或者检索对象的缩放比例之外,它还有可以触发ie的haslayout属性,清除浮动,清除margin重叠等作用。

    JS中取二维数组中最大值的方法

    function largestOfFour (arr) { // 通过map()方法,并通过回调函数,将子数组中最大值组合在一起,得到一新数组 return 		arr.map(function (group) { // 通过reduce方法,把每个子数组中最大值返回到group数组中 
    return group.reduce(function (prev, current) { // 如果current 大于prev,返回current,否则返回prev
     return (current > prev) ? current : prev; }); }); } 
     largestOfFour([[1,34],[456,2,3,44,234],[4567,1,4,5,6],[34,78,23,1]]); // [34, 456, 4567, 78] 
    

    多维数组中取最大值

    function largestOfFour (arr) {
     var newArray = arr.join(",").split(",");
      return Math.max.apply({},newArray); 
      } 
    

    取最小值同理

    参考https://www.jb51.net/article/82550.htm

    arr.reduce方法
    计算数组总和

    var num = [1,2,3,4,5];
    var res = num.reduce(function(total,num){
        return total+num;
        //return total + Math.round(num);//对数组元素四舍五入并计算总和
    },0);
    console.log(res);//15
    //num.reduce((total,num) => total += num, 0);
    //没有初始值initialValue(即上面例子中的0),当数组为0时会抛出异常提示reduce函数没有初始值,所以为兼容性一般加上initialValue
    

    合并二维数组

    var red = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
     return a.concat(b);
    }, []);
    console.log(red)
    

    (6) [0, 1, 2, 3, 4, 5]

    统计一个数组中有多少个不重复的单词:

    不用reduce时:

    var arr = ["apple","orange","apple","orange","pear","orange"];
    function getWordCnt(){
      var obj = {};
      for(var i= 0, l = arr.length; i< l; i++){
        var item = arr[i];
        obj[item] = (obj[item] +1 ) || 1;
      }
      return obj;
    }
    console.log(getWordCnt());
    VM3704:14 {apple: 2, orange: 3, pear: 1}
    
    用reduce时:
    var arr = ["apple","orange","apple","orange","pear","orange"];
    function getWordCnt(){
      return arr.reduce(function(prev,next){
        prev[next] = (prev[next] + 1) || 1;
        return prev;
      },{});
    }
    console.log(getWordCnt());
    VM3704:14 {apple: 2, orange: 3, pear: 1}
    

    写出下面程序的运行结果:

    var t = true;
    window.setTimeout(function(){
        t = false;
    },1000);
    while(t){
    
    }
    alert("end");
    

    浏览器卡死,因为浏览器执行到setTimeout()定时器时,先不执行,先把它放到异步队列中,接着执行while循环同步任务,这时是一个死循环,所以,浏览器卡死。

    console.log(typeof NaN); // number

    console.log( ‘hello’ + (1<2) ? ‘world’ : ‘me’); // world

    if(10 > 9 > 8 == true){
        console.log("html5");
    }else{
        console.log("css3");  // 打印这个
    }
    
    var length = 10;
    function fn(){
        console.log(this.length);
    }
    var obj = {
        length : 5,
        method : function(fn){
            fn();
            arguments[0]();
        }
    };
    obj.method(fn , 1);
    
    
    var output = (function(x){
        delete x;
        return x;
    })(0);
    console.log(output);  // 0
    

    列举3种强制类型转换和2种隐式类型转换?
    强制类型转换:Number() , String() , Boolean(); 隐式类型转换:布尔值参与的+运算,会先将布尔值转成对应的数字,然后再进行+运算;数字和字符串使用+运算,会将数字转成字符串,然后再进行字符串的连接。

    Label的作用是什么?是怎么用的?
    label标签是用来定义表单控制间的关系,当用户选择该标签时,浏览器会自动将焦点转到和标签相关的表单控件上。

    webSocket如何兼容低浏览器?

    如何居中div?如何居中一个浮动元素?如何让绝对定位的div居中?

    行级元素水平居中对齐(父元素设置 text-align:center)

    块级元素水平居中对齐(margin: 0 auto)

    浮动元素水平居中
    宽度不固定的浮动元素

    我是浮动的
    .outerbox{ float:left; position:relative; left:50%; } .innerbox{ float:left; position:relative; right:50%; }

    宽度固定的

    .outerbox{
         background-color:pink; /*方便看效果 */  
         width:500px ; 
         height:300px; /*高度可以不设*/
         margin: -150px 0 0 -250px; /*使用marin向左移动250px,保证元素居中*/
         position:relative;   /*相对定位*/
         left:50%;
         top:50%;
     }
    

    让绝对定位的元素水平居中对齐

    
    .center{
             position: absolute; /*绝对定位*/
             width: 500px;
             height:300px;
             background: red;
             margin: 0 auto; /*水平居中*/
             left: 0; /*此处不能省略,且为0*/
             right: 0; /*此处不能省略,且为0*/
    }
    

    图片预加载
    提前加载图片,例如漫画网站,会提前加载下一页的漫画,给用户体验比较好

    switch语句

      var day = new Date().getDay()
        console.log(day)
        function myConstructor(day) {
            var x = ''
            switch (day)  {
                case 0:
                    x="Today it's Sunday";
                    break;
                case 1:
                    x="Today it's Monday";
                    break;
                case 2:
                    x="Today it's Tuesday";
                    break;
                case 3:
                    x="Today it's Wednesday";
                    break;
                case 4:
                    x="Today it's Thursday";
                    break;
                case 5:
                    x="Today it's Friday";
                    break;
                case 6:
                    x="Today it's Saturday";
                    break;
            }
            return x
        }
    
        console.log(myConstructor(day))
    

    break和continue的区别?
    break结束整个循环体,continue终止本次循环

    图片预加载

    
    
    
        
        Title
        
    
    
    

    0%

    文字环绕图片居左

     
    
    
    
    pic 这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文

    JS中callee和caller的作用?
    callee是一个指针,指向拥有该arguments的函数
    arguments.callee代表这个函数

    // 阶乘函数
        function factorial(num) {
            if (num <= 1) {
                return 1
            }
            // return  num * factorial(num - 1)  这样写 如果函数名字改变了就会失效\
            return num * arguments.callee(num - 1)
        }
    
        console.log(factorial(3)) // 6
    

    caller保存着调用当前函数的函数的引用

    function outer() {
        inner()
    }
    
    function inner() {
        console.log(arguments.callee.caller)
    }
    
    outer() //  ƒ outer() {
    //              inner()
    //           }
    

    ajax请求时,如何解释json数据
    parse方法

    以下打印结果?

    console.log(undefined + 10) // NaN
    
    var a = 10;
    sayHi();
    function sayHi() {
        a = a + 10;
        console.log(a);
        return a;
    }
    console.info(a);
    console.info(sayHi() + 10);
    

    打印结果为 20 20 30 40

    var a = 10;
    sayHi();
    function sayHi() {
        var a = a + 10;
        console.info(a);
        return a;
    }
    console.info(a);
    console.info(sayHi() + 10);
    

    打印结果为 NaN 10 NaN NaN

    function init() {
        var ps = document.getElementsByTagName("p");  //body内有四个p标签
        for (var i=0; i

    当 console.info(i); 执行的时候,会根据作用域链去查找 i,当前函数作用域中没有i,这样会找到 for 中定义的全局 i,for 循环的执行已经结束,这个时候不管点击那个 p 标签其实打印的都是全局 i 变量,所以结果都是统一的 4;

    var add = function(m) {
        var temp = function(n) {
            return add(m + n);
        }
        temp.toString = function() {
            return m.toString(2)
        }
        return temp;
    }
    console.info(add(3)(4)(5)); //  二进制1100
    

    add(3)返回值是temp 形成闭包 此时add(3)(4) 其实是 temp(4), 执行完返回add(7)
    同样返回temp temp(5)调用的是 add(12)
    最后console.log temp 当 console.info 的时候,会默认调用 toString 方法进行字符串格式化
    而temp的toString方法被 改写了 返回二级制 所以结果是12的二进制

    304缓存原理
    客户端请求一个页面(A)。 服务器返回页面A,并在给A加上一个ETag。 客户端展现该页面,并将页面连同ETag一起缓存。 客户再次请求页面A,并将上次请求时服务器返回的ETag一起传递给服务器。 服务器检查该ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304(未修改——Not Modified)和一个空的响应体。

    在各个浏览器中的颜色

    background: red;  
    _background: green;   
    *background: blue;
    background: black\9;  
    

    IE9 支持 \9\0
    IE8 支持 \0,同样中间不要有空格。

    IE6,IE7 都支持 * ,

    IE6特别支持 下划线_: _background-color:green;

    IE7特别支持加号+: +background-color:green;

    实现表单ajax提交并刷新页面?

    
        用户名:
        密码:
        
        
    
    
                        
                        

    你可能感兴趣的:(整理)