试题整理
刷题错题整理:
-
setTimeout
的回调函数会在遍历结束后执行; -
static静态方法被设为只能被创建他们的构造器使用,并且不能传递给实例;
即 静态方法不能被实例调用;
-
函数名可以用点语法新增属性因为函数也是对象(除了基本类型,都是对象);
除了基本对象,所有对象都有原型;
-
不能够直接给构造函数添加属性,要通过原型结构给函数添加属性;
-
在测试相等性时,基本类型通过它们的值进行比较;对象通过它们的引用进行比较(判断是否具有对内存中相同位置的引用);
-
关闭tab标签页后,
sessionStrorage
存储的数据才会删除; -
使用var声明变量,可以使用相同的名称,变量将保存最新值;
-
如果对象有两个相同名称的键,则键会被替换掉:它仍然处于第一个键出现的位置,但是值是最后出现的那个键的值;
-
隐式字符串化:当对象的键也被设置为对象时,会字符串化一个对象,它会变成
[Object object]
; -
只有6种false值:undefined、null、NaN、0、‘’、false(注:对象是true);
-
typeOf typeOf 1 =“string”
;typeOf
检测null类型时,返回的是object
;typeOf
可以检测出的变量的基本数据类型:Number、String、Boolean、Undefined、Symbol、Object(null返回的是Object)、function -
BOM对象:Screen、Location、History、Navigator;
-
不要在块内声明一个函数,如果需要的话,就使用函数表达式;
-
stopPropagation()
阻止事件冒泡,但不会阻止定义在元素上的其他事件;stopImmediatePropagation()
彻底阻止事件,在其之后绑定在元素上的其他监听事件都不会触发; -
视口的缩放配置的目的:为了让css样式中的逻辑像素匹配手机终端的物理像素,让网页视图适合手机屏幕;
使用rem单位的目的:为了让一份代码适应大部分不同屏幕的手机;
自适应:在同一终端下,页面布局根据视口本身的变化而自动调节布局(如PC端页面变化、resize事件等);
响应式:指页面根据检测到的不同终端类型,自动调整布局;
-
执行优先级由高到低:小括号(xxx) > 属性访问. > new foo() > foo()
function getName(){
console.log(1)
}
function Foo() {
this.getName = function () {
console.log(2);
};
return this;
}
Foo.getName = function () {
console.log(3);
};
var a=new Foo.getName();//属性.的优先级高于new foo(),该行等于new (Foo.getName)();,返回3
var b=new Foo().getName();//new foo()的优先级高于foo(),该行等于(new Foo()).getName();,返回2
var c=new new Foo().getName();//new foo()优先级低于属性.,该行等于new (new Foo().getName)();,相当于new一个new foo()的getName属性函数,返回2
//再举个栗子
new Date().getTime();//===((new Date()).getTime)()
(new Date).getTime();//===((new Date()).getTime)()
new Date.getTime();//Uncaught TypeError: Date(...).getTime is not a function;===new (Date.getTime)()
1. 跨域怎么实现?jsonp的原理是什么?
跨域,指的是浏览器不能执行其他网站的脚本。浏览器执行javascript
脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。
同源策略限制内容有:
- Cookie、LocalStorage、IndexedDB 等存储性内容
- DOM 节点
- AJAX 请求发送后,结果被浏览器拦截了
解决办法:
①JSONP:注意JSONP只支持GET请求,不支持POST请求,不安全可能会遭受XSS攻击。
原理:ajax请求受同源策略影响,不允许进行跨域请求,而script标签src属性中的链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。
// index.html
function jsonp({ url, params, callback }) {
return new Promise((resolve, reject) => {
let script = document.createElement('script');
window[callback] = function(data) {
resolve(data);
document.body.removeChild(script);
}
params = { ...params, callback }; // wd=b&callback=show
let arrs = [];
for (let key in params) {
arrs.push(`${key}=${params[key]}`);
}
//创建一个<script>标签,把那个跨域的API数据接口地址,赋值给script的src,还要在这个地址中向服务器传递该函数名(可以通过问号传参: http://xxx?callback=show)
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
})
}
jsonp({
url: 'http://localhost:3000/say',
params: { wd: 'Iloveyou' },
callback: 'show'
}).then(data => {
console.log(data);
})
//上面这段代码相当于向 http://localhost:3000/say?wd=Iloveyou&callback=show 这个地址请求数据,然后后台返回 show('我不爱你'),最后会运行show()这个函数,打印出'我不爱你'
②CORS - 跨域资源共享
浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。
服务端设置响应头 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。
在发送请求时,分为两种情况,简单请求和复杂请求。
简单请求:
只要同时满足以下两大条件,就属于简单请求
条件1:使用GET、HEAD、POST方法之一;
条件2:Content-Type 的值是 text/plain、multipart/form-data、application/x-www-form-urlencoded三者之一;
复杂请求:
除了简单请求,就是复杂请求。
复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。
比如使用PUT方法进行后台请求的时候,后端需进行如下配置
// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// OPTIONS请求不做任何处理
if (req.method === 'OPTIONS') {
res.end()
}
// 定义后台返回的内容
app.put('/getData', function(req, res) {
console.log(req.headers)
res.end('我不爱你')
})
③postMessage
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
- 页面和其打开的新窗口的数据传递
- 多窗口之间消息传递
- 页面与嵌套的iframe消息传递
- 上面三个场景的跨域数据传递
postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。
otherWindow.postMessage(message, targetOrigin, [transfer]);
参数解释:
message: 将要发送到其他 window的数据。
targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串”*“(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。
transfer(可选):是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
④websocket协议
Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。
原生WebSocket API使用起来不太方便,我们使用Socket.io
,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
//本地文件socket.html向localhost:3000发生数据和接受数据
// socket.html
<script>
let socket = new WebSocket('ws://localhost:3000');
socket.onopen = function () {
socket.send('我爱你');//向服务器发送数据
}
socket.onmessage = function (e) {
console.log(e.data);//接收服务器返回的数据
}
</script>
// server.js
let express = require('express');
let app = express();
let WebSocket = require('ws');//记得安装ws
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
ws.on('message', function (data) {
console.log(data);
ws.send('我不爱你')
});
})
⑤Node中间件代理(两次跨域)
实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。 代理服务器,需要做以下几个步骤:
- 接受客户端请求 。
- 将请求 转发给服务器。
- 拿到服务器 响应 数据。
- 将 响应 转发给客户端。
//本地文件index.html文件,通过代理服务器http://localhost:3000向目标服务器http://localhost:4000请求数据。
// index.html(http://127.0.0.1:5500)
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$.ajax({
url: 'http://localhost:3000',
type: 'post',
data: { name: 'xiamen', password: '123456' },
contentType: 'application/json;charset=utf-8',
success: function(result) {
console.log(result) // {"title":"fontend","password":"123456"}
},
error: function(msg) {
console.log(msg)
}
})
</script>
// server1.js 代理服务器(http://localhost:3000)
const http = require('http')
// 第一步:接受客户端请求
const server = http.createServer((request, response) => {
// 代理服务器,直接和浏览器直接交互,需要设置CORS 的首部字段
response.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': 'Content-Type'
})
// 第二步:将请求转发给服务器
const proxyRequest = http
.request(
{
host: '127.0.0.1',
port: 4000,
url: '/',
method: request.method,
headers: request.headers
},
serverResponse => {
// 第三步:收到服务器的响应
var body = ''
serverResponse.on('data', chunk => {
body += chunk
})
serverResponse.on('end', () => {
console.log('The data is ' + body)
// 第四步:将响应结果转发给浏览器
response.end(body)
})
}
)
.end()
})
server.listen(3000, () => {
console.log('The proxyServer is running at http://localhost:3000')
})
// server2.js(http://localhost:4000)
const http = require('http')
const data = { title: 'fontend', password: '123456' }
const server = http.createServer((request, response) => {
if (request.url === '/') {
response.end(JSON.stringify(data))
}
})
server.listen(4000, () => {
console.log('The server is running at http://localhost:4000')
})
⑥nginx反向代理
实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。
使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
// proxy服务器
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm;
# 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
}
}
⑦window.name + iframe
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
//其中a.html和b.html是同域的,都是http://localhost:3000;而c.html是http://localhost:4000
<iframe src="http://localhost:4000/c.html" frameborder="0" onload="load()" id="iframe"></iframe>
<script>
let first = true
// onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
function load() {
if(first){
// 第1次onload(跨域页)成功后,切换到同域代理页面
let iframe = document.getElementById('iframe');
iframe.src = 'http://localhost:3000/b.html';
first = false;
}else{
// 第2次onload(同域b.html页)成功后,读取同域window.name中数据
console.log(iframe.contentWindow.name);
}
}
</script>
#b.html为中间代理页,与a.html同域,内容为空。
// c.html(http://localhost:4000/c.html)
<script>
window.name = '我不爱你'
</script>
总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
⑧location.hash + iframe
实现原理: a.html欲与c.html跨域相互通信,通过中间页b.html来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
具体实现步骤:一开始a.html给c.html传一个hash值,然后c.html收到hash值后,再把hash值传递给b.html,最后b.html将结果放到a.html的hash值中。 同样的,a.html和b.html是同域的,都是http://localhost:3000
;而c.html是http://localhost:4000
// a.html
<iframe src="http://localhost:4000/c.html#iloveyou"></iframe>
<script>
window.onhashchange = function () { //检测hash的变化
console.log(location.hash);
}
</script>
// b.html
<script>
window.parent.parent.location.hash = location.hash
//b.html将结果放到a.html的hash值中,b.html可通过parent.parent访问a.html页面
</script>
// c.html
console.log(location.hash);
let iframe = document.createElement('iframe');
iframe.src = 'http://localhost:3000/b.html#idontloveyou';
document.body.appendChild(iframe);
⑨document.domain + iframe
该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。只需要给页面添加 document.domain ='test.com'
表示二级域名都相同就可以实现跨域。
实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
//页面a.zf1.cn:3000/a.html获取页面b.zf1.cn:3000/b.html中a的值
// a.html
<body>
helloa
<iframe src="http://b.zf1.cn:3000/b.html" frameborder="0" onload="load()" id="frame"></iframe>
<script>
document.domain = 'zf1.cn';
function load() {
console.log(frame.contentWindow.a);
}
</script>
</body>
// b.html
<body>
hellob
<script>
document.domain = 'zf1.cn';
var a = 100;
</script>
</body>
总结:
CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案;
JSONP只支持GET请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
不管是Node中间件代理还是nginx反向代理,主要是通过 同源策略对服务器不加限制。
注:日常工作中,用得比较多的跨域方案是 cors 和nginx反向代理
浏览器中跨域创建cookie的问题
问题描述:当提交一个请求到www.b.com这个域时,后台尝试在响应中绑定cookie信息,以告知浏览器去保存这个cookie,但是默认情况下,浏览器是不会去为你创建cookie的,具体现象就是你发现在响应中已经有set-cookie的响应头了并且有值,而且浏览器也会有信息显示已接收到cookie了,但是就是在cookie中找不到。没错,该现象就是因为你是跨域提交的创建cookie的请求。ajax发送跨域请求的时候默认是不会携带cookie的。
解决方案:前台要配置一个ajax参数:xhrFields:{withCredentials:true},后台要在响应头中绑定”Access-Control-ALLOW-Credentials”,值为”true”
前台要配置一个ajax参数,使用到一个xmlHttpRequest对象的属性xhrFields
,该属性是一个用来配置xhr对象的键值对,比如在跨域请求有需要的时候设置withCredentials:true
;
该属性是告诉浏览器,1、允许创建来自不同域的cookie信息;2、每次的跨域请求都允许带上该cookie信息
该配置项还需要后台的允许才有效,后台如果允许浏览器发送带凭据的请求,那么会在响应头中带上"Access-Control-ALLOW-Credentials"
,值为”true”。
2. 有哪几种存储方式?有什么不同?
cookie
、localStorage
、sessionStorage
;
相同点:都保存在浏览器端;
不同点:
①传递方式不同
cookie
数据始终在同源的http请求中携带(即使不需要),即cookie
在浏览器和服务器间来回传递。
sessionStorage
和localStorage
不会自动把数据发给服务器,仅在本地保存。
②数据大小不同
(cookie
数据还有路径(path)的概念,可以限制cookie只属于某个路径下。)
存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie
,所以cookie只适合保存很小的数据,如会话标识。
sessionStorage
和localStorage
虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
③数据有效期不同
sessionStorage
:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;
localStorage
:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
cookie
只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
④作用域不同
sessionStorage
不在不同的浏览器窗口中共享,即使是同一个页面;
localStorage
在所有同源窗口中都是共享的;
cookie
也是在所有同源窗口中都是共享的。
3.点击按钮进行数据请求,怎么实现按序执行请求?
问:点击页面上一个按钮发送两个ajax请求,其中一个请求会不会等待另一个请求执行完毕之后再执行?
答:不会,这两个异步请求会同时发送,执行的快与慢是看响应的数据量的大小及后台逻辑的复杂程度。
问:怎么让它们按序执行?
答:两种方案:
- Ajax2()方法的执行放到Ajax1()的success回调函数的最后一行。
- Ajax1()的异步请求方法中,增加一个回调函数 :complete : Ajax2
4. jQuery和Vue使用起来有什么区别?
从jquery到vue或者说是到mvvm的转变则是一个思想想的转变,是将原有的直接操作dom的思想转变到操作数据上去。
从技术角度讲,Vue.js 专注于 MVVM 模型的 ViewModel 层。它通过双向数据绑定把 View 层和 Model 层连接了起来,通过对数据的操作就可以完成对页面视图的渲染。
jQuery是使用选择器($)选取DOM对象,对其进行赋值、取值、事件绑定等操作,和原生的区别只在于可以更方便的选取和操作DOM对象,其数据和界面是在一起的。
Vue则是通过Vue对象将数据和View层分离开来。对数据进行操作不再需要引用相应的DOM对象,通过Vue对象这个vm实现相互的绑定。
vue适用的场景:复杂数据操作的后台页面,表单填写页面;vue侧重数据绑定;
jquery适用的场景:比如说一些html5的动画页面,一些需要js来操作页面样式的页面;jquery侧重样式操作,动画效果等;
5.cookie和session了解吗?
cookie
和sessiom
是两种保持会话状态的方法。
cookie就是指客户端在向服务端发起请求的时候,服务端会在进行response的时候给当前客户端的一小段文本信息,并保存在当前的客户端的浏览器中,这一小段cookie文本信息也就是这个客户端去访问服务端的通行证,有了这个通行证,以后当这个客户端再去访问服务端的时候,服务端便知道是谁拿着通行证去进行访问了。
session和cookie的功能类似,也是一种保持会话状态的方式,在用户使用浏览器发起会话时,服务器会为每一个用户浏览器提供一个单独的session对象来保存用户的数据,并将它保存在服务端,而当用户访问其他web资源的时候,则可以从保存用户数据的session对象中把用户数据抽取出来并进行访问。
区别:
- cookie的用户数据是保存在用户浏览器的cookie中的;
session的用户数据是保存在服务器为用户浏览器单独创建的session对象中的。
-
数据的读取和调用,cookie可以采用request.getCookies这种方法;
session则可以用request.Session的方法。
-
安全性,cookie是存储在用户浏览器中的;
而session是存储在服务器上的,所以session比cookoe要相对安全;
30. npm中的工具了解过吗?(yarn)
npm就是JavaScript的包管理工具。npm主要用来下载,安装,管理第三方模块。
创建一个包描述文件:npm init [-y]
查看包的信息 npm info <package-name>
查看包的版本信息 npm info <package-name> versions
安装指定的包:npm install <package-name>
默认会安装在当前目录下的 node_modules 目录下,如果 node_modules 不存在,则会自动创建。
本地安装包,如果包里有可执行文件,则npm会把可执行文件安装到 node_modules/.bin 目录下。
安装指定版本的包:npm install <package-name>@<version>
安装包并记录依赖,会在 package.json 中 dependencies 属性记录依赖npm install <package-name> --save
卸载包:npm uninstall <package-name>
更新包:npm update <package-name>
全局安装包,把包安装在全局目录,供所有项目使用:npm install <package-name> -g
全局安装包,如果包里有可执行文件,则npm会把可执行文件安装到 node_modules 上一级目录中。
查看全局目录:npm root -g
修改全局目录的路径:npm config set prefix "新路径"
默认情况下全局安装的包不能直接在项目中加载,如果要直接加载,需要在系统环境变量中添加一个名为 NODE_PATH 的变量,值为全局安装目录下 node_modules 位置。
查看npm配置 npm config list
7. Node.js了解吗?
根据官方文档可以知道,node就是一个给予谷歌v8引擎的一个javascript的运行时,可以理解为运行js的一个虚拟机。他使用的是一个事件驱动,非阻塞I/O模型 ,他是将js的运行环境搬到了服务器端,和客户端没有一点关系。是一个纯服务端的东西,node只是为js提供了一个平台。
node里面其实还分了两块,一是封装了v8引擎,目的是为了执行es(如定义变量,定义函数等),另外一个提供了大量的工具库,是帮助node实现各种功能的,提供了一些以前js的环境办不到的事情,比如文件操作,网络操作,操作系统的操作。
既然node是一个平台(所谓的平台就是用来运行特定语言的),也就意味着node是用来运行语言的,那么java也是语言,node能运行java吗?据nodejs创始人Ryan Dahl回忆,他最初是选择了Ruby这门语言,但是Ruby这门语言的虚拟机效率不怎么样最终放弃了,按照这种思路,貌似node将java的虚拟机集成进来应该可以运行java,但node作者最终选择了javascript。
这样js就实现了在服务端运行的可能,js运行在node平台上(分为v8部分,用来执行es,和大量的工具库组件(API)称之为libuv,提供了以前js的环境办不到的事,如文件操作,网络操作等等)。
用途:
(1)node可以接受客户端用户的所有请求,并且能够快速的给出响应,因此node可以用来做网站。
(2)node可以作为一个中间层来来分发调用数据接口,比如有一个网站数据是有java提供的,我们可以让node作为一个中间层,来接受用户的请求,然后通过node来调用java数据接口,获取到数据后直接在node层面做html的封装,然后将渲染好的页面直接给用户。为什么要这样做,直接请求java接口不行吗,这是因为node被称之为高性能的web服务器,在并发和抗压方面都比传统的平台要好很多,因此这样一包装可以极大的减轻服务器的开发。
通过上面的两点,可以总结出,node在web中要么从前端页面到后端服务全包了,一个是只做其中的一点。
一言以蔽之,node就是一个javascript的运行环境(平台),他不是一门语言,也不是javascript的框架。可以用来开发服务端应用程序,web系统。其特点是体积小,快速,高性能。
8.城市搜索和区块联动用的组件怎么实现的?
城市搜索功能是将input输入的内容,绑定到变量keyword上面,然后用watch监听这个变量,一旦变量变化,就用变量执行indexOf的方法去便利城市的name和value值,将得到的值push进入数组,然后将数组遍历显示在ul>li里面。
watch: {
keyword () {
if (this.timer) {
clearTimeout(this.timer)
}
if (!this.keyword) {
this.list = []
return
}
this.timer = setTimeout(() => {
const result = []
for (let i in this.cities) {
this.cities[i].forEach((value) => {
if (value.spell.indexOf(this.keyword) > -1 || value.name.indexOf(this.keyword) > -1) {
result.push(value)
}
})
}
this.list = result
}, 100)
}
},
<div
class="search-content"
ref="search"
v-show="keyword"
>
<ul>
<li
class="search-item border-bottom"
v-for="item of list"
:key="item.id"
@click="handleCityClick(item.name)"
>
</li>
<li class="search-item border-bottom" v-show="hasNoData">
没有找到匹配数据
</li>
</ul>
</div>
区块联动的组件
给每个字母都绑定ref,同时绑定方法,点击的时候;移动的时候,根据高度来进行区域块的联动
<template>
<ul class="list">
<li
class="item"
v-for="item of letters"
:key="item"
:ref="item"
@touchstart.prevent="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
@click="handleLetterClick"
>
</li>
</ul>
</template>
<script>
export default {
name: 'CityAlphabet',
props: {
cities: Object
},
computed: {
letters () {
const letters = []
for (let i in this.cities) {
letters.push(i)
}
return letters
}
},
data () {
return {
touchStatus: false,
startY: 0,
timer: null
}
},
updated () {
this.startY = this.$refs['A'][0].offsetTop
},
methods: {
//点击字母的时候,将点击得到的内容字母向父级传输,触发change的方法
handleLetterClick (e) {
this.$emit('change', e.target.innerText)
},
handleTouchStart () {
this.touchStatus = true
},
//手指移动的时候,节流一下,同时也是触发父级的change,将手指滑动的内容传递
handleTouchMove (e) {
if (this.touchStatus) {
if (this.timer) {
clearTimeout(this.timer)
}
this.timer = setTimeout(() => {
const touchY = e.touches[0].clientY - 79
const index = Math.floor((touchY - this.startY) / 20)
if (index >= 0 && index < this.letters.length) {
this.$emit('change', this.letters[index])
}
}, 16)
}
},
handleTouchEnd () {
this.touchStatus = false
}
}
}
</script>
10.bootstrap中的栏栅一行有12个,是怎么做到的?
总共有五个栅格等级,每个响应式分界点隔出一个等级:特小.col-
、小.col-sm-
、中 .col-md-
、大.col-lg-
、特大.col-xl-
。
使用的row行必须包裹在container
和container-fluid
下,外部容器一个是container
,一个是container-fluid
,第一个container
是固定宽度,居中在网页中间,第二个container-fluid
是百分比宽度,宽度为100%,根据情况我们可以选择不同的容器。
工作原理:
栅格系统提供了内容居中、水平填充网页内容的方法,.container
实现固定的宽度并居中呈现,.container-fluid
实现全宽度,并和其它网格实现对齐。
行(.row)是列(.col-*)的横向组合和父容器,每列都有水平的padding值,用于控制列与列之间的间隔,同时在负边距的行上抵消,从而实现列中的所有内容在视觉上是左侧对齐的体验。
.row上带有margin-left: -15px;margin-right: -15px;
属性,你可以在.row上上定义.no-gutters
属性,从而消除这个属性,使页面不会额外宽出30px,即<div class="row no-gutters"...
。
.col-*
的width
属性(即列宽)是用百分比来表现和定义的,所以它们总是流式的,其尺寸大小受父元素的定义影响。
超小屏幕(新增规格)<576px | 小屏幕 次小屏≥576px | 中等屏幕 窄屏≥768px | 大屏幕 桌面显示器≥992px | 超大桌面 大桌面显示器≥1200px | |
---|---|---|---|---|---|
container最大宽度 | None(auto) | 540px | 720px | 960px | 1140px |
类前缀 | .col- | .col-sm- | .col-md- | .col-lg- | .col-xl- |
列数 | 12列 | 12列 | 12列 | 12列 | 12列 |
Gutter width(都是每列两侧各15px) | 30px | 30px | 30px | 30px | 30px |
列间隙(都是每列两侧各15px) | 30px | 30px | 30px | 30px | 30px |
都可嵌套、可排序 |
11.轮播图实现的时候是怎么考虑的?
四种方式实现:
swiper插件实现轮播图;
JS实现轮播图;
jQuery实现轮播图;
css3实现轮播图;
// 1. 克隆元素
ul.appendChild(ul.children[0].cloneNode(true));
// 2.创建ol 和li
var ol = document.createElement("ol");//创建ol元素
scroll.appendChild(ol);// 把ol放到scroll盒子里面去
for (var i=0;i<ulList.length-1;i++) {
var li = document.createElement("li");// 创建li元素
li.innerHTML = i + 1;// 给li里面添加文字 1 2 3 4 5
ol.appendChild(li);// 将li元素添加到ol里面
}
ol.children[0].className = "current";
// ol中的第一个li背景色为purple现无缝滚动就需要多一张图片才行,即克隆第一张图片,放到最后面
//动画函数:
// 动画函数的第一个参数,代表动画对象;第二个参数代表动量
// 让图片做匀速运动,匀速动画的原理是:当前的位置 + 速度,即 offsetLeft + speed
function animate(obj,target){
// 首先清除掉定时器
clearInterval(obj.timer);
// 用来判断 是+ 还是 - 即说明向左走还是向右走
var speed = obj.offsetLeft < target ? 15 : -15;
obj.timer = setInterval(function(){
var result = target - obj.offsetLeft;//它们的差值不会超过speed
obj.style.left = obj.offsetLeft + speed + "px";
// 有可能有小数的存在,所以在这里要做个判断
if (Math.abs(result) <= Math.abs(speed)) {
clearInterval(obj.timer);
obj.style.left = target + "px";
}
},10);
}
//定时器函数:
var timer = null; // 轮播图的定时器
var key = 0; // 控制播放的张数
var circle = 0; // 控制小圆点
timer = setInterval(autoplay,1000);// 自动轮播
function autoplay(){
/*自动轮播时,要对播放的张数key进行一个判断,如果播放的张数超过ulLis.length-1,就要重头开始播放.
因为我们克隆了第一张并将其放在最后面,所以我们要从第二张图片开始播放*/
key++; // 先++
if(key > ulLis.length-1){ // 后判断
ul.style.left = 0; // 迅速调回
key = 1; // 因为第6张是第一张,所以播放的时候是从第2张开始播放
}
// 动画部分
animate(ul,-key*liWidth);
// 小圆点circle,当显示第几张图片是,对应的小圆点的颜色也发生变化
/*同理,对小圆点也要有一个判断*/
circle++;
if (circle > olLis.length-1) {
circle = 0;
}
// 小圆点颜色发生变化
for (var i = 0 ; i < olLis.length;i++) {
// 先清除掉所用的小圆点类名
olLis[i].className = "";
}
// 给当前的小圆点 添加一个类名
olLis[circle].className = "current";
}
12.前端性能优化的方法,举例说明
①内容方面
减少HTTP请求次数(使用精灵图) 减少DOM操作 减少DNS查询:当客户端DNS缓存(浏览器和操作系统)缓存为空时,DNS查找的数量与要加载的Web页面中唯一主机名的数量相同,包括页面URL、脚本、样式表、图片、Flash对象等的主机名。减少主机名的 数量就可以减少DNS查找的数量。减少唯一主机名的数量会潜在减少页面中并行下载的数量(HTTP 1.1规范建议从每个主机名并行下载两个组件,但实际上可以多个),这样减少主机名和并行下载的方案会产生矛盾,需要大家自己权衡。建议将组件放到至少两个但不多于4个主机名下,减少DNS查找的同时也允许高度并行下载。
使用Ajax 可缓存:POST的请求,是不可以在客户端缓存的,每次请求都需要发送给服务器进行处理,每次都会返回状态码200。(可以在服务器端对数据进行缓存,以便提高处理速度)。GET的请求,是可以(而且默认)在客户端进行缓存的,除非指定了不同的地址,否则同一个地址的AJAX请求,不会重复在服务器执行,而是返回304。
②css方面
把css样式HTML代码页的头部,防止白屏
从页面中分离css代码,从外部引入
压缩代码
不要使用@import
避免css表达式width: expression(func(),document.body.clientWidth > 400 ? "400px" : "auto");
③js方面
脚本放到HTML代码页底部
从页面中分离js代码,从外部引入。
压缩代码 减少对DOM的访问 移除重复的脚本
④图片方面
优化图片(少用图片用css3新特性代替,使用矢量图代替位图) 矢量图:图标字体。 位图:GIF、JPG、PNG 不要在HTML中使用缩放图片 使用恰当的图片格式 按照HTTP协议设置合理的缓存 用css或js实现预加载 WebP图片格式能给前端带来优化 WebP格式:谷歌开发一种旨在加快图片加载速度的图片格式
(function(){
try{
console.log(a);
var a="a";
console.log(a);
b();
c();
function b(){
console.log("b");
}
var c=function(){
console.log("c");
}
console.log("d")
}
})
13.SEO搜索引擎优化有哪些方法?
1.创建唯一且准确的网页标题 <title>
<title>前端搜索引擎优化的技巧</title>
2.使用 <meta>
的 keywords
元数据来提炼网页重要关键字,以及 description
元数据准确总结网页内容。
<meta name='keywords' content='SEO,title,meta,语义化,alt'>
<meta name='description' content='介绍搜索引擎优化的技巧:语义化标签、img的alt属性等。'>
3.使用语义化元素:<em>
或 <strong>
4.利用 <img>
中的alt
属性
5.设置rel='nofollow'
忽略跟踪
6.尽量让结构(HTML)、表现(CSS)及行为(JavaScript)三者分离。如果在一个 HTML 页面中,编写大量的 CSS 样式或脚本,会拖慢其加载速度,此外,如果不为 <img>
定义宽高,那么会引起页面重新渲染,同样也会影响加载速度。一旦加载超时,“蜘蛛”就会放弃爬取。如果这个 HTML 文档内容比较独特丰富(合理插入图片说明)等,会被认为质量较高符合用户需求,从而提高 SEO 的排名。
16、jQuery中绑定事件用的on和bind有什么区别?
bind(type, [data], fn)//解绑用unbind
on(type,[selector],[data],fn)//解绑用off
区别在于:是否支持selector这个参数值。
由于javascript的事件冒泡特性,如果我们在父元素上注册了一个事件处理函数,当子元素上发生这个事件的时候,父元素上的事件处理函数也会被触发。如果使用on的时候,不设置selector,那么on与bind就没有区别了。
<div id="parent">
<input type="button" value="a" id="a"/>
<input type="button" value="b" id="b"/>
</div>
/*点击a的时候触发,点击b的时候不触发*/
$("#parent").on("click","#a",function(){
alert($(this).attr("id"));
});
on()函数的参数selector就是为了在事件冒泡的时候,让父元素能够过滤掉子元素上发生的事件。如果使用了bind,那么就没有这个能力,子元素上发生的事件一定会触发父元素事件。
bind()、unbind()、on()、off()的几个通性:(这里主要写bind和unbind)
①、JQuery中事件可以重复绑定,不会覆盖
//点击button1的时候,这2个事件处理函数都会触发
$("#button1").bind("click",function(){ alert("func1");});
$("#button1").bind("click",function(){ alert("func2");});
②、使用bind一次绑定多个事件和处理函数
//多个事件需要注册相同的处理函数
$("#button1").bind("mousedown mouseup",function(){
console.log(11);
});
//如果每个事件的处理函数不同,可以用json对象
$("#button1").bind(
{
"mousedown":function(){
console.log("mousedown");
},
"mouseup":function(){
console.log("mouseup");
}
}
);
③、传递event对象和自定义参数
//如果我们指定了自定义的参数,那么JQuery会将它放在事件对象的data属性中,即通过eventObject.data就能够拿到我们传递的参数值
$("#button1").bind("click", {name:"aty"}, function(eventObject){
alert("params=" + eventObject.data.name);
});
④、事件取消的三种形式
unbind用来取消之前通过bind绑定的事件处理函数,总的来说有三种形式:取消所有事件、取消某种类型的事件、取消某种类型下的某个事件处理函数。
$("#button1").unbind()//取消button1上所有已经绑定的事件处理函数。
$("#button1").unbind("click")//只取消button1上绑定的click类型的事件处理函数。
取消某种类型下的某个事件处理函数:
/容易犯的错误写法
$("#button1").bind("click",function(eventObj){console.log("click1");});
$("#button1").bind("click",function(eventObj){console.log("click2");});
// 这种写法是错误的,虽然用的匿名函数的功能相同,但这两个函数不是同一个,它们占用的是不同的内存空间
$("#button1").unbind("click",function(eventObj){console.log("click2");});
/正确写法
$("#button1").bind("click",func1);
$("#button1").bind("click",func2);
// 这种做法不允许使用匿名函数,我们不得不暴露全局的函数,JQuery提供了事件命名空间机制
$("#button1").unbind("click",func2);
function func1(){console.log("click1");}
function func2(){console.log("click2");}
⑤、事件命名空间
事件类型后面以点语法附加一个别名,以便引用事件,如”click.a”,其中”a”就是click当前事件类型的别名,即事件命名空间。
$("#button1").bind("click.a",function(eventObj){console.log("click1");});
$("#button1").bind("click.b",function(eventObj){console.log("click2");});
// 使用命名空间,能够以一种更优雅的方式取消某种事件类型下的某个事件处理函数
$("#button1").unbind("click.a");
能够按照命名空间来取消事件$("#button1").unbind(".a");
18.事件委托是什么?
将事件的处理程序绑定给一个父级元素,当任何子节点触发了匹配的父级元素绑定的事件,即可触发父级节点的处理程序,这就是 事件委托 。
事件委托是通过事件 ”冒泡“ 来用单个父节点而非多个子节点响应 UI Events 的技巧。
优点:
- 减少事件绑定,事件委托将很多子元素的事件绑定都集中到一个通用的父元素,使得动态创建和移除的元素更加方便,对于新添加的元素也会有之前的事件,不需要考虑元素的事件绑定逻辑。假设需要对 <li> 标签进行增加,只管进行操作就行,不用增加元素的 “onclick” 事件。
- 减少事件监听使用的内存,这可能对那些经常重新加载的小页面效果不明显,但是对需要长时间运行的应用很重要。因为当元素被从 DOM 中移除之后很难追踪它对内存的使用,造成内存泄露,这是由元素的事件绑定造成的。有了事件委托,在移除子元素之后不用担心没有解除绑定事件。
那什么样的事件可以用事件委托,什么样的事件不可以用呢?
适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。值得注意的是,mouseover和mouseout虽然也有事件冒泡,但是处理它们的时候需要特别的注意,因为需要经常计算它们的位置,处理起来不太容易。
不适合的就有很多了,举个例子,mousemove,每次都要计算它的位置,非常不好把控,在不如说focus,blur之类的,本身就没用冒泡的特性,自然就不能用事件委托了。
<ul id='ul'>
<li>111111</li>
<li>222222</li>
<li>333333</li>
</ul>
<button id='button'>添加元素</button>
window.onload = function(){
let Ul = document.getElementById('ul');
let Li = oUl.getElementsByTagName('li');
let but = document.getElementById('button');
let now = 3;
// 事件源:event对象,不管在哪个事件中,只要你操作的哪个元素就是事件源
// ie:window.event.srcElement
// 标准:event.target
//Event对象提供了一个属性叫target,可以返回事件的目标节点,我们成为事件源,也就是说,target就可以表示为当前的事件操作的dom,但是不是真正操作dom,当然,这个是有兼容性的,标准浏览器用ev.target,IE浏览器用event.srcElement,此时只是获取了当前节点的位置,并不知道是什么节点名称,这里我们用nodeName来获取具体是什么标签名,这个返回的是一个大写的,我们需要转成小写再做比较(习惯问题)
oUl.onmouseover = function(e){
let ev = e || window.event;
let target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
target.style.background = 'red';
}
}
oUl.onmouseout = function(e){
let ev = e || window.event;
let target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
target.style.background = '';
}
}
but.onclick = function(){
now ++;
let newLi = document.createElement('li');
newLi.innerHTML = 111111 * now;
Ul.appendChild(newLi);
}
}
19.前端框架Vue、angular、React的优点和缺点
其实Vue.js不是一个框架,因为它只聚焦视图层,是一个构建数据驱动的Web界面的库。
Vue.js通过简单的API(应用程序编程接口)提供高效的数据绑定和灵活的组件系统。
Vue.js的特性如下:
1.轻量级的框架
2.双向数据绑定
3.指令
4.插件化
优点:
1. 简单:官方文档很清晰,比 Angular 简单易学。
2. 快速:异步批处理方式更新 DOM。
3. 组合:用解耦的、可复用的组件组合你的应用程序。
4. 紧凑:~18kb min+gzip,且无依赖。
5. 强大:表达式 & 无需声明依赖的可推导属性 (computed properties)。
6. 对模块友好:可以通过 NPM、Bower 或 Duo 安装,不强迫你所有的代码都遵循 Angular 的各种规定,使用场景更加灵活。
缺点
1. 新生儿:Vue.js是一个新的项目,没有angular那么成熟。
2. 影响度不是很大:google了一下,有关于Vue.js多样性或者说丰富性少于其他一些有名的库。
3. 不支持IE8:
angularJS是一款优秀的前端JS框架,已经被用于Google的多款产品当中。
angularJS的特性如下:
1.良好的应用程序结构
2.双向数据绑定
3.指令
4.HTML模板
5.可嵌入、注入和测试
优点:
1. 模板功能强大丰富,自带了极其丰富的angular指令。
2. 是一个比较完善的前端框架,包含服务,模板,数据双向绑定,模块化,路由,过滤器,依赖注入等所有功能;
3. 自定义指令,自定义指令后可以在项目中多次使用。
4. ng模块化比较大胆的引入了Java的一些东西(依赖注入),能够很容易的写出可复用的代码,对于敏捷开发的团队来说非常有帮助。
5. angularjs是互联网巨人谷歌开发,这也意味着他有一个坚实的基础和社区支持。
缺点:
1. angular 入门很容易 但深入后概念很多, 学习中较难理解.
2. 文档例子非常少, 官方的文档基本只写了api, 一个例子都没有, 很多时候具体怎么用都是google来的, 或直接问misko,angular的作者.
3. 对IE6/7 兼容不算特别好, 就是可以用jQuery自己手写代码解决一些.
4. 指令的应用的最佳实践教程少, angular其实很灵活, 如果不看一些作者的使用原则,很容易写出 四不像的代码, 例如js中还是像jQuery的思想有很多dom操作.
5. DI 依赖注入 如果代码压缩需要显示声明.
React主要用于构建UI。你可以在React里传递多种类型的参数,如声明代码,帮助你渲染出UI、也可以是静态的HTML DOM元素、也可以传递动态变量、甚至是可交互的应用组件。
React特性如下:
1.声明式设计:React采用声明范式,可以轻松描述应用。
2.高效:React通过对DOM的模拟,最大限度地减少与DOM的交互。
3.灵活:React可以与已知的库或框架很好地配合。
优点:
1. 速度快:在UI渲染过程中,React通过在虚拟DOM中的微操作来实现对实际DOM的局部更新。
2. 跨浏览器兼容:虚拟DOM帮助我们解决了跨浏览器问题,它为我们提供了标准化的API,甚至在IE8中都是没问题的。
3. 模块化:为你程序编写独立的模块化UI组件,这样当某个或某些组件出现问题是,可以方便地进行隔离。
4. 单向数据流:Flux是一个用于在JavaScript应用中创建单向数据层的[架构](https://link.jianshu.com/?t=http://lib.csdn.net/base/16),它随着React视图库的开发而被Facebook概念化。
5. 同构、纯粹的javascript:因为搜索引擎的爬虫程序依赖的是服务端响应而不是JavaScript的执行,预渲染你的应用有助于搜索引擎优化。
6. *兼容性好:比如使用RequireJS来加载和打包,而Browserify和Webpack适用于构建大型应用。它们使得那些艰难的任务不再让人望而生畏。
缺点:
React本身只是一个V而已,并不是一个完整的框架,所以如果是大型项目想要一套完整的框架的话,基本都需要加上ReactRouter和Flux才能写大型应用
20.前端路由有哪些
22.简单的数值运算
1+'2'+'2'="122"
1+ +'2'+'2'="32"
1+ -'1'+'2'="02"
'A'-'B'+'2'="NaN2"
'A'-'B'+2=NaN
-
Canvas绘图;
-
vue-cli如何使用json数据模拟?
-
项目中轮播图、列表、联动、递归展示使用,后台数据怎么模拟,获取的地址是怎么写的,面试官会详细听,问到代码,甚至会给出一定的意见(v-for改为数组管理),项目的难点在哪里
-
学习的方法有哪些,《js高级程序设计》中函数重载了解吗
-
eval()函数可以解释由js源代码组成的字符串吗?该函数能用调试工具进行断点调试吗?该函数是js自带的函数,会不会引起安全性问题?该函数动态解释字符串,会存在效率问题吗?
-
属性document.body.scrolWidth表示网页中滚动条的宽度吗?
-
js或DOM操作方便,浏览器兼容的注意项有哪些
-
Web前端开发常见的安全漏洞
-
轮播图的实现及后台数据抓取
-
安全性,在无法使用HTTPS的情况下,局域网如何实现防止报文攻击
-
列举常用浏览器以及说明其内核
-
可以通过什么途径查看一个网站所使用的技术
-
react的核心是什么
-
为什选择
vue+element
这样一个体系搭建系统?有什么吗优点? -
公司要求写代码,用js原生仿照发布者订阅者模式写。
-
写一个左侧导航栏,不能调试,鼠标移动底部变色,参照京东左侧导航栏
-
虚拟DOM说一下?在生命周期里的对应阶段?
-
用的前端组件是什么?
-
验证码有写过没
-
npm有学过除简单命令之外的服务构建么?
-
echarts有用过么?WebGL知道么?
-
数据结构了解多少?数据库呢?
-
es6怎么声明类?继承怎么写?提出是为了解决什么问题?
-
怎么样去查看内存、性能:性能chrome调试的时候用network的网络选项,内存不清楚
-
react用过吗?讲了一下react和vue之前,jQuery和bootstrap,问学过吗?
-
实现0.5px横线
-
盒子模型height
-
定时器一秒加一次
-
Webscoket(解决痛点)
-
Vue写插件的时候,比较核心的install方法是怎么实现的
-
我现有项目里面使用的微信开发者工具是比较原生的小程序开发方法,有没有了解过比较新的小程序写法
-
es6中Promise、async await、generator分别是怎么使用的,她给了一个场景:按序分别请求三次数据,前一次调用结束才能开始下一次,怎么写
我回答:在promise里面,await+请求方法,resolve的时候回调下一个请求
她说这种性能比较低,链式的结果就是一个常见的回调地狱
-
keep-alive标签的原理是什么?有什么功能?
-
http里面cache-control了解吗?有什么作用?
-
在页面中的动画,设置一个定时器,间隔一段时间就动一次,考虑性能,以及考虑整个页面的刷新时间,应该设置多长时间?我???不知道要问我什么,我说我平常是写死的,500ms
-
在同源的标签里面要传递数据,会用什么方法?
-
ajax的原理
-
面向对象的基本特性(3个)
-
参数系列化
-
z-index的生效前提
-
react生命周期
-
==
和===
的区别 -
null和undefined的区别
-
用typeof bar===‘objec’验证的风险
-
NaN是什么?是什么类型?验证它的函数?
-
use strict是什么?
-
什么是window对象?什么是document对象
-
替代图片有哪几种
-
MVVM的原理
-
创建一个对象有哪几种方法(字面量、构造函数、工厂模式)
-
基本数据类型和引用数据类型的区别
-
set有那些用处?
-
js中遍历对象的方法?for in能否遍历出原型对象?
-
created和mounted的区别?
-
vue中v-model的原理?说一下Object.defineProperty上的方法?
-
v-if与v-show computed与watched的区别和应用场景?
-
浏览器策略–同源策略
-
写一个函数判断一个字符串回文
-
写一个方法将多个对象合并成一个对象(大概是这个,当时我理解错了)
-
vue-router原理
-
计算机网络中,客户端发送请求到客户端可以怎么发送
-
用style和.css文件引入css样式有什么不同?分别适用于什么场景?
-
项目中的公共样式是使用提取出来的单独文件好,还是统一放在style里面好?
-
使用rem作为手机端适配单位的过程中有没有遇到什么问题?会不会出现用px更好的情况?
-
什么是http协议?
-
三次握手中,服务端在发送ACK包+SYN包时做了什么
-
线程和进程有什么区别
-
手写一个单向链表
-
vue生命周期有哪些?destroy用过吗?
-
手写代码实现一个eventbus。分别实现三种方法listen、trigger、remove
-
回流和重绘
-
XSS脚本攻击
-
input、onmousedown、onmouseup、click、onfocus之间的区别
-
fetch请求是什么
-
缓存相关Header
-
node里的事件机制
-
Promise常用API有哪些?
-
await后面跟的是什么?
-
解释一下es6的Symbol,Symbol解决了什么问题?
-
介绍一下map和set
-
defineProperty的缺陷?怎么解决这个问题?
-
three.js学得怎么样