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中,向非同源下的服务器发出请求,获得请求结果,将结果返回给前端。
<?php
$name=$_GET['name'];
$info = $_GET['info'];
$crossUrl = 'http://b.com/sub?name='.$name; //向其他域下发出请求
$res = file_get_contents($crossUrl);
echo $res;
?>
简述一下过程
发起一个ajax,向同源的某个代理程序发出请求,这个代理程序向非同源的服务器发送请求,获得请求结果,将结果返回给前端。
h5的postMessage
// http://test.com/index.html
<div style="width:200px; float:left; margin-right:200px;border:solid 1px #333;">
<div id="color">Frame Color</div>
</div>
<div>
<iframe id="child" src="http://lsLib.com/lsLib.html"></iframe>
</div>
// 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));
闭包是什么?
当一个内部函数被外部函数以外的变量引用的时候,就形成了闭包
例如:
<script>
function outer(){
var num=0;//内部变量
return function add(){//通过return返回add函数,就可以在outer函数外访问了。
num++;//内部函数有引用,作为add函数的一部分了
console.log(num);
};
}
var func1=outer();//
func1();//实际上是调用add函数, 输出1
func1();//输出2
var func2=outer();
func2();// 输出1
func2();// 输出2
</script>
闭包的特性?
封闭性: 外部无法访问闭包内部的数据
持久性:一般来说,函数调用完毕,会被注销,而闭包的外部函数被调用后,闭包结构依然存在
什么场景需要闭包?
如果想封装一个私有变量或者私有方法可以使用闭包
闭包的作用?
保存私有变量,对外提供接口,但外部不能直接访问这个变量
闭包的缺点?
消耗内存,因为不会被垃圾回收机制回收,使用不当,会造成内存泄漏
什么是垃圾回收机制?
1.当某个变量不再被引用就会被垃圾回收
2.当两个变量相互引用,但不被第三个变量引用, 也会被回收
垃圾回收机制的方式?
1.标记清除:变量进入环境,给它一个进入标记,离开环境,给它一个清除标记。垃圾回收器会过滤,保留进入环境的变量,剩余被清除
2.计数清除:变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象。
开发过程中遇到的内存泄露情况,如何解决的?
内存泄漏:内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。C#和Java等语言采用了自动垃圾回收方法管理内存,几乎不会发生内存泄露。
什么情况会发生?
1.当页面中元素被移除或替换时,若元素绑定的事件仍没被移除
<div id="myDiv">
<input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
document.getElementById("myDiv").innerHTML = "Processing...";
}
</script>
解决办法
<div id="myDiv">
<input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
btn.onclick = null;
document.getElementById("myDiv").innerHTML = "Processing...";
}
</script>
或者使用事件委托
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不支持捕获
以下面的例子为例
<!DOCTYPE html>
<html>
<head>
<title>example</title>
</head>
<body>
<div>click</div>
</body>
<html>
事件冒泡的过程为 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
是的话就执行自定义事件
代码如下:
<h1>
请使用IE8或更低版本的浏览器测试
</h1>
<button id="btn" eventAttr="0">点击修改按钮的eventAttr属性值</button>
<script>
var btn = document.getElementById('btn')
btn.attachEvent('onpropertychange', function (e) {
if (e.propertyName === 'eventAttr') {
alert('触发了')
}
}
btn.attachEvent('onclick', function () {
btn.setAttribute('eventAttr', 1)
}
</script>
什么是事件委托?
事件委托指的是,不在事件的发生地设立监听函数,而是在事件发生地的父元素或者祖先元素设置监听器函数,这样可以大大提高性能,因为可以减少绑定事件的元素
实现一个通用事件绑定的函数
支持传三个或者四个参数
传三个参数的时候为普通的绑定事件
传四个参数为事件代理
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预解析):
<meta http-equiv="x-dns-prefetch-control" content="on" />
<link rel="dns-prefetch" href="http://bdimg.share.baidu.com" />
<link rel="dns-prefetch" href="http://nsclick.baidu.com" />
<link rel="dns-prefetch" href="http://hm.baidu.com" />
<link rel="dns-prefetch" href="http://eiv.baidu.com" />
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的区别?
- http1.0是非持久连接,每次请求都会为客户端与服务端创建一个连接,完成后就中断连接,而1.1支持持久连接,一次连接可以传多个请求和响应。
- 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,多个资源之间用逗号分隔
<img src="small.jpg " srcset="big.jpg 1440w, middle.jpg 800w, small.jpg 1x" />
- 使用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元素
//这些代码应被放置在</body>标签前(接近HTML文件底部)
<script type="text/javascript">
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load",downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload",downloadJSAtOnload);
else
window.onload =downloadJSAtOnload;
</script>
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.可以实现在新增子元素的时候,无需再对其进行事件绑定,对于动态部分来说很实用
缺点:
如果都使用事件代理,有可能会出现事件误判,也就是不该触发事件的元素被绑定了事件
实现一个兼容浏览器的事件代理
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
function delegateEvent(elem, selector, type, fn) {
if (elem.addEventListener) { // 绑定事件
elem.addEventListener(type, _handleFunc)
} else {
elem.attachEvent('on' + type, _handleFunc)
}
function _handleFunc(e) { // 处理事件
var e = e || window.event
var target = e.target || e.srcElement
if (matchSelector(target, selector)) { // 判断点击的是不是我们需要代理的元素
if (fn) {
fn.call(target, e)
}
}
}
}
function matchSelector(ele, selector) { // ele是触发事件的元素 也就是 target selector是传入的需要代理的元素
// console.log(ele,selector) // 打印<li>x<li> 'li'
// if use id
if (selector.charAt(0) === "#") {
return ele.id === selector.slice(1)
}
// use class
if (selector.charAt(0) === ".") {
return (" " + ele.className + " ").indexOf(" " + selector.slice(1) + " ") !== -1
}
// use tagName
return ele.tagName.toLowerCase() === selector.toLowerCase()
}
var ul = document.getElementById('ul')
delegateEvent(ul, 'li', 'click', function (e) {
alert(e.target.innerHTML)
})
</script>
实现事件模型
即写一个类或是一个模块,有两个函数,一个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部分
<div class="wrapper">
<div class="children">子元素</div>
</div>
1.absolute + margin:auto
适用于子元素宽高不固定
<style>
.wrapper {
position: relative;
width: 200px;
height: 200px;
border: 1px solid blue;
}
.children {
width: 100px;
height: 100px;
position: absolute;
bottom: 0;
right: 0;
left: 0;
top: 0;
margin: auto;
background: beige
}
</style>
2.absolute + 负的margin
适用于子元素宽高固定
<style>
.wrapper {
position: relative;
width: 200px;
height: 200px;
border: 1px solid blue;
}
.children {
width: 100px;
height: 100px;
position: absolute;
top:50%;
left:50%;
margin-top: -50px;
margin-left:-50px;
background: beige
}
</style>
3.absolute + transform
transform是css3属性 ie9之前版本兼容不好
<style>
.wrapper {
position: relative;
width: 200px;
height: 200px;
border: 1px solid blue;
}
.children {
width: 100px;
height: 100px;
position: absolute;
top:50%;
left:50%;
transform: translate(-50%, -50%);
background: beige
}
</style>
4.flex
ie不兼容 移动端推荐使用
<style>
.wrapper {
display: flex;
justify-content: center;
align-items: center;
width: 200px;
height: 200px;
border: 1px solid blue;
}
.children {
width: 100px;
height: 100px;
background: beige
}
</style>
5.table-cell
<style>
.wrapper {
display: table-cell;
text-align: center;
vertical-align: middle;
width: 200px;
height: 200px;
border: 1px solid blue;
}
.children {
display: inline-block;
width: 100px;
height: 100px;
background: beige
}
</style>
字体垂直居中
单行文本垂直居中
line-height = height
多行文本垂直居中
父元素高度不固定:高度只能由文本撑开,只需要设置padding-top的值等于padding-bottom即可
<style>
#div1 {
width: 300px;
margin: 50px auto;
border: 1px solid red;
text-align: center;
padding: 50px;
}
</style>
<div id="div1">
这是多行文本垂直居中,
这是多行文本垂直居中,
这是多行文本垂直居中,
这是多行文本垂直居中。
</div>
父元素高度固定
设置父级div为display:table 子元素为table-cell 然后给子元素设置vertical-align:middle
<div id="outer">
<div id="middle">
这是固定高度多行文本垂直居中,
这是固定高度多行文本垂直居中,
这是固定高度多行文本垂直居中,
这是固定高度多行文本垂直居中。
</div>
</div>
<style>
#outer {
width: 300px;
height: 150px;
margin: 50px auto;
border: 1px solid red;
display: table;
}
#middle {
width: 100%;
display: table-cell;
vertical-align: middle;
text-align: center;
}
</style>
40.自适应布局
三栏布局
左右宽度固定 中间自适应
<!-- 1.float -->
<div style="min-height: 300px;width: 100%">
<div style="float: left;width: 300px;background-color: red">左</div>
<div style="float: right;width: 300px;background-color: blue">右</div>
<div style="background-color: yellow">中</div>
</div>
<br />
<!-- 2.absolute-->
<div style="min-height: 300px;width: 100%;position: relative;">
<div style="position:absolute; left:0;width: 300px;background-color: red">左</div>
<div style="position:absolute;left:300px;right:300px;background-color: yellow">中</div>
<div style="position: absolute;right: 0;width: 300px;background-color: blue">右</div>
</div>
<br />
<!-- 3.flex -->
<section style="display: flex;flex-direction: row;justify-content: space-between;width: 100%">
<div style="width: 300px;background-color: red;">左</div>
<div style="background-color: yellow;flex: 1;">中</div>
<div style="background-color: blue;width: 300px;">右</div>
</section>
<br/>
<!--4.grid-->
<div style="display: grid;grid-template-columns:300px auto 300px">
<div style="background-color: red;">左</div>
<div style="background-color: yellow;">中</div>
<div style="background-color: blue;">右</div>
</div>
这几种方法的优缺点:
1.float 兼容比较好 缺点是需要清除浮动
2.position 比较快捷 缺点是脱离文档流 实际使用不是特别好相对于其他的方法
3.flex 比较完美的方法 除了低版本浏览器不兼容
4.grid 网格布局 代码量比较简单
上下高度固定 中间自适应同上
<!--上下固定高 中间自适应-->
<section style="position:relative;min-height: 400px;">
<div style="position:absolute;top: 0;height: 100px;background-color: red;width: 100%">上</div>
<div style="background-color: yellow;position:absolute;top: 100px;bottom: 100px;width: 100%;">中</div>
<div style="position:absolute;bottom: 0;height: 100px;background-color: blue;width: 100%">下</div>
</section>
<br>
<br>
<br>
<br>
<!--2.flex-->
<section style="display: flex;flex-direction:column;align-content: space-between ">
<div style="background-color: red;width: 100%;height: 100px;">上</div>
<div style="background-color: yellow;width: 100%;flex: 1">中</div>
<div style="background-color: blue;width: 100%;height: 100px;">下</div>
</section>
<br>
<br>
<br>
<!--3.grid-->
<section style="display: grid;grid-template-rows: 100px auto 100px">
<div style="background-color: red;width: 100%;">上</div>
<div style="background-color: yellow;width: 100%;">中</div>
<div style="background-color: blue;width: 100%;">下</div>
</section>
两栏布局
方法也可以借用上面的
<!--左定宽右自适应-->
<section style="width: 100%">
<div style="background-color: green;float: left;width: 300px">左</div>
<div style="background-color: pink">右</div>
</section>
<br>
<section style="width: 100%;position: relative;">
<div style="background-color: green;position:absolute;left: 0;width: 300px">左</div>
<div style="background-color: pink;position: absolute;left: 300px;width: 300px">右</div>
</section>
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
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,
minimum-scale=1.0">
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;
}
}
- 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加载的内容
<iframe id="fram"></iframe>
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标签里
<link rel="stylesheet" href="xxx.css" type="text/css">
- @import方法
<style>
@import url(xxxcss)
</style>
3.内联样式
直接在相应的元素标签上style=“xxxxx…”
49.display
块级元素 block
<div>、<p> <ul> <ol> <form> <h1~h6>……
行内元素 inline
<span> <a> <img> <input> <select> <label> ……
行内块级元素 inline-block
隐藏 none
50.为什么要初始化css
因为不同的浏览器的标签默认的一些间距不同,如果不初始化,会导致同样的样式在不同浏览器下有较大区别
但是初始化会对页面的seo有点影响
51.实现品 字布局
<style>
body{
height: 1200px;
}
.main {
position: fixed;
left: 0;
top: 0;
height: 100%;
width: 100%;
}
.wrapper-up {
height: 50%;
}
.wrapper-down {
height: 50%;
position: relative;
}
.div-square-up {
width: 50%;
margin: 0 auto;
border: 2px solid red;
height: 96%;
box-sizing: border-box;
}
.div-square-left {
position: absolute;
left: 0;
width: 48%;
height: 100%;
box-sizing: border-box;
border: 2px solid red;
}
.div-square-right {
position: absolute;
right: 0;
width: 48%;
height: 100%;
border: 2px solid red;
box-sizing: border-box;
}
</style>
</head>
<body>
<div class="main">
<div class="wrapper-up">
<div class="div-square-up"></div>
</div>
<div class="wrapper-down">
<div class="div-square-left"></div>
<div class="div-square-right"></div>
</div>
</div>
52.css实现三角形
原理就是让一些不需要显示的边框为透明色
53.清除浮动的方法及优缺点
为什么要清除浮动?
浮动让元素脱离文档流,造成父元素高度塌陷
1.早期清除浮动是在浮动的元素后面添加一个标签负责clear:both
<div style="clear:both;"></div>
优点:简单易懂
缺点:会增加一些无意义的空标签 不建议使用
2.对浮动元素的父元素设置overflow:hidden
<div class="warp" id="float3" style="overflow:hidden; *zoom:1;">
<h2>3)父元素设置 overflow </h2>
<div class="main left">.main{float:left;}</div>
<div class="side left">.side{float:right;}</div>
</div>
<div class="footer">.footer</div>
优点:代码简单
缺点: 如果内容增多,容易造成不会自动换行,导致内容隐藏。 不推荐
3.使用伪元素:after
.clearfix:after {
content: "";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
/* 为兼容IE6,IE7,因为ie6,ie7不能用after伪类 */
.clearfix{
zoom:1;
}
优点:代码量适中
缺点: 复用方式不当,会造成代码量增加
54.js的数据类型
值类型: Number、String、Boolean、undefined、null
引用类型:Object、Array、Function
typeof能得到哪些类型?
console.log(typeof undefined) // undefined
console.log(typeof 'str') // string
console.log(typeof 1) // number
console.log(typeof true) // boolean
console.log(typeof []) // object
console.log(typeof {}) // object
console.log(typeof null) // object
console.log(typeof function () { // function
})
可以区分undefined number string boolean 这几种值类型
区分不了引用类型 一律返回object 除了function之外
类型转换?
字符串转数字
var a = '1'
// 减乘除取余 除了加
console.log(typeof (a -1)) // number
console.log(typeof Number(a)) // 强制转换
console.log(typeof parseInt(a))
数字转字符串
var a = 1
console.log(typeof a.toString())
console.log(typeof (a + 'ha')) // 强制转换
console.log(typeof String(a))
如果想区分引用类型怎么办呢?
可以使用Object.prototype.toString.call()
console.log(Object.prototype.toString.call([])) // [object Array]
console.log(Object.prototype.toString.call({})) // [object Object]
console.log(Object.prototype.toString.call(null)) // [object Null]
console.log(Object.prototype.toString.call(function () {})) // [object Function]
什么时候用== 什么时候用===?
if (obj.a == null) {}
相当于 obj.a === null || obj.a === undefined
除此之外都最好用===
null和undefined的区别?
1.数据类型不同 null是null类型 undefined数据类型是undefined
2. null代表是一个空对象,typeof返回的是object,而undefined是声明了一个变量,但是没有给它赋值,那么就是undefined,typeof返回的是undefined
所以当我们定义一个变量,之后会为它赋一个对象,那么我们可以先将这个变量赋null
判断是否为null
var c = null
console.log(c === null)
判断是否为undefined console.log(typeof b === 'undefined')
记得要加引号
NaN?
NaN表示不是一个数字 但是它是Number类型
例如
var a = 's'
console.log(parseInt(a)) // NaN
判断是否为NaN
通过isNaN
console.log(isNaN(parseInt(a))) // true
除了NaN,number类型的特殊值还有infinity
例如 1 / 0的值就是infifnity
55.js的内置函数
Object Array String Number Boolean Date RegExp Error
56.js按存储方式区分变量类型
值类型
值类型的复制是对本身的复制,值修改不会相互影响
值类型的检测使用typeof
var a = 10
b = a
console.log(b++) // 10 b++可以看做在本行执行完之前b的值都不会+1
console.log(a, b) // 10 11
引用类型
引用类型的复制是对指针的复制,值之间修改会相互影响
引用类型检测使用instanceof
var obj1 = {a: 10}
obj2 = obj1
obj2.a = 11
console.log(obj1.a) // 11
57.JSON是什么
json是js中一个对象,有JSON.stringify和JSON.parse两种方法
同时 json也是一种数据格式
JSON.stringify是将js对象转化为json字符串
注意转化后是 string类型
// 一个参数
console.log(JSON.stringify({a:10, b:20})) // {"a":10,"b":20}
// 多个参数 4代表空格
console.log(JSON.stringify({a: 10, b:20}, null, 4))
/* {
"a": 10,
"b": 20
}*/
JSON.parse是将json字符串转化为js对象
console.log(JSON.parse('{"a":10,"b":10}')) // 注意json格式一定要双引号 {a: 10, b: 10}
58.原型链
原型链
原型五条规则 :
所有引用类型 ,除了null之外,都具有对象的特性,即可以自由扩展 属性
所有引用类型,都有一个__proto__属性,也称为隐式原型
所有函数,都有一个prototype属性,成为显示原型
所有引用类型的__proto__属性都是指向它的构造函数的prototype属性
第五条:也是原型链的定义
当我们试图获得一个对象的属性,首先会在对象本身属性上查找,如果没有找到,就会向对象的__proto__,
也就是它的构造函数的prototype中寻找,如果还没找到,会继续想构造函数的prototype的__proto__查找,这种层层查找会形成有一个链式结构,也就是原型链
举个例子
function Foo(name) {
this.name = name
}
Foo.prototype.alertName = function () {
alert(this.name)
}
var person = new Foo('tom')
person.hello = 'hello'
person.printfname = function () {
console.log(this.name)
}
person.alertName()
person.printfname()
// 循环自身的属性
for (var item in person) {
if (person.hasOwnProperty(item)) { // 判断是否是实例自身拥有的属性
console.log(item) // 打印name hello printfname
}
}
// instanceof 判断引用类型属于哪个构造函数
console.log(person instanceof Foo) // true
console.log(person instanceof Object) // true
写一个原型链继承的例子?
function Parent(name) {
this.name = name
}
Parent.prototype.say = function (str) {
console.log('parents say ' + str)
}
function Son(age) {
this.age = age
}
var parent = new Parent('tom')
Son.prototype = parent
var son = new Son(16)
console.log(son.name)
console.log(son.age)
son.say('hello')
for (var k in son) {
if (son.hasOwnProperty(k)) {
console.log(k) // 只有age
}
}
描述new一个对象的过程?
创建一个新对象
this指向这个新对象
执行代码
返回this
原生代码实现jquery 的html和on方法?
// 原生代码实现jquery的html和 on方法
function Elem(id) {
this.elem = document.getElementById(id)
.
}
Elem.prototype.html = function (val) {
var elem = this.elem
if (val) {
elem.innerHTML = val
return this
} else {
return elem.innerHTML
}
}
Elem.prototype.on = function (type, handle) {
var elem = this.elem
elem.addEventListener(type, handle)
return this
}
var test = new Elem('test')
console.log(test.html()) // 初始内容
test.html('<a>点我</a>').on('click', function (e) {
alert(e.target.innerHTML)
}).html('<input type="text" placeholder="试试看"/>')
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 + '<br/>'
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 + '<br/>'
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"
}
//
<div class="ajax">
<div>
<button id="btn">点我</button>
</div>
<div id="content"></div>
</div>
</body>
<script>
var btn = document.getElementById('btn')
var content = document.getElementById('content')
btn.addEventListener('click', function () {
btn.disabled = true
var test
if(window.XMLHttpRequest){
test = new XMLHttpRequest();
}else if(window.ActiveXObject){
test = new window.ActiveXObject();
}else{
alert("请升级至最新版本的浏览器");
}
if (test) {
test.open('GET', 'test.json', true)
test.onreadystatechange = function () {
if (test.readyState === 4 && test.status === 200) {
var obj = JSON.parse(test.responseText)
for (var k in obj) {
content.innerHTML = obj[k]
}
}
}
test.send()
}
})
66. 前端模块化 包括AMD、 CommonJS
AMD :
使用require.js,全局定义define和require函数,依赖的的js会自动、异步加载
注意一个define里可以有多个其他js文件依赖,例如
require( ["some/module", "my/module", "a.js", "b.js"],
function(someModule, myModule) {
//This function will be called when all the dependencies
//listed above are loaded. Note that this function could
//be called before the page is loaded.
//This callback is optional.
}
);
main.js是入口文件,第一个参数是依赖
注意:需要去官网安装require.js文件
http://www.requirejs.cn/docs/start.html
使用:
main.js作为入口文件
CommonJs
是nodejs模块化规范,不是异步加载js,而是 同步一次性加载
…
AMD和CommonJS使用场景的区分?
如果需要异步加载 js,使用AMD
如果同时还是用了 npm ,建议使用commonJS
AMD CMD CommonJS es6的区别?
AMD: 是requirejs在推广中对模块化的产物,特性:依赖前置,异步加载,使用define函数,第一个参数是所需依赖的数组,第二个参数是回调函数
CMD:是sea.js在推广中对模块化的产物,特性:依赖就近,哪里需要使用就在哪里require进来,是一个同步模块
//所有模块通过defined来定义
define(function(require,export,module){
//通过require引入依赖
var $=require('jqurey');
var spinning=require('./spinning');
})
CommonJS: 通过module.exports实现,是nodejs模块化规范,不是异步加载js,而是 同步一次性加载
ES6: 通过 export / import 对模块进行导出和引入
CommonJs 模块输出的是一个值的拷贝,ES6模块输出的是一个值的引用
CommonJS 模块是运行时加载,ES6模块是编译时输出接口
webpack安装与配置?
npm init
npm install webpack --save-dev dev代表只在开发环境中使用 上线不需要
配置是在webpack.config.js里
var path = require('path')
var webpack = require('webpack')
module.exports = {
context: path.resolve(__dirname, './src'), // ./src为自己创建一个目录
entry: { // 入口文件
app:'./app.js' // src目录下的app.js
},
output: {
path: path.resolve(__dirname, './dist'), //输出到dist文件夹
filename: 'bundle.js' // 打包完是bundle.js webpack打包完自动创建
},
plugins: [ // 压缩js
new webpack.optimize.UglifyJsPlugin()
]
}
上线和回滚?
上线
将测试完成的代码提交到git仓库的master分支
将当前的服务器的代码进行打包、备份
将master分支的代码提交覆盖到线上服务器,生成新的版本号
回滚
将当前服务器的代码打包,备份,记录版本号
将上一个版本代码解压,覆盖到线上服务器,生成新版本号
linux基本命令?
登录 (有可能是公共的,也有可能是自己的账号)
ssh nameserver nameserver是账号名字
mkdir a 创建一个a文件夹
ls 查看文件夹名字
ll 横排列表显示文件名字
cd a 进入文件夹a
a pwd 查看当前文件路径
cd … 返回上一级
rm -rf a 删除a文件夹
cat xx.js 查看xx.js内容
head xx.js 查看xx.js头部的一些内容
tail xx.js 查看尾部
head -n 1 xx.js 查看第一行
tail -n 2 xx.js 查看倒数两行
grep ‘hello’ xx.js 在xx文件里搜索带hello的一行
vi xx.js 编写xx.js
67.运行环境
从输入一个url到页面加载的过程?
1.浏览器根据DNS解析得到域名的ip地址
2.浏览器与服务器建立tcp连接
3.浏览器向服务器发送http请求
4.服务器接受、处理并返回http报文
5.浏览器得到返回的内容 渲染页面
浏览器渲染的过程?
见9
window.onload 和 DOMContentLoaded的区别?
window.addEventListener('load', function () {
// 页面全部资源加载完毕才会执行,包括图片、视频等等
})
window.addEventListener('DOMContentLoaded', function () {
// dom渲染完成就可以执行, 不用等图片、视频 等 加载完
})
有点类似于 $.ready和 区别
66.BFC
什么是BFC?
块级格式化上下文
BFC的渲染规则?
1.内部的盒子会沿着垂直方向一个接一个排列
2.BFC不会与浮动元素的盒子重叠
3.BFC计算高度的时候浮动的子元素也会参与计算
4.BFC在页面上是一个独立的容器,外面不会影响里面,里面也不会影响外面
如何创建BFC?
1.overflow不为visible
2.float不为none
3.position不为static和relative
4.display不为table-cell table-caption 和inline-block
BFC的使用场景?
解决边距重叠的问题
<section id="margin">
<style>
#margin{
background: pink;
overflow: hidden;
}
#margin>p{
margin: 5px auto 25px;
background: red;
}
</style>
<p>1</p>
<!--解决边距重叠 用div包裹并设置overflow 创建了一个BFC-->
<!--p1的下边距25px和p2的上边距5px重叠 只显示25px 边距重叠的时候取最大值为准-->
<div style="overflow:hidden">
<p>2</p>
</div>
<!-- <p>2</p>-->
<p>3</p>
</section>
66.什么是doctype? 作用是什么
doctype是用来声明文档类型和DTD语法规则
主要用来验证文件的合法性
常见的就是H5的 <!DOCTYPE HTML>
67.单线程
什么是单线程?
就是同时只能做一件事,两段js不能同时执行
原因是为了避免dom渲染冲突
解决办法是异步
js的异步加载?
常见的有两种
1.给script标签添加async属性
<script type="text/javascript" src="demo_async.js" async="async"></script>
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
Promise的all和race方法
async和await
asycn和await es7提案中
使用await必须有async标识
await后面必须跟上promise实例
需要安装babel-polyfill
并不是取代了promise 而且还使用了promise,完全同步的写法。没有回调函数。
任何写法的改变 都改变不了js的单线程、异步的本质
虚拟DOM
vdom是什么?为什么存在?
虚拟dom ,用js模拟dom结构, dom变化的对比放在js层来做,提高重绘性能
dom操作影响性能,减少dom操作
基本的dom
js模拟的dom
核心api是什么?
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
<body>
<div id="app">
<p>{{name}}</p>
<p>{{age}}</p>
</div>
</body>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
// 直接在控制台 vm.age = 100 页面也会修改
// 为什么不是vm.data.age来修改 这些data属性直接被代理到了vm上了?
var vm = new Vue({
el: '#app',
data: {
name: 'zhangsan',
age: 99
}
})
// es5就有这个方法 可以监听读写
var obj = {}
name = 'zhangsan'
Object.defineProperty(obj , 'name', {
get: function () {
console.log('get')
return name
},
set: function (newVal) {
console.log('set')
name = newVal
}
})
console.log(obj.name)
obj.name = 'haha'
console.log(obj.name)
// 以上打印顺序为 get zhangsan set get haha
// 模拟实现vue的响应式
var mv = {}
var data = {
price: 100,
name: 'zhangsan'
}
var key, value
for (key in data) {
(function (key) {
Object.defineProperty(mv, key, {
get: function () {
return data[key]
},
set: function (newVal) {
data[key] = newVal
}
})
})(key)
}
模板引擎: vue模板如何被解析,指令怎么处理?
模板是什么?
本质是字符串,有逻辑 例如v-if v-for等等,最后要转化为HTML,必须要用js实现,因此模板要转化成js函数 (render函数 是一类函数 不是唯一叫render的)
with函数 我们尽量不要用 vue内部使用了
var vm = new Vue({
el: '#app',
data: {
price: 100
}
})
function render() {
with (this) { // this 就是vm
return _c(
'div',
{
attrs: {'id': 'app'}
},
[
_c('p', [_v(_s(price))])
]
)
}
}
vm._c 和vnode中的h函数类似 也是返回vnode,然后在updateComponent里使用patch,分为首次渲染,和不是第一次渲染两种情况
渲染: vue模板如何被渲染成html?
68.尾调用
什么是尾调用?
函数的最后一步是 调用另外一个函数
例如
function f(x){
return g(x);
}
以下两种均不是 尾调用
// 情况一
function f(x){
let y = g(x);
return y;
}
// 情况二
function f(x){
return g(x) + 1;
}
上面代码中,情况一是调用函数g之后,还有别的操作,所以不属于尾调用,即使语义完全一样。情况二也属于调用后还有操作,即使写在一行内。
尾调用不一定出现在函数尾部,只要是最后一步操作即可。
function f(x) {
if (x > 0) {
return m(x)
}
return n(x);
}
尾调用实现的优化?
function f() {
let m = 1;
let n = 2;
return g(m + n);
}
f();
// 等同于
function f() {
return g(3);
}
f();
// 等同于
g(3);
如果函数g不是尾调用,函数f就需要保存内部变量m和n的值、g的调用位置等信息。由于调用g之后,函数f就结束了,所以执行到最后一步,完全可以删除 f() 的调用记录,只保留 g(3) 的调用记录
尾调用优化 即指保存内层函数的调用记录,大大节省内存
尾递归
函数调用自身即为递归 生成成千上百个调用记录 非常消耗内存 容易出现栈溢出的错误
但对于尾递归来说,由于只存在一个调用记录,所以永远不会发生"栈溢出"错误。
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
factorial(5) // 120
上面代码是一个阶乘函数,计算n的阶乘,最多需要保存n个调用记录,复杂度 O(n) 。
如果改写成尾递归,只保留一个调用记录,复杂度 O(1) 。
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1) // 120
69.循环遍历
forEach数组专利遍历
for in 对象遍历
for of 对象 数组 字符串遍历
70.map set array object
set和array 类似 区别在于set的元素 不能重复 使用场景:数组去重
weakSet和set类似 只是 元素只能是对象 不能被遍历 没有clear方法 无法检测内部的元素是否已经被垃圾回收了
map和Object类似 区别在于 object的key只能是字符串 而map的 key可以是任意数据类型
weakmap的key只能是 对象
71.Class类
class声明和函数声明的最大区别在于 函数声明会提升,而class声明不会
class的继承
class类中定义的方法都会被实例继承,但是加上static关键字的方法不会被实例继承,只能通过类调用,但是可以被子类继承
class Foo {
static method () {
console.log('hello')
}
}
// 静态方法可以直接调用
Foo.method()
// 但不会被实例继承
let f = new Foo()
// f.method() // is not a function
// 可以被子类继承
class Bar extends Foo {}
Bar.method()
71.module.exports/exports 与 export/export default的区别
1.写法上区别
前两者后面要接等号 后两者直接接具体的到处 例如变量 函数 类等等
2.前两者是nodejs将每个js文件看做一个模块,为每个js文件生成一个module对象,这个对象有个exports属性,并且exports的值是一个空对象 也就是module.exports 其实就是exports
后两者是es6的语法,用于导出模块中的变量、函数、类,对应的导入关键字是import
一个是对象一个是语法 所以两者肯定不同
export和export default区别
1.一个js文件中只能有一个export default 但是可以有多个export
2.export default对应的导入不用加{},而export要加
72.各种x、y
screenX/Y 鼠标位置相对于屏幕的坐标
clientX/Y 相对于当前页面 (不考虑 滚动条)的坐标
X/Y 同clientX/Y 火狐不支持
pageX/Y 相对于文档流(包含滚动条)的坐标
offsetX/Y 相对于触发事件的元素(块级或者行内块)的坐标(除safari之外不包括border) 如果是行内元素则无效(返回父级元素的坐标)
scrollX/Y属性可以返回文档当前水平/垂直滚动的像素数 是window的属性 和前面对象e的属性不同
73.像素
PPI表示每英寸像素点 个数,PPI越高,像素点越多
viewport表示移动设备上用来显示网页的区域,一般比移动设备浏览器的可视区要大
逻辑分辨率pt和屏幕尺寸有关 简单理解为就是 长度相关
物理分辨率 px 简单理解为就是像素点 不是长度相关单位
DPR(设备像素比) = 物理分辨率 px / 逻辑分辨率pt
为什么retina屏幕(苹果手机)要使用二倍图?
因为他 的DPR为2 所以设置的initial-scale为0.5 初始缩放率为0.5 所以想要图片达到我们想要的显示效果 需要两倍的图
74.flex
flex-direction 定义元素在主轴的排列方向 row column
flex-wrap让盒子里的元素在必要的时候拆行 wrap拆行 no-wrap不拆行 wrap-reverse拆行时倒着排列
设置为wrap-reverse后
flex-flow是flex-direction和flex-wrap的组合属性
例如 flex-flow: row wrap
justify-content 在主轴上的对齐方式
space-between 伸缩项目两边碰 中间部分平均分
space-around 伸缩项目平均分 剩余部分两边碰
也有flex-start flex-end center属性值
align-items 定义元素在交叉轴上的排列模式
默认flex-start
center
align-content类似于justify-content 控制在交叉轴上的对齐方式
flex子元素属性 order控制排列位置
.flex-container {
display: flex;
flex-direction: column;
}
.flex-item:nth-child(1) {
order:3;
}
.flex-item:nth-child(2) {
order:1;
}
.flex-item:nth-child(3) {
order:-1;
}
.flex-item:nth-child(4) {
order:0;
}
order越小就越靠前
flex-grow 的意思已经很明显了,就是索取父容器的剩余空间,默认值是0
.flex-container {
display: flex;
}
.flex-item {
flex-grow: 1;
}
.flex-item:nth-child(1) {
flex-grow: 2;
}
.flex-item:nth-child(2) {
flex-grow: 1;
}
.flex-item:nth-child(3) {
flex-grow: 1;
}
flex-shrink默认为1 设置为0表示不收缩
.flex-container {
display: flex;
width: 300px;
}
.flex-item:nth-child(1) {
width: 100px;
}
.flex-item:nth-child(2) {
width: 200px;
}
.flex-item:nth-child(3) {
width: 150px;
flex-shrink: 0;
}
第三个子元素会让前俩收缩
flex-basis
子容器设置了flex-basis或者width,那么在分配空间之前,他们会先跟父容器预约这么多的空间,然后剩下的才是归入到剩余空间
总结 通过上面的分析,我们就可以得出这样几个结论:
1、剩余空间=父容器空间-子容器1.flex-basis/width - 子容器2.flex-basis/width - …
2、如果父容器空间不够,就走压缩flex-shrink,否则走扩张flex-grow;
3、如果你不希望某个容器在任何时候都不被压缩,那设置flex-shrink:0;
4、如果子容器的的flex-basis设置为0(width也可以,不过flex-basis更符合语义),那么计算剩余空间的时候将不会为子容器预留空间。
5、如果子容器的的flex-basis设置为auto(width也可以,不过flex-basis更符合语义),那么计算剩余空间的时候将会根据子容器内容的多少来预留空间。
参考https://www.cnblogs.com/ghfjj/p/6529733.html
flex属性整合了flex-grow flex-shrink flex-basis
flex: 1 其实就是设置了flex-grow: 1
align-self 子元素自己决定自己在交叉轴上的对齐方式
想达到flex布局每行只显示两个子元素
主要设置
display:flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
// flex子元素
width: 45%
75.字体图标
使用font awesome 字体图标库
网址http://fontawesome.dashgame.com/
使用方法
先下载font-awesome
然后
你可以用 标签把 Font Awesome 图标放在任意位置。
找到需要使用的图标的class名
如 <i class="fa fa-graduation-cap"></i>
就可以使用啦
76.jquery中对css的操作
css() 设置或返回匹配元素的样式属性。
width() 设置或返回匹配元素的宽度。
height() 设置或返回匹配元素的高度。
offset() 返回第一个匹配元素相对于当前视口的偏移的位置。
position() 返回第一个匹配元素相对于父元素的位置。
scrollLeft() 设置或返回匹配元素相对滚动条左侧的偏移。
scrollTop() 设置或返回匹配元素相对滚动条顶部的偏移。
.index()获得第一个匹配元素相对于其同胞元素的 index 位置。
例如$(selector).index()
77.zepto和jquery的异同
相同点:他们的api是相似的,但是zepto文件体积还要小一点
不同点:
1.zepto有触摸事件 tap和swiper jquery是没有的
2.jquery的.offset方法只返回left和top两个属性,而zepto的.offset返回left top widht height四个属性
3.jquery的.width和.height方法只计算content的宽高
zepto的.width和.height 返回的宽高是content+padding和border的
78.HTML XHTML html5的关系
HTML属于SGML (文本标记语言)
XHTML属于XML,是HTML基于XML严格化的结果
而h5不属于SGML也不属于XML 比XML要宽松
79.HTML5
html5有什么新变化?
1.新的语义化元素 header footer article等等
2.表单增加新的属性 例如autocomplete placeholder等等
3.新的api 本地存储indexdb 音频video audio 图像canvas svg 实时通信websocket 离线缓存等等
4.嵌套规则变化 例如a标签某些情况可以嵌套块级元素了 以前是不允许的
em和i的区别?
em具有强调的意思
而i仅仅是斜体
在h5中不推荐使用i 一般只有做字体图标的时候用
语义化的意义?
1.开发者容易理解
2.软件容易理解结构 (例如读屏软件)
3.有利于seo
哪些元素可以自闭合?
input br img meta link
html和dom的关系?
dom是有html解析而来
js可以操作dom
property和attribute区别?
attribute是写在html中的属性
property是js中的特性
form标签的作用?
可以直接提交表单
便于浏览器保存表单
第三方库可以进行表单验证和提取到整体的值
图片下面有空白间隙?
形成原因:img是内联元素 所以也是遵循基线对齐 离底线有间隙
解决办法: 设置vertical-align:bottom 或者把img设置为块级元素
把图片转为base64编码的好处?
减少http请求
适用于小图片
将图片转base64有相关在线转码网站
使用base64编码的图片 background: url(data:image/jpeg;base64,xxxx这里是编码)
css hack是什么?
是用来兼容ie的 难理解 难维护
表单美化?
<style>
.haha input {
display: none;
}
.haha input + label {
background: url("./checkbox1.png") left center no-repeat;
background-size: 20px 20px;
padding-left: 20px;
}
.haha input:checked + label {
background: url("./checkbox2.png") left center no-repeat;
background-size: 20px 20px;
padding-left: 20px;
}
</style>
</head>
<body>
<div class="haha">
<input type="checkbox" id="haha" />
<label for="haha">hah</label>
</div>
步骤:
首先把原生的input设置为display:none
然后替换一下背景图
css实现一个梯形?
.c3{
width:400px;
height: 200px;
border-bottom:30px solid red;
border-left:30px solid transparent;
border-right:30px solid transparent;
}
css优先级?
计算权重决定
行内样式 +1000
id选择器 +100
class、伪类、属性选择器 + 10
标签 、伪元素选择器+ 1
!important优先级最高
如果权重相同 后写的生效
雪碧图的作用?
减少http请求 提高加载性能
自定义字体?
在新的 @font-face 规则中,您必须首先定义字体的名称(比如 myFirstFont),然后指向该字体文件。
如需为 HTML 元素使用字体,请通过 font-family 属性来引用字体的名称 (hoverTreeFont).
@font-face {
font-family: "IF";
src: url("./IndieFlower.ttf");
}
.custom-font{
font-family: IF;
}
<div class="custom-font">你好 Hello World</div>
自定义字体的使用场景?
1.放在banner或者slogan这种地方
2.作为字体图标
伪元素和伪类的区别?
伪类表示的是状态 例如hover link
伪元素是真的有这个元素 例如before after
伪类用单冒号 伪元素双冒号 当然before after也简写为单冒号了
如何产生不占空间的边框?
box-shadow 不设置模糊值
box-shadow参数 水平阴影位置 垂直阴影位置 模糊值 阴影尺寸 颜色 是否将外阴影改内阴影(inset;
往右为正值 往下为正值
例如 :box-shadow: 10px 10px 5px #888888;
outline 轮廓 : 边框颜色 边框样式 边框宽度
例如 outline:#00FF00 dotted thick;
box-sizing:border-box
将一个图片裁剪成指定的形状?
用clip-path
css3实现半圆 扇形?
原理是设置border-radius的值
半圆
div {
width:100px;
height:50px;
border-radius:50px 50px 0 0;
background:red;
}
通过修改值可以完成不同方向的半圆
扇形
.circle{
border-width: 100px;
border-radius: 100px;
border-color: red transparent transparent transparent;
border-style: solid;
width: 0;
height:0;
}
改变border-color可以达到不同方向的扇形
背景图?
实现居中 background-position :center
不重复 background-repeat: no-repeat
大小 background-size
如何实现3d效果?
设置perspective:500px
transform-style:preserve-3d
然后设置transform :translate 啊 scale啊 rotate啊等等
实现动画的方式?
第一种transition 过渡动画
第二种keyframes 关键帧动画
过渡动画和关键帧动画的区别?
过渡动画需要有状态变化
关键帧动画不需要 ,而且关键帧动画控制更精细
如何实现逐帧动画?
animation参数 : keyframe名字 动画持续时间 动画速度曲线 动画延迟 动画播放次数 是否反向播放
使用关键帧动画 然后加上steps(1,start);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.container{
width: 100px;
height: 100px;
border: 1px solid red;
background: url(./animal.png) no-repeat;
animation: run 1s infinite;
animation-timing-function: steps(1);
}
@keyframes run{
0%{
background-position: 0 0;
}
12.5%{
background-position: -100px 0;
}
25%{
background-position: -200px 0;
}
37.5%{
background-position: -300px 0;
}
50%{
background-position: 0 -100px;
}
62.5%{
background-position: -100px -100px;
}
75%{
background-position: -200px -100px;
}
87.5%{
background-position: -300px -100px;
}
100%{
background-position: 0 0;
}
}
</style>
</head>
<body>
<div class="container">
</div>
</body>
</html>
css 动画和 js 动画的差异?
1.代码复杂度,js 动画代码相对复杂一些
2.动画运行时,对动画的控制程度上,js 能够让动画,暂停,取消,终止,css动画不能添加事件
3.动画性能看,js 动画多了一个js 解析的过程,性能不如 css 动画好
预处理器的作用?
常见的 sass less stylus
帮助更好的组织css代码
提高代码复用率
提升可维护性
预处理器的功能?
嵌套 反映层级
变量和计算 减少重复代码
extend和mixin
sass中循环
import css模块化
预处理器优缺点?
优点:提高代码复用率和可维护性
缺点:需要编译 有学习成本
bootstrap的优缺点?
优点:代码结构合理 现成样式可以直接用
缺点:体积大 想要特定的样式 需要覆盖原有样式 甚至是修改源码
bootstrap如何实现的响应式?
原理其实是媒体查询 在不同分辨率下有不同的class
css模块化?
1.使用less sass等预处理器
2.使用postCss插件
3.webpack处理css(css-loader和style-loader)
postcss作用?
取决于装了哪些插件
autoprefixer作用是为 CSS 中的属性添加浏览器特定的前缀
cssnext 负责把这些新特性转译成当前浏览器中可以使用的语法。
css modules是做什么的怎么用?
解决类名冲突的问题 在html中使用编译过不会冲突的类名
使用postcss或者webpack等构建工具进行编译
jQuery中$(’.classname’).get(0);$(’.classname’).eq(0); $(’.classname’)[0]
三者的区别?
(
’
.
l
i
−
t
e
s
t
’
)
.
g
e
t
(
0
)
和
(’.li-test’).get(0)和
(’.li−test’).get(0)和(’.li-test’)[0]返回的是DOM对象,而$(’.li-test’).eq(0)返回的是JQuery对象。
解释以下名词?
xhr:XMLHttpRequest 对象的一个实例
jsonp:用于解决主流浏览器的跨域数据访问的问题
cors:允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制
避免表单重复提交?
1.将提交按钮变为不可点击状态
function dosubmit() {
//获取表单提交按钮
Var btnSubmit = documen.getElementById(“sumit”);
//将表单提交按钮设置为不可用,可以避免用户再次点击提交按钮进行提交
btnSubmit.disabled = “disabled”;
//返回true让表单可以提交
return true;
}
2.POST/Redirect/Get设计模式 简单说就是用户提交一个表单后 执行一个客户端的重定向 跳转到提交成功的页面
3.在数据库添加唯一字段,防止出现重复数据 最有效
服务端渲染和客户端渲染
相同之处:渲染本质都是字符串拼接
不同:
服务端渲染性能消耗在服务端,访问人数多了可以使用缓存部分数据避免重复渲染
客户端渲染性能消耗在数据更新后,页面如何更新节省资源
服务端seo更好 不好之处在于前端更新了 后端也要改
客户端seo差
常见的块级元素:div h1~h6 ol ul li form p
常见的行内元素 a img input
区分html和h5?
DOCTYPE声明的方式是区分HTML和HTML5标志的一个重要因素,此外,还可以根据新增的结构、功能元素来加以区分。
css3新特性?
圆角 盒阴影 文字阴影 渐变 transform的xxxxx
新增的伪类选择器 :checked :nth-child :enable :disabled
ajax的原理 平时怎么发送请求?
通过XMLHttpRequest/ActiveXObject新建Ajax请求 通过onreadystatechange注册回调函数 使用open、setRequestHeader、send结合发送请求
平常发送网络请求:用axio 也用过fetch
css哪些样式可以继承?
font-size,font-weight,line-height,color,
es6的新功能
let/const
模板字符串
解构赋值
块级作用域
箭头函数
函数默认参数
70.原生js怎么添加class
通过 elem.className的方法添加
原生js实现jquery的addClass、removeClass、 hasClass 、toggleClass
function hasClass(obj, cls) {
var reg = new RegExp('(^|\\s)' + cls + '(\\s|$)')
return !!obj.className.match(reg) // 是obj.className.match(reg) ?true :false的简写
}
function addClass(obj, cls) {
if (!hasClass(obj, cls)) {
obj.className += ' ' + cls
}
}
function removeClass(obj, cls) {
if (hasClass(obj, cls)) {
var reg = new RegExp('(^|\\s)' + cls + '(\\s|$)')
obj.className = obj.className.replace(reg, ' ')
}
}
function toggleClass(obj, cls) {
if (hasClass(obj, cls)) {
removeClass(obj, cls)
} else {
addClass(obj, cls)
}
}
console.log(typeof hasClass(div, 'ha'))
71.
删除数组的元素用arr.splice, 返回被删除的元素
在对象的value(key-value)怎么再放一个对象?
直接赋一个对象
var obj = {
}
obj.h = {
a: 'hello'
}
for (var key in obj) {
console.log(key, obj[key])
}
只通过css实现固定长宽比?
使用padding-top/padding-bottom
比如我们容器的长宽比是 16:9 ,那么根据计算: 100% * 9 / 16 可以得到 56.25% 。如果你希望的是 4:3 ,那么对应的就是 100% * 3 / 4 。
<div class="aspectration" data-ratio="1:2">
<div class="content"></div>
</div>
// css
.aspectration {
width: 100%;
height:0; /*让容器高度由padding 撑开*/
position: relative; /*需要绝对定位*/
}
.aspectration .content {
padding-top: 200%; /* 100% 2 / 1 */
background: black;
}
js继承?
1.class类继承
相较于es5的继承方法 清晰方便了很多
class Parent {
constructor (name, age) {
this.name = name
this.age = age
}
saySomething () {
console.log(this.name)
}
}
Parent.prototype.callme = function () {
alert('call me ')
}
class Son extends Parent {
constructor (name, age) {
super(name, age) // ES6 要求,子类的构造函数必须执行一次super函数。
}
wow () {
super.saySomething() // super 在普通方法中指向父类的原型对象 在静态方法中,指向父类。
}
}
var son = new Son('wow', 18)
son.wow()
son.callme()
2.借用构造函数继承
function Parent(name) {
this.name = name
}
function Son(name) {
Parent.call(this, name) // apply也可以
this.type = 'son'
}
var son = new Son('ho')
console.log(son.type, son.name) // son ho
// 缺点 父类原型上的方法无法继承
Parent.prototype.haha = function () {
console.log('我是 ' + this.name)
}
// son.haha() // 报错
new Parent('天才').haha()
构造函数继承 子类没有继承父类原型链方法。原型链继承子类可以继承父类所有属性和方法。
3.原型链继承
function Parent() {
this.name = 'parent'
this.color = ['red', 'yellow']
}
Parent.prototype.callme = function () {
alert(this.name)
}
function Son() {
this.age = 1
}
Son.prototype = new Parent()
var son = new Son()
console.log(son.name)
son.callme()
// 解决了构造函数继承无法继承父类原型链上的方法
//缺点
son.color.push('black')
var son2 = new Son()
console.log(son2.color) ["red", "yellow", "black"]
// 明明只改变了第一个son实例的color数组 可是第二个实例也改变了
// 原因是他们两个实例的原型链上的对象都是同一个父类
4.组合继承
function Parent() {
this.name = "parent4";
this.colors = ["red","blue","yellow"];
}
Parent.prototype.sex = "男";
Parent.prototype.say = function(){console.log("Oh, My God!")}
function Son() {
Parent.call(this)
}
Son.prototype = Object.create(Parent.prototype)
Son.prototype.constructor = Son
var son1 = new Son()
var son2 = new Son()
son1.say()
son1.colors.push('black')
console.log(son2.colors) // ["red", "blue", "yellow"] 没有受到影响
对于创建对象完全不同的两种方法:
i)Student.prototype=Person.prototype
这种方法,创建Student的prototype对象,如果改变Student.prototype的值的时候,Person.prototype也会同时改变,为了避免这种情况,我们应采用其他方式;
ii)Student.prototype=Object.create(Person.prototype)
这种方法,创建的Student的Prototype对象,在改变Student.prototype的属性或者方法时,不会同时去改变Person.prototype的属性。
手写一个继承,并解释一下?
写组合继承,解释借用构造函数继承和原型链继承的缺点,最后说一下es6的class继承
实现一个递归,每隔1秒调用自身,一共调用一百次
function selfish() {
var timer
for (var i = 0; i < 100; i++) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function () {
selfish()
}, 1000)
}
}
selfish()
什么是组件 ?
js组件就是把一系列的功能封装起来,包装成一个对象。比如一个表格组件,一个表单组件等等。一个组件必然包含了某种特定的职能,目的在于可以复用。
怎么去设计一个组件封装?
组件封装的目的是为了复用,提高开发效率和代码质量
所以低耦合,单一职责,可复用性,可维护性是设计组件的原则
静态属性怎么继承?
利用call()实现类的静态属性继承
var class1 = function(x){
this.a = x;
}
var class2 = function(x,y){
class1.call(this,x);
this.b = y;
}
var obj = class2(1,5);
console.log("obj.a:"+obj.a+",obj.b"+obj.b);
结果:
obj.a:1,obj.b:5
vue怎么实现双向绑定的?
首先说一下mvvm和vue
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。
1.实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。
vue是通过Object.defineProperty()来实现数据劫持的。
它可以来控制一个对象属性的一些特有操作,比如读写权、是否可以枚举,这里我们主要先来研究下它对应的两个描述属性get和set
实现页面的局部刷新?
第一种:
当某几个页面都有相同的头部、导航、底部的时候,点击导航链接可以在几个页面中切换,此时想要的效果是点击链接后只切换内容部分,其他不再重新加载。上代码。
jq-load.html:
<!DOCTYPE html>
<html>
<head>
<title>ajax局部刷新</title>
</head>
<body>
<header>
<nav>
<a href="jq-load.html" rel="external nofollow" class="current">首页</a>
<a href="jq-load2.html" rel="external nofollow" >新闻资讯</a>
<a href="jq-load3.html" rel="external nofollow" >用户中心</a>
</nav>
</header>
<section id="content">
<div id="container">
首页的内容
</div>
</section>
<script src="js/jquery-1.11.0.min.js"></script>
<script src="js/jq-load.js"></script>
</body>
</html>
注: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:
<!DOCTYPE html>
<html lang="en">
<head>
<title>个人中心</title>
<meta charset="utf-8">
<script src="js/jquery-1.11.0.min.js"></script>
<script src="js/user.js"></script>
</head>
<body>
<div class="userWrap">
<ul class="userMenu">
<li class="current" data-id="center">用户中心</li>
<li data-id="account">账户信息</li>
<li data-id="trade">交易记录</li>
<li data-id="info">消息中心</li>
</ul>
<div id="content"></div>
</div>
</body>
</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:
<div>
用户中心
……
</div>
判断{}{}? [][]? null==undefined?
// 以下全是false
console.log([] == [])
console.log({} == {})
console.log(NaN == NaN)
中间固定,两边自适应
1浮动加负边距
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>中间固定宽度,两边自适应布局-浮动加负边距</title>
<style type="text/css">
*{
margin: 0px;
padding: 0px;
}
.wrap{
overflow: hidden;
margin-top: 20px;
}
.center{
width: 70px;
text-align: center;
float: left;
}
.left{
line-height: 30px;
height: 30px;
float: left;
width: 50%;
margin-left: -35px;
}
.right{
line-height: 30px;
height: 30px;
float: right;
width: 50%;
margin-right: -35px;
}
hr{ height:1px;border:none;border-top:1px solid red;}
</style>
</head>
<body>
<div class="wrap">
<div class="left">
<hr style="margin-top: 14px;">
</div>
<div class="center">测试居中</div>
<div class="right">
<hr style="margin-top: 14px">
</div>
</div>
</body>
</html>
2.flex
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>中间固定宽度,两边自适应布局-弹性盒子模型</title>
<style type="text/css">
*{
margin: 0px;
padding: 0px;
}
.wrap{
display: flex;
flex-direction: row;
margin-top: 20px;
}
.center{
width: 70px;
text-align: center;
}
.left,.right{
flex-grow: 1;
line-height: 30px;
height: 30px;
}
hr{ height:1px;border:none;border-top:1px solid red;}
</style>
</head>
<body>
<div class="wrap">
<div class="left">
<hr style="margin-top: 14px">
</div>
<div class="center">测试剧中</div>
<div class="right">
<hr style="margin-top: 14px">
</div>
</div>
</body>
</html>
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 = "example@qq.com";
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禁用浏览器的前进后退按钮?
<script type="text/javascript" language="javascript">
$(document).ready(function() {
window.history.forward(1);
//OR window.history.forward(-1);
});
</script>
写出一个简单的$.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
<div>
<ul id="ul-list"></ul>
</div>
</body>
<script>
var $txtTitle = $('#txt-title')
var $ulList = $('#ul-list')
var $btnSubmit = $('#btn-submit')
$btnSubmit.click(function () {
var title = $txtTitle.val()
var $li = $('<li>' + title + '</li>')
$ulList.append($li)
$txtTitle.val('')
})
. f n . e x t e n d ( ) 核 心 代 码 实 现 ? 其 中 , 60 − 64 行 是 一 个 特 别 重 要 的 函 数 , 就 是 平 时 用 的 .fn.extend()核心代码实现? 其中,60-64行是一个特别重要的函数,就是平时用的 .fn.extend()核心代码实现?其中,60−64行是一个特别重要的函数,就是平时用的() jQuery()对外的接口
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},
但是现在这个jQuery还是以局部变量的形式存在,要提供对外的接口,才能使用。提供接口在第8823-8827行
// If there is a window object, that at least has a document property,
// define jQuery and $ identifiers
if ( typeof window === "object" && typeof window.document === "object" ) {
window.jQuery = window.$ = jQuery;
}
7.在第96-283行,都是给jQuery对象添加一些方法和属性。
prototype(原型)是面向对象的东西,所以说,jQuery就是一个基于面向对象的程序,jQuery里面写的都是跟面向对象有关的。
//96行
jQuery.fn = jQuery.prototype
// extend
JQuery.extend({
speak:function(){
alert("how are you!");
}
});
$(this) 和 this 关键字在 jQuery 中有何不同?
$(this) 返回一个 jQuery 对象,你可以对它调用多个 jQuery 方法,比如用 text() 获取文本,用val() 获取值等等。
而 this 代表当前元素,它是 JavaScript 关键词中的一个,表示上下文中的当前 DOM 元素。你不能对它调用 jQuery 方法,直到它被 $() 函数包裹,例如 $(this)。
jquery怎么移除标签onclick属性?
获得a标签的onclick属性: $(“a”).attr(“onclick”)
删除onclick属性:$(“a”).removeAttr(“onclick”);
设置onclick属性:$(“a”).attr(“onclick”,“test();”);
75.
简述一下src与href的区别?
href 是指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,用于超链接。
src是指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求src资源时会将其指向的资源下载并应用到文档内,例如js脚本,img图片和frame等元素。
简述同步和异步的区别?
同步是阻塞模式,异步是非阻塞模式。
同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;
异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
浏览器的内核分别是什么?
IE: trident内核
Firefox:gecko内核
Safari:webkit内核
Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核
Chrome:Blink
什么叫优雅降级和渐进增强?
渐进增强
针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级
一开始就构建完整的功能,然后再针对低版本浏览器进行兼容。
document.write和innerHTML的区别?
document.write是直接写入到页面的内容流,每次写完关闭之后重新调用该函数,会导致页面被重写。
innerHTML则是DOM页面元素的一个属性,代表该元素的html内容,将内容写入某个DOM节点,不会导致页面全部重绘
react和vue有哪些不同,说说你对这两个框架的看法
相同点
· 都支持服务器端渲染
· 都有Virtual DOM,组件化开发,通过props参数进行父子组件数据的传递,都实现webComponent规范
· 数据驱动视图
· 都有支持native的方案,React的React native,Vue的weex
不同点
· React严格上只针对MVC的view层,Vue则是MVVM模式
· virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制
· 组件写法不一样, React推荐的做法是 JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即’all in js’; Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,jd写在同一个文件;
· 数据绑定: vue实现了数据的双向绑定,react数据流动是单向的
· state对象在react应用中不可变的,需要使用setState方法更新状态;在vue中,state对象不是必须的,数据由data属性在vue对象中管理
eval()的作用?
把字符串参数解析成JS代码并运行,并返回执行的结果;
eval(“2+3”);//执行加运算,并返回运算值。
eval(“varage=10”);//声明一个age变量
meta的作用
meta里的数据是供机器解读的,告诉机器该如何解析这个页面,还有一个用途是可以添加服务器发送到浏览器的http头部内容
display:none visibility :hidden区别?
display:none是彻底消失,不在文档流中占位,浏览器也不会解析该元素;visibility:hidden是视觉上消失了,可以理解为透明度为0的效果,在文档流中占位,浏览器会解析该元素;
前者引发重绘与回流 后者不会
CSS中 link 和@import 的区别是?
A:(1) link属于HTML标签,而@import是CSS提供的; (2) 页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;(3) import只在IE5以上才能识别,而link是HTML标签,无兼容问题; (4) link方式的样式的权重 高于@import的权重.
iframe框架的缺点?
不利于seo
阻塞页面的onload事件
如何实现浏览器内多个标签页之间的通信?
调用localstorge、cookies等本地存储方式
如何获取UA?
document.Browser.Agent.value=navigator.userAgent; 就说之类的 其他不想记
什么是CSS 预处理器 / 后处理器?
-
预处理器例如:LESS、Sass、Stylus,用来预编译Sass或less,增强了css代码的复用性,
还有层级、mixin、变量、循环、函数等,具有很方便的UI组件模块化开发能力,极大的提高工作效率。 -
后处理器例如:PostCSS,通常被视为在完成的样式表中根据CSS规范处理CSS,让其更有效;目前最常做的
是给CSS属性添加浏览器私有前缀,实现跨浏览器兼容性的问题。
li与li之间有看不见的空白间隔是什么原因引起的?有什么解决办法?
行框的排列会受到中间空白(回车\空格)等的影响,因为空格也属于字符,这些空白也会被应用样式,占据空间,所以会有间隔,把字符大小设为0,就没有空格了。
css多列等高如何实现?
1.flex
<div class="container">
<div class="left">多列等高布局左<br/>多列等高布局左</div>
<div class="right">多列等高布局右</div>
</div>
.container{
display:flex;
}
.left,.right{
flex:1;
}
.left{
background:pink;
}
.right{
background:green;
}
2.使用内外边距相抵消,注意父元素设置 “overflow:hidden;”
<div id="container">
<div id="left" class="column aside">
<p>Sidebar</p>
</div>
<div id="content" class="column section">
<p>Main content;content;content;content;content</p>
</div>
<div id="right" class="column aside">
<p>Sidebar</p>
</div>
</div>
#container {
margin: 0 auto;
overflow: hidden;
width: 960px;
}
.column {
background: #ccc;
float: left;
width: 200px;
margin-right: 5px;
margin-bottom: -99999px;
padding-bottom: 99999px;
}
#content {
background: #eee;
}
#right {
float: right;
margin-right: 0;
}
CSS里的visibility属性有个collapse属性值是干嘛用的?
当一个元素的visibility属性被设置成collapse值后,对于一般的元素,它的表现跟hidden是一样的。但例外的是,如果这个元素是table相关的元素,例如table行,table group,table列,table column group,它的表现却跟display: none一样
什么是外边距合并?
外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距。
合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。
水平方向不会发生边距重叠
zoom:1的清除浮动原理?
Zoom属性是IE浏览器的专有属性,它可以设置或检索对象的缩放比例
当设置了zoom的值之后,所设置的元素就会就会扩大或者缩小,高度宽度就会重新计算了,这里一旦改变zoom值时其实也会发生重新渲染,运用这个原理,也就解决了ie下子元素浮动时候父元素不随着自动扩大的问题。
margin和padding分别适合什么场景使用?
margin是用来隔开元素与元素的间距;padding是用来隔开元素与内容的间隔。
margin用于布局分开元素使元素与元素互不相干;
padding用于元素与内容之间的间隔,让内容(文字)与(包裹)元素之间有一段间距
一些题目
var z = 10;
function foo(){
console.log(z);
}
(function(funArg){
var z = 20;
funArg();
})(foo);
// 打印10
如何匹配敏感字 并为字添加 红色字体?
<div id="p">中国军队和阿扁一起办证</div>
<script>
var p = document.querySelector('#p');
var str = p.innerHTML;
var pattern = /国军|阿扁|办证/g;
var newStr = str.replace(pattern,function($1) {
return '<span style="color: red;">' + $1 + '</span>';
});
p.innerHTML = newStr;
基于观察者模式的事件绑定机制?
观察者模式:又称为发布订阅模式,是一种一对多的关系,多个观察者同时监听同一个对象,一旦这个对象发生了变化,会通知所有观察者,发布者和订阅者互相不知道对方的存在,仅仅共享一个自定义事件的名称
function Pubsub() { // 定义观察者类 pubsub
// 存放事件和对应的处理方法
this.handles = {}
}
Pubsub.prototype = {
// 传入事件类型type和事件处理handle
on: function (type, handle) {
if (!this.handles[type]) {
this.handles[type] = []
}
this.handles[type].push(handle)
// console.log(this.handles[type]) // 'haha: function(name) {}'
},
emit: function () { // 实现事件的订阅 on
// 通过传入参数来获取事件类型
var type = Array.prototype.shift.call(arguments)
// console.log(type) // 'haha' 第一个参数是type
if (!this.handles[type].length) { // 如果没有定义直接返回false
console.log('没有这个事件')
return false
}
for (var i = 0; i < this.handles[type].length; i++) {
var handle = this.handles[type][i]
// 执行事件
handle.apply(this, arguments) // 这里的arguments已经shift了第一个参数
}
},
off: function (type, handle) { // 取消订阅
var handles = this.handles[type]
if (handles) {
if (!handle) {
handles.length = 0 // 清空数组
} else {
for (var i = 0; i < handles.length; i++) { // 删除单个handle
var _handle = handles[i]
if (_handle === handle) {
handles.splice(i, 1)
}
}
}
}
}
}
var p1 = new Pubsub()
// 订阅
p1.on('haha', function (name) {
console.log('haha:name ' + name)
})
// 发布事件
p1.emit('haha', '哈哈') // 打印了哈哈
var fn = function (age) {
console.log('haha:age ' + age)
}
p1.on('haha', fn)
p1.emit('haha', 12) // 打印哈哈 和 12
// 取消订阅
p1.off('haha', fn)
p1.emit('haha', 'rua') // 只打印第一个handle函数
// 全部取消
p1.off('haha')
p1.emit('haha', '取消了吗') // 无事发生
/*console.log([] == []) // fasle
console.log([] == ![]) // true
console.log([] == false) // true
console.log('true' == true) // false
console.log('haha' == 1) // false
console.log('' == false) // true
console.log(1 == true) // true
console.log(0 == false) // true
console.log(0 == '0') // true
console.log({} == {}) // false
console.log(NaN == false) // false
console.log(NaN == NaN) //false
console.log(![] ) // false 所以判断是否为一个空数组使用 !arr.length判断
console.log(!{}) // false
console.log(!0) // true*/
应用场景就是订阅某个博主 博主更新了博客 订阅的人能看到~
工厂模式
应用场景 对象比较复杂 对象有很多相同的小属性 需要依赖具体环境创建实例
// 抽象工厂模式 先设计一个抽象类,这个类不能被实例化,只能用来派生子类,最后通过对子类的扩展实现工厂方法
var weChatUser = function () {}
// 如果子类继承WechatUser但是并没有去重写getName,
// 那么子类的实例化对象就会调用父类的getName方法并抛出错误提示。
weChatUser.prototype = {
getName: function () {
return new Error('抽象方法 不能调用')
}
}
// AccountFactory就是一个抽象工厂方法,
// 该方法在参数中传递子类和父类,在方法体内部实现了子类对父类的继承。
var AccountFacto = function (subType, superType) {
// 判断抽象工厂中是否有该抽象类
if (typeof AccountFacto[superType] === 'function') {
// 缓存类
function F() {}
// 继承父类属性和方法
F.prototype = new AccountFacto[superType]()
// 将子类的constructor指向子类
subType.constructor = subType
// 子类原型继承父类
subType.prototype = new F()
} else {
throw new Error('抽象类不存在')
}
}
// 微信用户抽象类
AccountFacto.WeChatUser = function () {
this.type = 'wechat'
}
AccountFacto.WeChatUser.prototype = {
getName: function () {
return new Error('抽象方法 不能调用')
}
}
// qq用户抽象类
AccountFacto.QQUser = function () {
this.type = 'qq'
}
AccountFacto.QQUser.prototype = {
getName: function () {
return new Error('抽象方法 不能调用')
}
}
// 普通用户子类
function UserOfWeChat(name) {
this.name = name;
}
// 抽象工厂实现weChatUser类继承
AccountFacto(UserOfWeChat, 'WeChatUser') // 这里传的第二个参数是字符串类型 因为object的key只能是字符串类型
// 子类中重写抽象方法
UserOfWeChat.prototype.getName = function () {
return this.name
}
// qq也类似 这里就不写了
// 实例化
let weChatUserA = new UserOfWechat('微信用户a')
console.log(weChatUserA.getName(), weChatUserA.type)
单例模式
单例就是保证一个类只有一个实例
js字面量形式是一个天生的 单例
var zhangsan = {}
var lisi = {}
console.log(zhangsan == lisi) // false 运用为命名空间
通用单例模式
function getSingleton(fn) {//专门实现单例
var instance = null;
return function () {
return instance || (instance = fn.apply(null, arguments));//有些函数需要传参 所以改写为这样 null表示不改变this
};
}
js判断数组是否含有某个值
方法一: arr.indexOf()
if (arr.indexOf(2) != -1){
console.log("数组含有2")
}else {
console.log("数组不含2")
}
方法二: for循环结合if判断
复制代码
for (let i = 0;i < arr.length;i++){
if (arr[i] === 2){
console.log("数组含有2")
}else {
console.log("数组不含2")
}
}
复制代码
方法三: arr.find(callback)
arr.find(value => {
if (value === 2){
console.log("数组含有2")
}
})
方法四: arr.includes() 数组中含有某值返回true,没有返回false。ES6新方法。
let arr = [1,2,3,4];
if(arr.includes(2)){
console.log("数组中有2");
}else{
console.log("数组中无2");
}
判断是否为空对象
var obj = {}
// 1.for in遍历
function empty(obj) {
for(var key in obj) {
return console.log('非空对象')
}
return console.log('空的')
}
empty(obj)
// 2.json对象转json字符串来判断
console.log(JSON.stringify(obj) === '{}') // true
// 3.es6的Object.keys()方法
console.log(Object.keys(obj).length === 0) // true
display有哪些值?
none:此元素不显示。
block:将元素显示为块级元素
inline:默认值,元素会被显示为内联元素
inline-block:行内块级元素。
table 元素视为类似于table标签
table-cell 元素被视为表格单元
flex flex布局
inline-flex 行内flex
position 中,relative 和 absolute 的区别,包括使用时的注意事项和定位原点
relative是相对定位 定位原点是元素本来的 位置
absolute是绝对定位 定位原点是离自己最近的一级定位不为static的父元素
以下输出什么?
var a = 100;
function testResult(){
console.log(a)
var b = 2 * a; // undefined
var a = 200;
var c = a / 2;
console.log(b); // NaN
console.log(c); // 100
}
testResult();
console.log(undefined * 2) // NaN
给定一些文档(docs)、词(words),找出词在文档中全部存在的所有文档
var docs = [
{
id: 1,
words: ['hello',"world"]
},
{
id: 2,
words: ['hello',"kids"]
},
{
id: 3,
words: ['zzzz',"hello"]
},
{
id: 4,
words: ['world',"kids"]
}
];
function findDocList(docs, arrKey) {
var target = []
var targetStr = arrKey.join('?')
for (var i = 0; i < docs.length; i++) {
var wordStr = docs[i].words.join('?')
if (wordStr.indexOf(targetStr) > -1) {
target.push(docs[i].id)
}
}
if (!target.length) {
return '没找到'
}
target = target.map(function (item, index) {
return '文档' + item
})
return target.join(',')
}
console.log(findDocList(docs, ['world', 'hello']))
上面这个方法不太好,换了搜索词的顺序就找不到了
tips:
1.如何判断两个数组相同
console.log([].toString() === [].toString()) // true
console.log([1,2,3].toString() === [3,2,1].toString()) // false
console.log([1,2,3].sort().toString() === [3,2,1].sort().toString()) // true
2.如何判断两个数组有相同的元素
// 1. 取出数组中不同的元素 filter不会改变原数组
var arr1 = [1,3,5,‘7’]
var arr2 = [2,5,‘1’,7]
var different = arr1.concat(arr2).filter(function (item, index, arr) {
return arr.indexOf(item) === arr.lastIndexOf(item)
})
console.log(different)
// 2. 返回相同的元素
var result = []
for (var i = 0; i < arr1.length; i++) {
for (var j = 0; j < arr2.length; j++) {
if (arr1[i] === arr2[j]) {
result.push(arr2[j])
}
}
}
console.log(result)
3.字符串和数组互相转化
// 数组转字符串
var arr = ['我',1,'dada',5]
b = arr.join('|') // 不改变原数组
console.log(b, arr) // 我|1|dada|5
// 字符串转数组
c = b.split('|')
console.log(c)
为什么无法定义1px左右高度的容器
ie6有默认行高
解决办法 设置line-height:1px
请以缩写方法写出 1px 直线灰色,上面无边框的矩形边框样式。
<div style="width: 100px; height: 100px; outline: grey solid 1px"></div>
以下打印结果?
var test = (function(a){
this.a = a;
console.log(this.a) // 1
return function(b){
console.log('b:' + b) // 3
return this.a + b;
}
}(function(a,b){
console.log(a,b) // 1, 2
return a;
}(1,2)));
console.log(test(3)) // 1 + 3 = 4
sass和less的异同
共同点:
语法上有相同的地方:
1.有变量
2.mixin class中的class
3.嵌套规则
4.可以计算
不同点
Less和Sass的主要不同就是他们的实现方式。
Less是基于JavaScript,是在客户端处理的。
Sass是基于Ruby的,是在服务器端处理的。
关于变量在Less和Sass中的唯一区别就是Less用@,Sass用$。
** 不用循环,创建一个长度为 100 的数组,并且每个元素的值等于它的下标。**
// 1. object.keys 返回的是数组 但是由于keys是字符串 我们要用map转为number类型
console.log(Object.keys(Array.apply(null, {length: 100})).map(item => {
return +item // 也可以用parseInt 这里是个小技巧 字符串转数字
}))
// 2 .Array.from方法 第二个参数起map作用
console.log(Array.from({length: 100}, (value, key) => {
return key
}))
// 3. 定时器
var arr = []
var i = 0
var timer = setInterval(function () {
arr[i] = i++
if (i >= 100) {
clearInterval(timer)
console.log(arr)
}
})
// 4 .递归
var arr2 = []
var j = 0
function makeArray(num) {
if (j < num) {
arr2[j] = j++
makeArray(num)
}
return arr2
}
console.log(makeArray(100))
问测试工具就说 名字不记得了 好像是y开头什么什么的
当点击一个页面内的元素时,alert 出这个元素的标签名
document.addEventListener(‘click’, function (e) {
alert(e.target.tagName) // 结果是大写
})
输出结果
(function(){
var a = b = 3;
console.log(a, b) // 3, 3
})();
console.log("a defined?" + (typeof a != 'undefined')); // false
console.log("b defined?" + (typeof b != 'undefined')); // true
// b是个自由变量 所以在全局作用域中也能找到 而a是在函数作用域中声明的 外部无法调用
var myObject = {
foo: "bar",
func: function(){
var self = this;
console.log('outer func : this.foo' + this.foo); // bar
console.log('outer func : self.foo' + self.foo); // bar
(function(){
console.log(this) // window
console.log('inner func : this.foo' + this.foo); // undefined
console.log('inner func : self.foo' + self.foo); // bar
})();
}
};
myObject.func();
console.log(0/0) // NaN
console.log(1/0) // Infinity
var arr = [1,'abc',function(){alert(3333);}];
alert(arr[2]()); // alert 3333 然后 第二次alert undefined 因为默认return undefined
arr[2](); // 3333
var len = 4
while(len--){
setTimeout(function(){console.log(len)},3000);
console.log(len);
}
// 打印结果为 3 2 1 0 -1 -1 -1 -1
window.name = "Window";
var cat = {
name:'Cat'
};
var dog = {
name:'Dog',
sound:function(word){
console.log(this.name + word);
}
};
dog.sound("is pooping");
dog.sound.call(window,"is banking");
dog.sound.call(dog,"is banking");
dog.sound.apply(cat,['喵喵喵']); // cat 喵喵喵 apply第二个参数可以传一个数组 数组元素是后续要传的参数
for(var i = 0,j = 0; i < 10, j < 6; i++, j++){
value = i + j;
console.log(value) // 0 2 4 6 8 10
}
alert(value); // 5 + 5 = 10
if(!("a" in window)){
var a = 1;
console.log(a) // 不打印
}
alert(a); // undefined
打乱数组元素
var arr = [1, 2, 3, 4, 5];
function randomsort(a, b) {
return Math.random()>.5 ? -1 : 1;
//用Math.random()函数生成0~1之间的随机数与0.5比较,返回-1或1
}
console.log(arr.sort(randomsort));
h5新增的表单元素
email 类型用于验证email的格式,当提交表单时会自动验证email域的值
url 类型用于验证 URL 地址的格式,当提交表单时会自动验证url域的值
range 一个可以拉的东西
date 可以选择年月日
search 类型用于搜索域
css3新增的文本效果
text-shadow box-shadow word-wrap 文本换行
关于Http 2.0 你知道多少?
HTTP/2引入了“服务端推(server push)”的概念,它允许服务端在客户端需要数据之前就主动地将数据发送到客户端缓存中,从而提高性能。
HTTP/2提供更多的加密支持
HTTP/2使用多路技术,允许多个消息在一个连接上同时交差。
它增加了头压缩(header compression),因此即使非常小的请求,其请求和响应的header都只会占用很小比例的带宽。
web storage和cookie的区别
Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的。Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可以跨域调用。
除此之外,Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。
但是cookie也是不可以或缺的:cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生
CSS中link 和@import的区别是?
(1) link属于HTML标签,而@import是CSS提供的;
(2) 页面被加载的时,link会同时被加载,而@import被引用的CSS会等到引用它的CSS文件被加载完再加载;
(3) import只在IE5以上才能识别,而link是HTML标签,无兼容问题;
(4) link方式的样式的权重 高于@import的权重.
position:absolute和float属性的异同
§ 共同点:对内联元素设置float和absolute属性,可以让元素脱离文档流,并且可以设置其宽高。
§ 不同点:float仍会占据位置,absolute会覆盖文档流中的其他元素。
说一下常见的兼容问题?
浮动ie产生的双倍距离(IE6双边距问题:在IE6下,如果对元素设置了浮动,同时又设置了margin-left或margin-right,margin值会加倍。)
#box{ float:left; width:10px; margin:0 0 0 100px;}
这种情况之下IE会产生20px的距离,解决方案是在float的标签样式控制中加入
_display:inline;将其转化为行内属性。
如何实现浏览器内多个标签页之间的通信?
调用localstorge、cookies等本地存储方式
谈谈你对重构的理解
网站重构:在不改变外部行为的前提下,简化结构、添加可读性,而在网站前端保持一致的行为。也就是说是在不改变UI的情况下,对网站进行优化,
对于传统的网站来说重构通常是:
表格(table)布局改为DIV+CSS
针对于SEO进行优化
增强用户体验
压缩JS、CSS、image等前端资源(通常是由服务器来解决)
采用CDN来加速资源加载
git fetch和git pull的区别
git pull:相当于是从远程获取最新版本并merge到本地
git fetch:相当于是从远程获取最新版本到本地,不会自动merge
input 和 textarea
input和textarea的区别
1.input需要指定type属性,通过size来指定显示字符的长度,maxlength指定 文本框最大输入长度,焦点垂直居中 文本框,单行
2.textarea,使用row、col指定textarea的大小,焦点在左上角,多行
用div模拟实现textarea
核心在于contenteditable=“true”这个属性
<div class="textarea" contenteditable="true"></div>
.textarea {
width: 300px;
min-height: 120px;
max-height: 300px;
border: 1px solid #333;
overflow-y: auto;
}
原生js实现网页加载进度条
参考https://blog.csdn.net/qq_42345237/article/details/82710535
自动生成gif图标的一个网址:preloaders.net
<style>
.loading {
width: 100%;
height:100%;
position: fixed;
top: 0;
left:0;
z-index: 100;
background-color: #fff;
}
.loading .pic {
height: 10px;
background: url("./292.gif") center center no-repeat;
text-align: center;
}
</style>
</head>
<body>
<div class="loading">
<div class="pic"></div>
</div>
<p>判断页面加载完毕</p>
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779145193&di=88f99c68903b47c4e386755b73893335&imgtype=0&src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1212%2F21%2Fc2%2F16781720_1356079420979.jpg" alt=""/>
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779184701&di=f3ab80235c5ddf5adb9d6b06ce47e82c&imgtype=0&src=http%3A%2F%2Fattachments.gfan.com%2Fforum%2Fattachments2%2Fday_110730%2F110730052814920f360299a915.jpg" alt="">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779211730&di=4c244c8bd60f74b1832625e27c063fc0&imgtype=0&src=http%3A%2F%2Fi3.download.fd.pchome.net%2Ft_960x600%2Fg1%2FM00%2F09%2F12%2FoYYBAFO6NYCIE0tSAAdYOvon7RoAABtkwF4hgIAB1hS650.jpg" alt="">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779225935&di=4c13b2276bbe03877d4c5ea0cc56cc98&imgtype=0&src=http%3A%2F%2Fc15.eoemarket.net%2Fapp0%2F652%2F652549%2Fscreen%2F3260012.png" alt="">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779271901&di=3ccda1af260cf969189de3f52ea31686&imgtype=0&src=http%3A%2F%2Fpic1.ytqmx.com%3A82%2F2015%2F0526%2F14%2F02.jpg%2521720.jpg" alt="">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779311038&di=0599243d4fe87313ed37ee416cd73d6a&imgtype=0&src=http%3A%2F%2Fwww.desktx.cc%2Fd%2Ffile%2Fwallpaper%2Fscenery%2F20170105%2F2647448be73294d17c28d91407661f8c.jpg" alt="">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779320074&di=ec9d10c18c21daec3b89b5573c22ef0f&imgtype=0&src=http%3A%2F%2Fpicture.ik123.com%2Fuploads%2Fallimg%2F170320%2F3-1F320150H5.jpg" alt="">
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779349967&di=11eaaee20a3da68abf58938bdad012e0&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2017-11-29%2F5a1e13119deee.jpg" alt="">
</body>
<script>
// 重点代码
var loading = document.querySelector('.loading')
document.onreadystatechange = function () {
if (document.readyState === 'complete') {
loading.style.display = 'none'
}
}
图片懒加载
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
}
body {
background-color: #edeff0;
}
.course {
width: 1208px;
background-color: #fff;
padding: 20px 0 0 20px;
margin: 800px auto;
overflow: hidden;
}
.course .course-item {
float: left;
width: 280px;
border: 1px solid #ebebeb;
background-color: #fff;
box-shadow: 0 1px 2px #c5c5c5;
margin: 0 20px 20px 0;
cursor: pointer;
}
.course-item:hover {
box-shadow: 0 2px 8px #bbb;
}
.img-container {
height: 160px;
overflow: hidden;
}
.course-item p {
text-align: center;
line-height: 54px;
}
</style>
</head>
<body>
<ul class="course">
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/0.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/1.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/2.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/3.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/4.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/5.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/6.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/7.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/8.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/9.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/10.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/11.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/12.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/13.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/14.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
<li class="course-item">
<div class="img-container"><img src="img/placeholder.gif" alt="" data-src="img/15.jpg" class="lazy"></div>
<p>前端课程</p>
</li>
</ul>
</body>
<script>
// 1. 方法1
// ①通过document.documentElement.clientHeight获取屏幕可视窗口高度
// ②通过element.offsetTop获取元素相对于文档顶部的距离
// ③通过document.documentElement.scrollTop获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离
// ② - ③ < ① 那么元素出现在屏幕可视区域 可以自己画个图
// 方法2 通过getBoundingClientRect()方法来获取元素的大小以及位置
const clientHeight = window.innerHeight // 可视区的高度
// 判断是否在可视区
function isInsight(elem) {
// 表示图片到可视区域顶部距离;
const bound = elem.getBoundingClientRect()
// 也就是说,在bound.top<=clientHeight时,图片是在可视区域内的。
return bound.top <= clientHeight // 加一百是为了提前加载图片
}
// 加载真正的图片
function loadImg(elem) {
var trueSrc = elem.dataset.src
elem.src = trueSrc
}
function handle() {
console.log(this)
const imgs = Array.prototype.slice.call(document.querySelectorAll('.lazy'))
imgs.forEach(function (item, index) {
if (isInsight(item)) {
loadImg(item)
}
})
}
function debounce(func) { // 函数节流 :让一个函数不要执行的太频繁,减少一些过快的调用来节流。
var timer = null
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function() {
func.apply(this, arguments)
}, 1000)
}
}
window.onload = function () {
handle()
}
window.addEventListener('scroll',debounce(handle))
window.addEventListener('resize', debounce(handle))
</script>
</html>
实现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个兄弟节点中的最后一个节点拖拽到节点
<ul>
<li id="li1" draggable="true">1</li>
<li id="li2" draggable="true">2</li>
<li id="li3" draggable="true">3</li>
<li id="li4" draggable="true">4</li>
<li id="li5" draggable="true">5</li>
</ul>
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事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0;
}
div.router-wrap {
width: 100%;
height: 100%;
background: #fefefe;
}
a {
padding: 10px;
color: pink;
font-size: 25px;
font-weight: bold;
text-decoration: none;
}
</style>
</head>
<body>
<div class="router-wrap">
<a href="#/black">黑色</a><br>
<a href="#/green">绿色</a><br>
<a href="#/red">红色</a>
</div>
<script>
// 创建Router构造函数
// currentHash为当前hash值,routes为路径对象
function Router() {
this.currentHash = '/'
this.routes = {}
}
// 注册路径,每个路径对应一个回调函数。
Router.prototype.route = function (path, callback) {
this.routes[path] = callback || function () {
alert('未定义回调函数')
}
}
// 更新页面函数
Router.prototype.refresh = function () {
this.currentHash = location.hash.slice(1) || '/'
this.routes[this.currentHash] ()
}
// 初始化
Router.prototype.init = function () {
var self = this
window.addEventListener('load', function () {
self.refresh()
})
window.addEventListener('hashchange', function () {
self.refresh()
})
}
var wrap = document.querySelector('.router-wrap')
// 实例化Router
window.Router = new Router()
// 注册路由 实现相应功能
Router.route('/', function () {
wrap.style.backgroundColor = '#fefefe'
})
Router.route('/black', function () {
wrap.style.backgroundColor = 'black';
});
Router.route('/green', function () {
wrap.style.backgroundColor = 'green';
});
Router.route('/red', function () {
wrap.style.backgroundColor = 'red';
});
Router.init()
</script>
</body>
</html>
- 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度旋转
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div{
width:120px;
height:120px;
line-height:120px;
margin: 20px;
background-color: #5cb85c;
float: left;
font-size: 12px;
text-align: center;
color:orangered;
}
.img1, .img2, .img3, .img4 {
-webkit-transition: All 0.4s ease-in-out;
-moz-transition: All 0.4s ease-in-out;
-ms-transition: All 0.4s ease-in-out;
-o-transition: All 0.4s ease-in-out;
transition: All 0.4s ease-in-out;
}
.img1:hover {
transform: rotate(360deg);
}
.img2:hover {
transform: scale(1.2);
}
.img3:hover {
transform: rotate(360deg) scale(1.2);
}
.img4:hover {
transform: translate3d(0, -10px, 0);
}
</style>
</head>
<body>
<div class="img1">效果一:360°旋转 </div>
<div class="img2">效果二:放大</div>
<div class="img3">效果三:旋转放大</div>
<div class="img4">效果四:上下左右移动 </div>
<script>
</script>
</body>
</html>
position:absolute和float属性的异同
共同点:对内联元素设置float和absolute属性,可以让元素脱离文档流,并且可以设置其宽高。
不同点:float仍会占据位置,absolute会覆盖文档流中的其他元素。
兼容问题
1.不同浏览器的margin和padding不同
解决办法*{margin:0;padding:0;}
2.ie6双倍边距问题
<div style="float:left;margin-left:10px;"> </div>
会出现实际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布局
- 标签最低高度设置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事件?
可以。
.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)
<!--console输出结果是什么,考察即时函数的执行流程-->
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)
浮动元素水平居中
宽度不固定的浮动元素
<div class="outerbox">
<div class="innerbox">我是浮动的</div>
</div>
.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终止本次循环
图片预加载
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body{
height: 100%;
}
a{
text-decoration: none;
}
.box{
text-align: center;
}
img {
width: 1024px;
height:640px;
}
.btn{
display: inline-block;
height: 30px;
line-height: 30px;
border: 1px solid #ccc;
background-color: #fff;
padding: 0 10px;
margin-right: 50px;
color: #333;
}
.btn:hover{
background-color: #eee;
}
.btn:disabled {
color: red;
border: 1px solid red;
}
.loading{
position: fixed;
top:0;
left: 0;
width: 100%;
height: 100%;
background-color: #eee;
text-align: center;
font-size: 30px;
}
.progress{
position: absolute;
top: 50%;
left: 50%;
margin-top: -20px;
margin-left: -23px;
}
</style>
</head>
<body>
<div class="box">
<img src="https://timgsa.baidu.com/timg?image&quality80&sizeb9999_10000&sec1536779145193&di88f99c68903b47c4e386755b73893335&imgtype0&srchttp%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1212%2F21%2Fc2%2F16781720_1356079420979.jpg"
alt="" id="img">
<p id="parent">
<input type="button" class="btn" value="上一页" data-control="prev" />
<input type="button" class="btn" value="下一页" data-control="next" />
</p>
</div>
<!--加载-->
<div class="loading">
<p class="progress">0%</p>
</div>
<script>
var img = document.querySelector('#img')
var p = document.querySelector('#parent')
var btn = document.querySelectorAll('.btn')
var progress = document.querySelector('.progress')
var loading = document.querySelector('.loading')
var imgs = [
"https://timgsa.baidu.com/timg?image&quality80&sizeb9999_10000&sec1536779145193&di88f99c68903b47c4e386755b73893335&imgtype0&srchttp%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1212%2F21%2Fc2%2F16781720_1356079420979.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779184701&di=f3ab80235c5ddf5adb9d6b06ce47e82c&imgtype=0&src=http%3A%2F%2Fattachments.gfan.com%2Fforum%2Fattachments2%2Fday_110730%2F110730052814920f360299a915.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779211730&di=4c244c8bd60f74b1832625e27c063fc0&imgtype=0&src=http%3A%2F%2Fi3.download.fd.pchome.net%2Ft_960x600%2Fg1%2FM00%2F09%2F12%2FoYYBAFO6NYCIE0tSAAdYOvon7RoAABtkwF4hgIAB1hS650.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779225935&di=4c13b2276bbe03877d4c5ea0cc56cc98&imgtype=0&src=http%3A%2F%2Fc15.eoemarket.net%2Fapp0%2F652%2F652549%2Fscreen%2F3260012.png",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779271901&di=3ccda1af260cf969189de3f52ea31686&imgtype=0&src=http%3A%2F%2Fpic1.ytqmx.com%3A82%2F2015%2F0526%2F14%2F02.jpg%2521720.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779311038&di=0599243d4fe87313ed37ee416cd73d6a&imgtype=0&src=http%3A%2F%2Fwww.desktx.cc%2Fd%2Ffile%2Fwallpaper%2Fscenery%2F20170105%2F2647448be73294d17c28d91407661f8c.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779320074&di=ec9d10c18c21daec3b89b5573c22ef0f&imgtype=0&src=http%3A%2F%2Fpicture.ik123.com%2Fuploads%2Fallimg%2F170320%2F3-1F320150H5.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1536779349967&di=11eaaee20a3da68abf58938bdad012e0&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2017-11-29%2F5a1e13119deee.jpg"
]
var index = 0, // 当前是哪张图片
len = imgs.length,
count = 0 // 加载了多少图片
function btnListener() { // 按钮事件监听
p.addEventListener('click', function (e) {
if (e.target.dataset.control === 'prev') {
/*index--
if (index < 0) {
index = 0
}*/
index = Math.max(0, --index)
} else {
index = Math.min(++index, len - 1)
}
document.title = (index + 1) + '/' + len; // 改变页面标题
disabled()
img.setAttribute('src', imgs[index])
})
}
function disabled() { // 按钮样式变化
if (index === 0) {
btn[0].disabled =true
btn[0].value = '没有啦'
} else if (index === len - 1) {
btn[1].disabled = true
btn[1].value = '没有啦'
} else {
btn[0].disabled = false
btn[0].value = '上一页'
btn[1].disabled = false
btn[1].value = '下一页'
}
}
function preLoad() { // 预加载
imgs.forEach(function (item, index) {
var imgObj = new Image()
imgObj.addEventListener('load', function (e) {
progress.innerHTML = Math.round((count + 1) / len * 100) + '%'
if (count >= len - 1) {
loading.style.display = 'none'
document.title = '1/' + len
}
count++
})
imgObj.src = item
})
}
window.onload = function () {
disabled()
btnListener()
preLoad()
}
</script>
</body>
</html>
文字环绕图片居左
<style>
.img-left {
border: 3px solid #005588;
width:300px;
word-wrap : break-word; /* 单词换行*/
}
.img-left img {
float:left; /* 对图片进行浮动就可以实现了 */
width:150px;
}
</style>
</head>
<body>
<div class="img-left">
<img src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png" alt="pic"/>
这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文这是一段中文
<div style="clear:both;"></div>
</div>
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<ps.length; i++) {
ps[i].onclick = function() {
console.info(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提交并刷新页面?
<form id="form">
用户名:<input type="text">
密码:<input type="password">
<button>登录</button>
<span id="result"></span>
</form>
<script>
var btn = document.querySelector('button')
btn.addEventListener('click', function (e) {
e.preventDefault()
var userName = document.querySelector('[type=text]').value
var password = document.querySelector('[type=password]').value
var xhr = null
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
} else {
xhr = new ActiveXObject()
}
xhr.open('POST', 'xxx', true) // 请求方式 地址 异步
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.onreadystatechange = function () {
if (xhr.readyState === 200 && xhr.status === 4) {
// 页面跳转
// window.location.href = 'https://mp.csdn.net/'
// 页面刷新
// window.location.reload()
}
}
})
css3实现 超出的字符为省略号
<div class="text1">热卖精选:从子频道(服饰鞋包,亲子,居家,美妆)档期里面挑选出来,库存大于30%的高信价比商品list,数量为50个</div>
<style>
.text1 {
width: 200px;
border: 1px solid #ddd;
overflow: hidden;
text-overflow: ellipsis; /* 文本超出部分省略号显示 */
white-space: nowrap; /* 设置文本不换行 */
}
</style>
location.replace/location.assign的区别?
window.location.assign(url) : 加载 URL 指定的新的 HTML 文档。 就相当于一个链接,跳转到指定的url,当前页面会转为新页面内容,可以点击后退返回上一个页面。
window.location.replace(url) : 通过加载 URL 指定的文档来替换当前文档 ,这个方法是替换当前窗口页面,前后两个页面共用一个窗口,所以是没有后退返回上一页的
请描述伪元素 (pseudo-elements) 及其用途。
伪类用于选择那些DOM树中不存在的不容易被常规选择器找到的信息 :hover :active :focus :link
伪元素用于将某些特殊效果添加到选择器上; 如::before ::after
伪元素用于表现非正文、装饰性的东西,利于HTML语义化;
请问为何要使用 translate() 而非 absolute position,或反之的理由?为什么?
从动画来讲,absolute最小动画单位是1px,而transform可以更小,使动画更平滑,
从其他角度来讲,就是absolute必须有relative的父盒子;
你能描述当你制作一个网页的工作流程吗?
内容分析:分清展现在网络中内容的层次和逻辑关系
结构设计:写出合理的html结构代码
布局设计:使用html+css进行布局
交互设计:鼠标特效
行为设计:js代码,ajax页面行为和从服务器获取数据
测试兼容性;优化性能。
DNS(域名系统)负载均衡;
在DNS中为多个IP地址配置同一个域名如:www.baidu.com,因而查询这个域名的客户机将得到其中一个地址,从而使得不同的客户访问不同的服务器,达到负载均衡的目的,从而减小服务器端的压力。DNS负载均衡是一种简单而有效的方法,但是它不能区分服务器的差异,也不能反映服务器的当前运行状态。
HTTP重定向
(通过使客户端重定向,来分散和转移请求压力,比如一些下载服务通常都有几个镜像服务器);301重定向是网址重定向最为可行的一种办法,seo最为友好。
ie6无法设置较小的高度
原因是有默认行高
解决办法: 1.overflow:hidden 2.line-height:0
强制文字换行
word-wrap: break-word
word-break: break-all
前端页面由哪几个部分组成
结构 样式 行为
以下输出结果
console.log(0 == null) // false
console.log(0 == ‘0’) // true
console.log(2 == ‘1’) // false
console.log(null instanceof Object) // false
console.log(undefined instanceof Object) // false
var a = 2
function obj() {
var a = 1
function inner() {
console.log(a)
}
inner()
}
console.log(obj()) // 1(inner内部) undefined (由于没返回值)
console.log('\n == 0') // == 0
function test() {
alert(1)
}
test()
function test() {
alert(2)
}
// 只会弹出2
console.log(0.1 + 0.2); // 不是0.3
console.log(0.1 + 0.2 == 0.3); // false
var arr1 = "john".split('');
var arr2 = arr1.reverse();
// console.log(arr1, arr2) // 都是 n h o j reverse会改变原数组
var arr4 = arr1.slice()
var arr3 = "jones".split('');
arr2.push(arr3); // 并不是拼接数组 而是将arr3作为一个元素push进去
console.log(arr1) // n h o j arr3 因为arr2是对arr1的引用 改变会相互影响
console.log(arr4) // n h o j 不会影响
console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1));
console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));
console.log(1 + "2" + "2"); // “122”
console.log(1 + +"2" + "2"); // “32”
console.log(1 + -"1" + "2"); // “02”
console.log(+"1" + "1" + "2"); // “112”
console.log( "A" - "B" + "2"); // “NaN2”
console.log( "A" - "B" + 2); // NaN
返回一个布尔值指明字符串是否为回文结构。
正序倒序都一样
function isPalindrome(str) {
str = str.replace(/W/g, '').toLowerCase();
return (str == str.split('').reverse().join(''));
}
写一个 sum方法,在使用下面任一语法调用时,都可以正常工作。
console.log(sum(2,3)); // Outputs 5
console.log(sum(2)(3)); // Outputs 5
function sum(x, y) {
if (y !== undefined) {
return x + y;
} else {
return function(y) { return x + y; };
}
}
三次握手 四次挥手
第一次握手:起初两端都处于CLOSED关闭状态,Client将标志位SYN置为1,随机产生一个值seq=x,并将该数据包发送给Server,Client进入SYN-SENT状态,等待Server确认;
第二次握手:Server收到数据包后由标志位SYN=1得知Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=x+1,随机产生一个值seq=y,并将该数据包发送给Client以确认连接请求,Server进入SYN-RCVD状态
第三次握手:Client收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并将该数据包发送给Server,Server检查ack是否为y+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client和Server就可以开始传输数据。
(1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
(2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
(3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
(4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手
为什么需要三次握手,两次不可以吗?或者四次、五次可以吗?
三次握手
假设客户端请求建立连接,发给服务器SYN包等待服务器确认,服务器收到确认后,如果是两次握手,假设服务器给客户端在第二次握手时发送数据,数据从服务器发出,服务器认为连接已经建立,但在发送数据的过程中数据丢失,客户端认为连接没有建立,会进行重传。假设每次发送的数据一直在丢失,客户端一直SYN,服务器就会产生多个无效连接,占用资源
四次挥手过程(关闭客户端到服务器的连接)
客户端发送FIN后,进入终止等待状态,服务器收到客户端连接释放报文段后,就立即给客户端发送确认,服务器就进入CLOSE_WAIT状态,此时TCP服务器进程就通知高层应用进程,因而从客户端到服务器的连接就释放了。此时是“半关闭状态”,即客户端不可以发送给服务器,服务器可以发送给客户端。
此时,如果服务器没有数据报发送给客户端,其应用程序就通知TCP释放连接,然后发送给客户端连接释放数据报,并等待确认。客户端发送确认后,进入TIME_WAIT状态,但是此时TCP连接还没有释放,然后经过等待计时器设置的时间后,才进入到CLOSE状态。
URG 紧急指针是否有效。为1,表示某一位需要被优先处理。
ACK 确认号是否有效,一般置为1。
PSH 提示接收端应用程序立即从TCP缓冲区把数据读走。
RST 对方要求重新建立连接,复位。
SYN 请求建立连接,并在其序列号的字段进行序列号的初始值设定。建立连接,设置为1.
FIN 希望断开连接。
序列号seq
占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据字节都编上一个序号,第一个字节的编号由本地随机产生,给字节编上序号后,就给每一个报文段指派一个序号,序列号seq就是这个报文段中的第一个字节的数据编号。
-
确认号ack
占4个字节,期待收到对方下一个报文段的第一个数据字节的序号,序列号表示报文段携带数据的第一个字节的编号,而确认号指的是期望接受到下一个字节的编号,因此挡墙报文段最后一个字节的编号+1即是确认号。 -
确认ACK
占1个比特位,仅当ACK=1,确认号字段才有效。ACK=0,确认号无效。 -
同步SYN
连接建立时用于同步序号。当SYN=1,ACK=0表示:这是一个连接请求报文段。若同意连接,则在响应报文段中使用SYN=1,ACK=1.因此,SYN=1表示这是一个连接请求,或连接接收报文,SYN这个标志位只有在TCP建立连接才会被置为1,握手完成后SYN标志位被置为0. -
终止FIN
用来释放一个
tcp/ip
TCP/IP协议族是一个四层协议系统,自底而上分别是数据链路层、网络层、传输层和应用层
数据链路层
数据链路层两个常用的协议时ARP(地址解析协议)和RARP(逆地址解析协议)
ARP协议的用途
网络层使用IP地址寻址一台机器,而数据链路层使用物理地址寻址一台机器,因此网络层必须先将目标机器的IP地址转换为其物理地址,
RARP
RARP协议仅用于网络上的某些无盘工作站(没有硬盘)。因缺乏存储设备,
无盘工作站无法记住自己的IP地址,但他们可以利用网卡上的物理地址来向网络管理者(服务器或网络管理软件)查询自身的IP地址。
网络层
网络层实现数据包的选路和转发。WAN(广域网)通常使用众多分级的路由器来连接分散的主机或LAN(局域网),因此,
通讯的两台主机一般不是直接相连的,而是通过多个中间节点(路由器)连接的。网络层的任务就是选择这些中间节点,
确定两台主机之间的通讯路径
传输层
传输层为两台主机上的应用程序提供端到端(end to end)的通信
传输层只关心通信的起始端和目的端,而不在乎数据包的中转过程。
传输层协议主要有三个:TCP 协议、UDP协议、SCTP协议。
应用层
数据链路层、网络层、传输层负责处理网络通信细节,这部分必须既稳定又高效,因此它们都在内核空间中实现。而应用层则在用户空间中实现, 负责数据的展示和获取。
js如何实现一个栈。
主要就是数组的尾部操作增加、删除。
对jquery的了解
jquery是一款轻量级js框架,极大简化了js编程
1.提供了许多选择器
基本选择器: #id .class tagname
层级选择器 + > ~
过滤选择器 [type=xxx] …
表单选择器 $(":input") $(":text") $(":password")
2.对css提供了操作 例如 addclass…
3.对dom操作的封装
4.jquery解决了浏览器兼容的一些问题
5.jquery对事件处理,除了静态绑定事件(原本就存在的节点),还可以动态绑定事件(动态创建的元素绑定事件 通过on)
6.简化了ajax的写法
7.内置了一些简单的动画效果fade show hide slide等等
jQuery链式调用的最大优点是什么?
答:避免频繁操作的DOM,链式调用可以实现先缓存再操作。
Ajax是什么?
答:是指一种创建交互式网页应用的网页开发技术。通过在后台与服务器进行少量数据交换,AJAX可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
封装cookie的添加,删除,查询方法cookie是存储在浏览器端的
CookieUtil={
addCookie:function(key,value,options){
var str=key+"="+escape(value);
if(options.expires){
var curr=new Date(); //options.expires的单位是小时
curr.setTime(curr.getTime()+options.expires*3600*1000);
options.expires=curr.toGMTString();
}
for(var k in options){ //有可能指定了cookie的path,cookie的domain
str+=";"+k+"="+options[k];
}
document.cookie=str;
},
queryCookie:function(key){
var cookies=document.cookie;
//获得浏览器端存储的cookie,格式是key=value;key=value;key=value
cookies+=";";
var start=cookies.indexOf(key);
if(start<=-1){ return null; } //说明不存在该cookie
var end=cookies.indexOf(";",start);
var value=cookies.slice(start+key.length+1,end);
return unescape(value);
},
deleteCookie:function(key){
var value=CookieUtil.queryCookie(key);
if(value===null){return false;}
CookieUtil.addCookie(key,value,{expires:0});//把过期时间设置为0,浏览器会马上自动帮我们删除cookie
}
}
html和xhtml有什么区别?
1.XHTML 元素必须被正确地嵌套。
2.XHTML 元素必须被关闭。
3.标签名必须用小写字母。
4.空标签也必须被关闭。
5.XHTML 文档必须拥有根元素。
Jq中如何实现多库并存?
$.noConflict();
这个函数归还$的名称控制权给另一个库- (function($){})(jQuery)
Jq如何判断元素显示隐藏?
//第一种:使用CSS属性
var display =$('#id').css('display');
if(display == 'none'){ alert("我是隐藏的!"); }
//第二种:使用jquery内置选择器
<div id="test"> <p>仅仅是测试所用</p> </div>
if($("#test").is(":hidden")){ $("#test").show(); //如果元素为隐藏,则将它显现 }else{ $("#test").hide(); //如果元素为显现,则将其隐藏 }
//第三种:jQuery判断元素是否显示 是否隐藏
var node=$('#id');
if(node.is(':hidden')){ //如果node是隐藏的则显示node元素,否则隐藏
node.show();
}else{
node.hide();
}
简述下你理解的面向对象?
把一个对象抽象成类,具体上就是把一个对象的静态特征和动态特征抽象成属性和方法封装在一个类之中,程序就是多个对象和互相之间的通信组成的.
面向对象具有封装性,继承性,多态性
封装性
隐蔽了对象内部不需要暴露的细节,只依靠接口进行通信.
继承
实例可以从父类继承属性和方法
多态
不同类产生的实例对相同的消息做出不同的反应,提高代码通用性
总之,面向对象的特性提高了大型程序的重用性和可维护性.
你对数据校验是怎么样处理的?jquery.validate?
正则表达式
后者是jqueryd 表单验证插件
在jq中 mouseover mouseenter mouseout mouseleave 和 hover有什么关联?
mouseenter与mouseover:
不论鼠标指针穿过被选中元素或其子元素,都会触发mouseover事件。
只有在鼠标指针穿过被选元素时,才会触发mouseentr事件。
mouseout与mouseleave:
不论鼠标离开被选元素还是任何子元素,都会触发mouseout事件。
只有在鼠标指针离开被选元素时,才会触发mouseleave事件。
hover:
hover是一个符合方法,相当于mouseenter+mouseleave。
如何确保ajax或连接不走缓存路径
在Ajax中使用Get请求数据不会有页面缓存的问题,而使用POST请求可是有时候页面会缓存我们提交的信息,导致我们发送的异步请求不能正确的返回我们想要的数据
$.post(url,data ,ranNum:Math.random()} ,function(data){})
ranNum : 这个是防止缓存的核心,每次发起请求都会用Math.random()方法生成一个随机的数字,这样子就会刷新url缓存
disabled readyonly?
readonly只针对input(text / password)和textarea有效,而disabled对于所有的表单元素都有效,当表单元素在使用了disabled后,当我们将表单以POST或GET的方式提交的话,这个元素的值不会被传递出去,而readonly会将该值传递出去。
函数fn1 函数fn2 函数fn3,如果想在三个函数都执行完成后执行某一个事件应该如何实现?
/1、设置事件监听。
//2、回调函数:
function fn1(){
console.log("执行fn1");
fn2();
}
function fn2(){
console.log("执行fn2");
fn3();
}
function fn3(){
console.log("执行fn3");
mou();
}
function mou(){
console.log("执行某个函数");
}
fn1();
谁是c的构造函数?
function ab() {
this.say = ""; }
ab.constructor = {} ab.name = '';
var c = new ab();
//构造函数默认指向函数本身,ab是一个类,它的构造函数是它本身,
//然后ab.constructor={};ab的构造函数就指向{}了,c是ab的实例化对象,c的构造函数就是{}
eval是做什么的?
把对应的字符串解析成JS代码并运行; 应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。
HTML 5中的DataList是什么?
有助于提供自动完成功能的文本框
svg和canvas区别
svg:绘制并记忆,SVG绘制的任意形状都可以被记住和操作,并且浏览器可以再次渲染它。
canvas绘制然后遗忘。一旦绘制完成,你就不能访问和处理
SVG绘制一个缓慢的过程,因为它需要记住坐标以便于后续操作。
canvas就快多了,它不需要记住这些东西所以Canvas用于绘制和遗忘类似动漫和游戏的场画。
冒泡排序时间复杂度,最好的情况的时间复杂度
png8和24区别
颜色总数的区别
盒模型是什么
HTML文档中的每个元素都被描绘成矩形盒子,这些矩形盒子通过一个模型来描述其占用空间,这个模型称为盒模型。盒模型通过四个边界来描述:margin(外边距),border(边框),padding(内边距),content(内容区域)。
seo优缺点
优点:
1.分离前后端关注点,前端负责view,后端负责model,各司其职;
2.服务器只接口提供数据,不用展示逻辑和页面合成,提高性能;
3.同一套后端程序代码,不用修改兼容Web界面、手机;
4.用户体验好、快,内容的改变不需要重新加载整个页面
5.可以缓存较多数据,减少服务器压力
6.单页应用像网络一样,几乎随处可以访问—不像大多数的桌面应用,用户可以通过任务网络连接和适当的浏览器访问单页应用。如今,这一名单包括智能手机、平板电脑、电视、笔记本电脑和台式计算机。
缺点:
1.SEO问题没有html抓不到什么。。。
2.刚开始的时候加载可能慢很多
3.用户操作需要写逻辑,前进、后退等;
4.页面复杂度提高很多,复杂逻辑难度成倍
为什么会出现 MVVM 呢?
由mvc演变过来
为了解决mvc的弊端
view通过事件绑定影响model
model通过数据绑定影响view
原理
Mvvm的核心是数据驱动,实际开发中,只要预先写好view和model的关系映射(viewmodel),然后以viewmodl为核心,从view出发,页面需要什么数据,就去model中设置数据源。当发生了用户事件时,view处理自己的用户接口事件,并把相关事件映射到视图模型。viewmodl通知更新model,然后刷新view。 从而实现数据双向绑定更新。
用 flex 与 grid 实现如下即可:
实现方式如下:
<html>
<head>
<style>
/* flex */
.box {
display: flex;
flex-wrap: wrap;
width: 100%;
}
.box div {
width: calc(100% / 3 - 2px);
height: 100px;
border: 1px solid black;
}
/* grid */
.box {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
width: 100%;
}
.box div {
height: 100px;
border: 1px solid black;
}
</style>
<head>
<body>
<div class="box">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<body>
</html>