前端笔试
从输入网址到显示网页的过程分析
1、应用层DNS解析域名:客户端先检查本地是否有对应的IP地址,若找到则返回响应的IP地址。若没找到则请求上级DNS服务器,直至找到或到根节点。
2、浏览器与服务器建立TCP连接(默认端口80)(详细点可以说下三次握手的过程)
3、应用层客户端发送HTTP请求。
4、服务器响应请求:查找客户端请求的资源,并返回响应报文,响应报文中包括一个重要的信息——状态码(200-300,成功;304使用缓存)。
5、服务器返回相应文件给浏览器。
6、Tcp连接释放(可以说下四次挥手的过程)。
7、浏览器对HTML文件进行**解析构建**DOM树 ,构建渲染树 ,js根据DomAPI操作执行绑定事件等,页面显示完成。
TCP
以太网协议:子网内部点对点通信
IP协议:局域网互通,路由功能
TCP协议:保证数据通信的完整性和可靠性,防止丢包
三次握手(TCP连接建立):
1.C向S发出连接请求,进入同步已发送状态,S在监听状态
2.S向C发出确认报文,进入同步接受状态
3.C向S发出确认报文,进入建立连接状态,S收到也进入建立连接状态
四次挥手(TCP连接释放)
1.C向S发出连接释放报文,进入终止等待1状态
2.S接收,S向C发出确认报文,进入关闭等待状态
3.C接收,进入终止等待2状态
4.S向C发出连接释放报文,进入最后确认状态
5.C接收,C向S发出确认报文,进入时间等待状态,等待2∗MSL时长,进入关闭状态
6.S接收,进入关闭状态
两栏分布
1、float
2、flex
3、table
Cookie的get,set,以及del
var CookieUtil={
// 获取,每个cookie都是一个名称/值对,名称/值对用“=”连接,
//如果要一次存储多个名称/值对,可以使用分“;”隔开
get:function(name){
// 在cookie的名或值中不能使用分号(;)、逗号(,)、等号(=)以及
//空格。如果想存入这些值,我们可以使用encodeURIComponent()
//函数进行编码
let cookieName=encodeURIComponent(name);
let cookieStr=document.cookie;
let arr1=cookieStr.split(";");
for(let i=0;i<arr1.length;i++){
let arr2=arr1[i].split("=");
if(arr2[0]==cookieName){
return decodeURIComponent(arr2[1]);
}
}
},
// 设置,document.cookie可以赋不同的值;如果新赋的名值对的名已经存
//在,浏览器就会认为这是一个更新操作,新值会覆盖原先的值,如果名不存
//在,则浏览器认为这是一个新增操作,就会把这个名值对写进当前文档的
//cookie里;如果要改变一个cookie的值,只需重新赋值
set:function(name,value,expires){
let cookieText=
encodeURIComponent(name)+"="+encodeURIComponent(value);
if(expires){
let odate=new Date();
odate.setDate(odate.getDate()+expires);
cookieText+=";expires="+odate.toGMTString();
}
//console.log(cookieText);
document.cookie=cookieText;
},
// 删除,直接将cookie的有效时间设置成过去即可
del:function(name){
this.set(name,"",-1);
}
}
前端存在哪些安全问题
- CSRF
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全。
1.检查报头中的Referer参数确保请求发自正确的网站(但XHR请求可调用setRequestHeader方法来修改Referer报头);
2.对于任何重要的请求都需要重新验证用户的身份;
3.创建一个唯一的令牌(Token),将其存在服务端的session中及客户端的cookie中,对任何请求,都检查二者是否一致。 - XSS漏洞:
xss表示Cross Site Scripting(跨站脚本攻击),通过构造特殊数据,在用户浏览器上执行特定脚本,从而造成危害(如以用户身份发帖、转账等)。浏览器错误的将攻击者提供的用户输入数据当做JavaScript脚本给执行了。
1.浏览器自身可以识别简单的XSS攻击字符串,从而阻止简单的XSS击。
2.从根本上说,解决办法是消除网站的XSS漏洞,防御XSS最佳的做法就是对数据进行严格的输出编码,使得攻击者提供的数据不再被浏览器认为是脚本而被误执行。
3.对于普通网民,需要注意尽量抵挡诱惑,别去点击非知名网站的链接。 - iframe风险
有些时候我们的前端页面需要用到第三方提供的页面组件,通常会以iframe的方式引入。因为iframe中的内容是由第三方来提供的,默认情况下他们不受我们的控制,若iframe中的域名因为过期而被恶意攻击者抢注,或者第三方被黑客攻破,iframe中的内容被替换掉了,从而利用用户浏览器中的安全漏洞下载安装木马、恶意勒索软件等等。
1.HTML5中,iframe有了一个叫做sandbox的安全属性,通过它可以对iframe的行为进行各种限制,充分实现“最小权限“原则。 - 点击劫持攻击
我们在通过iframe使用别人提供的内容时,我们自己的页面也可能正在被不法分子放到他们精心构造的iframe或者frame当中。受害者访问到这个页面后,肉眼看到的是其他,如果受到诱导进行了点击的话,实际上点击到的却是iframe中的我们的页面。点击劫持的危害在于,攻击利用了受害者的用户身份,在其不知情的情况下进行一些操作。如果只是迫使用户关注某个微博账号的话,看上去仿佛还可以承受,但是如果是删除某个重要文件记录,或者窃取敏感信息,那么造成的危害可就难以承受了。
1.有多种防御措施都可以防止页面遭到点击劫持攻击,例如Frame Breaking方案 - 错误的内容推断
某网站允许用户在评论里上传图片,攻击者在上传图片的时候,看似提交的是个图片文件,实则是个含有JavaScript的脚本文件。该文件逃过了文件类型校验(这涉及到了恶意文件上传这个常见安全问题,但是由于和前端相关度不高因此暂不详细介绍),在服务器里存储了下来。接下来,受害者在访问这段评论的时候,浏览器会去请求这个伪装成图片的JavaScript脚本,而此时如果浏览器错误的推断了这个响应的内容类型(MIME types),那么就会把这个图片文件当做JavaScript脚本执行,于是攻击也就成功了。后端服务器在返回的响应中设置的Content-Type Header仅仅只是给浏览器提供当前响应内容类型的建议,而浏览器有可能会自作主张的根据响应中的实际内容去推断内容的类型。
1.通过设置X-Content-Type-Options这个HTTP Header明确禁止浏览器去推断响应类型。 - 不安全的第三方依赖包
如果这些来自第三方的代码有安全漏洞,那么对应用整体的安全性依然会造成严峻的挑战。
1.使用自动化的工具检查,比如NSP(Node Security Platform),Snyk等等。 - HTTPS也存在安全隐患
为了保护信息在传输过程中不被泄露,保证传输安全,使用TLS或者通俗的讲使用HTTPS已经是当今的标准配置了。黑客可以利用SSL Stripping这种攻击手段,强制让HTTPS降级回HTTP,从而继续进行中间人攻击。问题的本质在于浏览器发出去的第一次请求就被攻击者拦截了下来并做了修改,根本不给浏览器和服务器进行HTTPS通信的机会。大致过程如下,用户在浏览器里输入URL的时候往往不是从https://开始的,而是直接从域名开始输入,随后浏览器向服务器发起HTTP通信,然而由于攻击者的存在,它把服务器端返回的跳转到HTTPS页面的响应拦截了,并且代替客户端和服务器端进行后续的通信。由于这一切都是暗中进行的,所以使用前端应用的用户对此毫无察觉。
1.使用HSTS(HTTP Strict Transport Security),它通过下面这个HTTP Header以及一个预加载的清单,来告知浏览器在和网站进行通信的时候强制性的使用HTTPS,而不是通过明文的HTTP进行通信。 - 本地存储数据泄露
在前端存储敏感、机密信息始终都是一件危险的事情,推荐的做法是尽可能不在前端存这些数据。 - 缺乏静态资源完整性校验
出于性能考虑,前端应用通常会把一些静态资源存放到CDN(Content Delivery Networks)上面,例如Javascript脚本和Stylesheet文件。这么做可以显著提高前端应用的访问速度。如果攻击者劫持了CDN,或者对CDN中的资源进行了污染,那么我们的前端应用拿到的就是有问题的JS脚本或者Stylesheet文件,使得攻击者可以肆意篡改我们的前端页面,对用户实施攻击。这种攻击方式造成的效果和XSS跨站脚本攻击有些相似,不过不同点在于攻击者是从CDN开始实施的攻击,而传统的XSS攻击则是从有用户输入的地方开始下手的。
1.使用浏览器提供的SRI(Subresource Integrity)功能。顾名思义,这里的Subresource指的就是HTML页面中通过script/link所指定的资源文件。每个资源文件都可以有一个SRI值,就像下面这样。它由两部分组成,减号(-)左侧是生成SRI值用到的哈希算法名,右侧是经过Base64编码后的该资源文件的Hash值。
跨域的实现方式
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制以下几种行为:
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送
解决方案:
1、 通过jsonp(只支持get请求t,本质通过script标签引入,callback)
2、 document.domain + iframe(不同子域框架交互,document.domain都设成相同主域名)
3、 location.hash + iframe(改变URL的hash部分来进行双向通信)
4、 window.name + iframe(windowd. name**重点内容**是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。)
5、 HTML5的postMessage(targetIframe.postMessage(message, targetOrigin))
6、 跨域资源共享(CORS)(使用自定义的HTTP头部让浏览器与服务器进行沟通,设置Access-Control-Allow-Origin,可通过Ajax进行跨域)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域(Socket.io)
方案详解1
方案详解2
jquery绑定click的方法有几种
jQuery中提供了四种事件监听方式,分别是bind、live、delegate、on,对应的解除监听的函数分别是unbind、die、undelegate、off
bind()函数只能针对已经存在的元素进行事件的设置;但是live(),on(),delegate()均支持未来新添加元素的事件设置;
bind()函数在jquery1.7版本以前比较受推崇,1.7版本出来之后,官方已经不推荐用bind(),替代函数为on(),这也是1.7版本新添加的函数,同样,可以用来代替live()函数,live()函数在1.9版本已经删除;
live()函数和delegate()函数两者类似,但是live()函数在执行速度,灵活性和CSS选择器支持方面较delegate()差些。
推荐使用on()
on()方法绑定事件可以提升效率
多个事件绑定同一个函数;多个事件绑定不同函数;绑定自定义事件;绑定多个选择器,多个事件
on()方法可以绑定动态添加到页面元素的事件
css3新特性
选择器部分
特效部分1:圆角,阴影,渐变:border-radius、box-shadow 、text-shadow、 -webkit-gradient
特效部分2:背景,边框背景: background-origin/clip/size、border-image
特效部分3: 变形:transform、translate、rotate、scale、transition-origin/property/duratio/timing-function
特效部分4:动画:animation-name/duration/timing-function/delay/iteration-count/direction
移动端适配问题
1、自动适应屏幕宽度(viewport) <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
2、使用框架搭建页面
bootstrap等
3、 宽度的严格布局书写
auto或者%
4、图片自适应
5、屏幕适配布局问题
- 响应式布局
- 伸缩布局(flex)
- rem布局(rem=document.documentElement.clientWidth*dpr/10(10是为了取整))
盒模型
在标准模型中,盒模型的宽高只是内容(content)的宽高
在IE模型中盒模型的宽高是内容(content)+填充(padding)+边框(border)的总宽高
/* 标准模型 */
box-sizing:content-box;
/*IE模型*/
box-sizing:border-box;
dom.offsetWidth/offsetHeight
边距重叠
父元素没有设置margin-top,而子元素设置了margin-top;则父元素也一起有了边距。
边距重叠解决方案(BFC)
Block Formatting Context 直译为“块级格式化上下文”
怎么取创建bfc
float属性不为none(脱离文档流)
position为absolute或fixed
display为inline-block,table-cell,table-caption,flex,inine-flex
overflow不为visible
根元素
应用场景
自适应两栏布局
清除内部浮动
防止垂直margin重叠
http1.1 和http2之间的区别
早在 HTTP 建立之初,主要就是为了将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。
HTTP1.1和HTTP1.0的一些区别
1、缓存处理,header引入了更多的缓存控制策略
2、带宽优化及网络连接的使用,支持断点续传
3、错误通知的管理,错误状态响应码
4、Host头处理,一台物理服务器上可以存在多个虚拟主机,并且它们共享一个IP地址
5、长连接,支持长连接和请求的流水线处理,在一个TCP连接上可以传送多个HTTP请求和响应,不用每次请求都要创建连接,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive
http2 和http1.1之间的区别
1、HTTP/2采用二进制格式而非文本格式
2、HTTP/2是完全多路复用的,而非有序并阻塞的——只需一个连接即可实现并行
3、使用header压缩,HTTP/2降低了开销
4、服务端推送,HTTP/2让服务器可以将响应主动“推送”到客户端缓存中
HTTP2.0的多路复用和HTTP1.X中的长连接复用有什么区别
1、HTTP1. 一次请求-响应,建立一个连接,用完关闭;每一个请求都要建立一个连接;
2、 HTTP1.1 Pipeling解决方式为,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞;
3、 HTTP2 多个请求可同时在一个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行;
HTTPS与HTTP的一些区别
1、HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。
2、HTTP协议运行在TCP之上,所有传输的内容都是明文,HTTPS运行在SSL/TLS之上,SSL/TLS运行在TCP之上,所有传输的内容都经过加密的。
3、HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、HTTPS可以有效的防止运营商劫持,解决了防劫持的一个大问题。
HTTP
HTTP(hypertext transport protocol), 即超文本传输协议.这个协议详细规定了浏览器和万维网服务器之间互相通信的规则.。
- HTTP叫超文本传输协议,基于请求/响应模式
- HTTP是无状态协议。
URL:统一资源定位符,就是一个网址:协议名://域名:端口/路径,例如:http://www.oldboy.cn:80/index.html
消息格式
首行 //请求消息和响应消息中具体格式略有区别,下面介绍
头部 //头部用来指出http消息的一些属性,它们有固定的格式
正文 //传输的实际内容
请求消息的结构
请求行 、请求头部 、请求正文
Method(方法|basic-path[?query-string](路径)|http/version(http版本)
-----------------------------------------------
Header name1 : value
...
Header nameN : value
-----------------------------------------------
-----------------------------------------------
request body(optional)
1、请求行
请求方法:GET/POST/DELETE/HEAD/PUT/OPTIONS/TRACE/CONNECT
请求路径:basic-path[?query-string]
请求url:协议://域名:端口/虚拟目录/文件部分?参数部分#锚
http://www.aspxfans.com:8080/news/index.asp
?boardID=5&ID=24618&page=1#name
2、请求头部
请求头与响应头
Accept:告诉服务器,客户端支持的数据类型。
Accept-Charset:告诉服务器,客户端采用的编码。
Accept-Encoding:告诉服务器,客户机支持的数据压缩格式。
Accept-Language:告诉服务器,客户机的语言环境。
Host:客户机通过这个头告诉服务器,想访问的主机名。
If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间。
Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的。(一般用于防盗链)
User-Agent:客户机通过这个头告诉服务器,客户机的软件环境。
Cookie:客户机通过这个头告诉服务器,可以向服务器带数据。
Connection:客户机通过这个头告诉服务器,请求完后是关闭还是保持链接。
Date:客户机通过这个头告诉服务器,客户机当前请求时间。
3、请求正文
当使用GET方法发送请求的时候,请求体是空的
响应消息的结构
响应行 、 响应头部 、 响应正文
http/version number | status code | message
-----------------------------------------------
Header name 1: value
header name 2: value
...
-----------------------------------------------
-----------------------------------------------
response body(optional)
1、响应行
版本号 :http版本目前有四个:HTTP0.9 、 HTTP1.0 、HTTP1.1 、 HTTP2
状态码 :HTTP状态码主要表示应答的状态。状态码由三位数字组成,第一个数字定义了响应的类别,后面两个数字表示该大状态的一个子状态。
1XX 提示信息类 - 表示请求已被成功接收,继续处理
2XX 响应成功类 - 表示请求已被成功接收,理解,接受
3XX 重定向类 - 要完成请求必须进行更进一步的处理
4XX 客户端错误类 - 请求有语法错误或请求无法实现
5XX 服务器端错误类 - 服务器未能实现合法的请求
200 ok:
最常见的就是成功响应状态码200了, 这表明该请求被成功地完成,
所请求的资源发送回客户端。上面打开项目主页的实例中就是200
304 not modified:
假如我们打开主页后在浏览器中刷新,就会看到响应的状态码变成了304,
这代表之前响应的html文档已经被缓存了,服务器端相同的文档没有变化,
可以继续使用缓存的文档,因此304响应没有response body部分
302 found:
重定向,新的URL会在response header中的Location中返回,浏览器将
会自动使用新的URL发出新的Request,假如我们在登录页提交登录表单发
送一个POST请求进行登录,就会得到一个302响应并且重定向到/index路
径下
404 not found:
请求资源不存在(输错了URL,或者服务器端现在没有这个页面了)
500 Internal Server Error:
服务器发生了不可预期的错误,这个一般在会在服务器的程序码出错时发生
状态文本
2、响应头部
请求头与响应头
Location:这个头配合302状态码使用,告诉用户端找谁。
Server:服务器通过这个头,告诉浏览器服务器的类型。
Content-Encoding:服务器通过这个头,告诉浏览器数据采用的压缩格式。
Content-Length:服务器通过这个头,告诉浏览器回送数据的长度。
Content-Language:服务器通过这个头,告诉服务器的语言环境。
Content-Type:服务器通过这个头,回送数据的类型
Last-Modified:服务器通过这个头,告诉浏览器当前资源的缓存时间。
Refresh:服务器通过这个头,告诉浏览器隔多长时间刷新一次。
Content-Disposition:服务器通过这个头,告诉浏览器以下载的方式打开数据。
Transfer-Encoding:服务器通过这个头,告诉浏览器数据的传送格式。
ETag:与缓存相关的头。
Expires:服务器通过这个头,告诉浏览器把回送的数据缓存多长时间。-1或0不缓存。
Cache-Control和Pragma:服务器通过这个头,也可以控制浏览器不缓存数据。
Connection:服务器通过这个头,响应完是保持链接还是关闭链接。
Date:告诉客户机,返回响应的时间。
3、相应正文
Flex布局是什么
Flex是Flexible Box的缩写,意为”弹性布局“,用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为Flex布局。Webkit内核的浏览器,必须加上-webkit前缀。子元素的float、clear和vertical-align属性将失效。采用Flex布局的元素,称为Flex容器(flex container),简称”容器”。它的所有子元素自动成为容器成员,称为Flex项目(flex item),简称”项目”。
容器
- flex-direction
- flex-wrap
- flex-flow
- justify-content
- align-items
- align-content
项目
- order
- flex-grow
- flex-shrink
- flex-basis
- flex
- align-self
柯里化
柯里化是指将使用多个参数的函数转换成一系列使用一个参数的函数的技术。
柯里化的用途主要
- 延迟计算。
- 参数复用。当在多次调用同一个函数,并且传递的参数绝大多数是相同的,那么该函数可能是一个很好的柯里化候选。
- 动态创建函数。这可以是在部分计算出结果后,在此基础上动态生成新的函数处理后面的业务,这样省略了重复计算。或者可以通过将要传入调用函数的参数子集,部分应用到函数中,从而动态创造出一个新函数,这个新函数保存了重复传入的参数(以后不必每次都传)
// 通用版
// 首先将参数进行分割,也就是将除了func之外的参数存进args。
// 返回的函数接受新传入的参数并与之前的参数合并,
//从而将所有的参数传入函数中,并执行真正的函数。
var curry1=function(func){
// []相当于Array,数组
// [].slice()是一个函数,返回数组某一段
// .call()是函数slice本身的方法,第一个参数是指定函数
//执行时的this指针,第二个是参数
// 所以相当于arguments.slice(1)
// arguments是传入的参数数组,但不是真正数组,需要借助数组的slice方法
var args=[].slice.call(arguments,1);
return function(){
// connect参数合并
var newArgs=args.concat([].slice.call(arguments));
// 执行
return func.apply(this,newArgs);
}
}
function add1(a,b){
return a+b;
}
var addCurry1=curry1(add1);
console.log(addCurry1(1,2));
addCurry1=curry1(add1,1,2);
console.log(addCurry1());
addCurry1=curry1(add1,1,);
console.log(addCurry1(2));
// 改进版
// 若传入的参数没有到达两个的话,就继续调用curry,继续接受参数。
//若参数到达2个了,就直接调用add函数。
var curry2=function(func,args){
var len=func.length;
args=args||[];
return function(){
var newArgs=args.concat([].slice.call(arguments));
if(newArgs.length<len){
return curry2.call(this,func,newArgs);
}else{
return func.apply(this,newArgs);
}
}
}
function add2(a,b,c){
return a+b+c;
}
var addCurry2=curry2(add2);
console.log(addCurry2(1)(2)(3));
console.log(addCurry2(1,2,3));
console.log(addCurry2(1,2)(3));
Bind函数
- 首先通过数组的原型方法把bind函数参数中除了othis对象以外的参数保存到args中,然后再讲args和调用函数传入参数列表合并,并通过调用Function.prototype.apply方法将othis绑定到调用函数的this上,并传入合并后的参数列表。
- 因为调用apply方法返回了一个新的函数对象,丢失了原函数对象的原型属性,所以还要将新的函数对象的prototype属性引用原函数对象的原型对象。
- 之所以不采用result.prototype=this.prototype这种写法,而是使用了一个中间层对象temp,是因为不想通过修改result.prototype就修改了原函数对象的原型对象。
Function.prototype.bind=function(othis){
var args=Array.prototype.slice.call(arguments,1);
var ftobind=this;
var result=function(){
return ftobind.apply(
othis,args.concat(Array.prototype.slice.call(arguments))
);
}
var temp=function(){};
temp.prototype=this.prototype;
result.prototype=new temp();
return result;
};
var A={
name:'lorogy',
print:function(title){
console.log(title+'!'+this.name);
}
};
A.print('Hello');
var func=A.print;
func('Hello');
var funcc=A.print.bind(A);
funcc('Hello');
// Hello!lorogy
// Hello!undefined
// Hello!lorogy
对象原型原型链
OOP
即Object Oriented Programming,面向对象编程,是计算机的一种编程架构,OOP的一条基本规则是,计算机程序由能够起到子程序作用的单个或对象组合而成。包含属性和方法的对象是类的实例,而JS中没有类的概念,而是直接使用对象实现编程任务。
特性:
- 封装:能够将一个实体的信息、功能、响应都装在一个单独对象中的特性;使编程过程不必拘泥于原理,而是重在实现;
- 继承:在不改变源程序的基础上进行扩充,原功能得以保存,并且子程序能对其进行扩展,避免编写重复代码,提高工作效率;
- 多态:允许将子类类型的指针赋值给父类类型的指针;原生JS是弱类型语言,没有多态概念。
构造函数
只有函数对象才有 prototype属性 。函数对象是由function创造出来的函数或者系统内置的函数对象(Function,Object,Array,String,Number)。
函数也是对象的一种,所以继承了对象原型,可以对其添加属性和方法,构造函数也是函数,所以用自定义函数的方式,并将首字母大写以明确是构造函数即可,可以用new操作符创建函数实例验证。
prototype
即原型对象,每创建一个函数都会有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
特性:让所有对象实例共享原型对象所包含的属性和方法
constructor
constructor 属性返回对创建此对象的函数对象的引用。
原型链
1. 每个对象都具有一个名为_proto_的属性;
2. 每个构造函数(构造函数标准为大写开头,如Function(),Object()等等JS中自带的构造函数,以及自己创建的)都具有一个名为prototype的方法(注意:既然是方法,那么就是一个对象(JS中函数同样是对象),所以prototype同样带有_proto_属性;
3. 每个对象的_proto_属性指向自身构造函数的prototype;
function Fun(){}
//我创造了一个函数Fn
//这个函数由Function生成(Function作为构造函数)
var fn=new Fun()
//我创建了一个函数fn
//这个函数由Fn生成(Fn作为构造函数)
console.log(fn.__proto__===Fun.prototype) //true
//fn的__proto__指向其构造函数Fun的prototype
console.log(Fun.__proto__===Function.prototype) //true
//Fun的__proto__指向其构造函数Function的prototype
console.log(Function.__proto__===Function.prototype) //true
//Function的__proto__指向其构造函数Function的prototype
//构造函数自身是一个函数,他是被自身构造的
console.log(Function.prototype.__proto__===Object.prototype) //true
//Function.prototype的__proto__指向其构造函数Object的prototype
//Function.prototype是一个对象,同样是一个方法,方法是函数,
//所以它必须有自己的构造函数也就是Object
console.log(Fun.prototype.__proto__===Object.prototype) //true
//与上条相同
//此处可以知道一点,所有构造函数的的prototype方法的__都
//指向__Object.prototype(除了....Object.prototype自身)
console.log(Object.__proto__===Function.prototype) //true
//Object作为一个构造函数(是一个函数对象!!函数对象!!),
//所以他的__proto__指向Function.prototype
console.log(Object.prototype.__proto__===null) //true
//Object.prototype作为一切的源头,他的__proto__是null
//下面是一个新的,额外的例子
var obj={}
//创建了一个obj
console.log(obj.__proto__===Object.prototype)//true
//obj作为一个直接以字面量创建的对象,所以obj__proto__直接指向了
//Object.prototype,而不需要经过Function了!!
//下面是根据原型链延伸的内容
//还有一个上文并未提到的constructor, constructor在原型链中,
//是作为对象prototypr的一个属性存在的,它指向构造函数
//(由于主要讲原型链,这个就没在意、);
console.log(obj.__proto__.__proto__===null)
//true
console.log(obj.__proto__.constructor===Object)
//true
console.log(obj.__proto__.constructor.__proto__
===Function.prototype)
//true
console.log(obj.__proto__.constructor.__proto__.
__proto__===Object.prototype)
//true
console.log(obj.__proto__.constructor.__proto__.
__proto__.__proto__===null)
//true
console.log(obj.__proto__.constructor.__proto__.
__proto__.constructor.__proto__===Function.prototype)
//true
object.hasOwnProperty(proName); //如果该属性或者方法是该 对象自身定义的而不是器原型链中定义的 则返回true;否则返回false;
object1.isPrototypeOf(object2); //判断指定对象object1是否存在于另一个对象object2的原型链中,是则返回true,否则返回false。
实例
<script>
function People(name) {
this.name = name;
this.sayName = function() {
console.log('my name is:' + this.name);
}
}
People.prototype.walk = function() {
console.log(this.name + 'is walking');
}
var p1 = new People('饥人谷');
var p2 = new People('前端');
</script>
Js继承
js继承和继承基础总结
父类代码
// 父类
function Fn(name){
this.name=name;
this.sleep=function(){
console.log(this.name+' is sleeping');
}
}
Fn.prototype.eat=function(food){
console.log(this.name+' is eating '+food);
};
1、原型链继承
// 原型链继承,父类的实例为子类的原型
function Subfn1(){}
Subfn1.prototype=new Fn();
Subfn1.prototype.name='sub1';//必须在 new fn()之后
var subfn1=new Subfn1();
console.log(subfn1.name);//sub1
subfn1.eat('1');//sub1 is eating 1
subfn1.sleep();//sub1 is sleeping
console.log(subfn1 instanceof Fn);//true
console.log(subfn1 instanceof Subfn1);//true
特点:
- 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
- 父类新增原型方法/原型属性,子类都能访问到
- 简单,易于实现
缺点:
- 要想为子类新增属性和方法,必须要在new Fn()这样的语句之后执行,不能放到构造器中
- 无法实现多继承
- 来自原型对象的引用属性是所有实例共享的
- 创建子类实例时,无法向父类构造函数传参
推荐指数:★★(3、4两大致命缺陷)
2、构造继承
// 构造继承,使用父类的构造函数来增强子类实例,
//等于是复制父类的实例属性给子类(没用到原型)
function Subfn2(name){
Fn.call(this);
this.name=name||'sub2';
}
var subfn2=new Subfn2();
console.log(subfn2.name);//sub2
//subfn2.eat('2');//subfn2.eat is not a function
subfn2.sleep();//sub2 is sleeping
console.log(subfn2 instanceof Fn);//false
console.log(subfn2 instanceof Subfn2);//true
特点:
- 解决了1中,子类实例共享父类引用属性的问题
- 创建子类实例时,可以向父类传递参数
- 可以实现多继承(call多个父类对象)
缺点:
- 实例并不是父类的实例,只是子类的实例
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
推荐指数:★★(缺点3)
3、实例继承
// 实例继承,为父类实例添加新特性,作为子类实例返回
function Subfn3(name){
var instance=new Fn();
instance.name=name||'sub3';
return instance;
}
var subfn3=new Subfn3();
console.log(subfn3.name);//sub3
subfn3.eat('3');//sub3 is eating 3
subfn3.sleep();//sub3 is sleeping
console.log(subfn3 instanceof Fn);//true
console.log(subfn3 instanceof Subfn3);//false
特点:
- 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
缺点:
- 实例是父类的实例,不是子类的实例
- 不支持多继承
推荐指数:★★
4、拷贝继承
// 拷贝继承
function Subfn4(name){
var fn=new Fn();
for(var p in fn){
Subfn4.prototype[p]=fn[p];
}
Subfn4.prototype.name=name||'sub4';
}
var subfn4=new Subfn4();
console.log(subfn4.name);//sub4
subfn4.eat('4');//sub4 is eating 4
subfn4.sleep();//sub4 is sleeping
console.log(subfn4 instanceof Fn);//false
console.log(subfn4 instanceof Subfn4);//true
特点:
- 支持多继承
缺点:
- 效率较低,内存占用高(因为要拷贝父类的属性)
- 无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)
推荐指数:★(缺点1)
5、组合继承
// 组合继承,通过调用父类构造,继承父类的属性并保留传参的优点,
//然后通过将父类实例作为子类原型,实现函数复用
function Subfn5(name){
Fn.call(this);
this.name=name||'sub5';
}
Subfn5.prototype=new Fn();
Subfn5.prototype.constructor=Subfn5;
var subfn5=new Subfn5();
console.log(subfn5.name);//sub5
subfn5.eat('5');//sub5 is eating 5
subfn5.sleep();//sub5 is sleeping
console.log(subfn5 instanceof Fn);//true
console.log(subfn5 instanceof Subfn5);//true
特点:
- 弥补了方式2的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
既是子类的实例,也是父类的实例 - 不存在引用属性共享问题
- 可传参
- 函数可复用
缺点:
- 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
推荐指数:★★★★(仅仅多消耗了一点内存)
6、寄生组合继承
// 寄生组合继承,通过寄生方式,砍掉父类的实例属性,这样,
//在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,
//避免的组合继承的缺点
function Subfn6(name){
Fn.call(this);
this.name=name||'sub6';
}
(function (){
var Super=function(){};
Super.prototype=Fn.prototype;
Subfn6.prototype=new Super();
Subfn6.prototype.constructor=Subfn6;
})();
var subfn6=new Subfn6();
console.log(subfn6.name);//sub6
subfn6.eat('6');//sub6 is eating 6
subfn6.sleep();//sub6 is sleeping
console.log(subfn6 instanceof Fn);//true
console.log(subfn6 instanceof Subfn6);//true
特点:
堪称完美
缺点:实现较为复杂
推荐指数:★★★★(实现复杂,扣掉一颗星)
浅拷贝深拷贝
浅拷贝和深拷贝都只针对于像Object, Array这样的复杂对象,
浅拷贝:浅拷贝是拷贝引用,拷贝后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响
深拷贝:在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响
// 浅拷贝
// 浅拷贝
let obj = {
nNum : 1,
sName : 'aaron'
};
function shallowCopy(o) {
let result = {};
for(let item in o) {
if(o.hasOwnProperty(item)) {
result[item] = o[item];
};
};
return result;
};
console.log(shallowCopy(obj));//{ nNum: 1, sName: 'aaron' }
// $.extend({} , obj);//jquery
console.log(Object.assign({} , obj));//es6
// 深拷贝
obj = {
nNum : 1,
oAar : [1,2,3,4]
};
let newObj = shallowCopy(obj);
console.log(newObj === obj); // false
console.log(newObj.oAar === obj.oAar); // true,引用的同一地址
console.log(newObj);//{ nNum: 1, oAar: [ 1, 2, 3, 4 ] }
newObj.oAar.push(5);
console.log(obj);//{ nNum: 1, oAar: [ 1, 2, 3, 4, 5 ] }
console.log(newObj);//{ nNum: 1, oAar: [ 1, 2, 3, 4, 5 ] }
function deepCopy(o,temp){
let result=temp||{};
for(let item in o){
if((typeof o[item])==='object'&&o[item]!==null){
//typeof null==='object'
result[item]=(o[item].constructor===Array)?[]:{};
//针对数组情况,result初始化应为[]而不是{}
result[item]=deepCopy(o[item],result[item]);
}else{
result[item]=o[item];
}
}
return result;
}
newObj = deepCopy(obj);
//$.extend(true, {}, obj)//jquery
console.log(newObj === obj); // false
console.log(newObj.oAar === obj.oAar); // false
console.log(newObj);
newObj.oAar.push(6);//{ nNum: 1, oAar: [ 1, 2, 3, 4, 5 ] }
console.log(obj);//{ nNum: 1, oAar: [ 1, 2, 3, 4, 5 ] }
console.log(newObj);//{ nNum: 1, oAar: [ 1, 2, 3, 4, 5, 6 ] }
垃圾回收机制
和C#、Java一样JavaScript有自动垃圾回收机制,也就是说执行环境会负责管理代码执行过程中使用的内存,在开发过程中就无需考虑内存分配及无用内存的回收问题了。
- 标记清除:进入环境标记,离开环境,标记为离开
- 引用计数:每一个对象负责维护对象所有引用的计数值。当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减。当引用计数到零时,该对象就将释放占有的资源。
哪些常见操作会造成内存泄漏?
内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。
- 意外的全局变量引起的内存泄漏
- 闭包引起的内存泄漏
- 没有清理的DOM元素
- 被遗忘的定时器或者回调
判断类型的方法
typeof [var]
//string/number/object/function
[var] instanceof [String/Number/Array/Function/Error]
//true/false
[var].constructor==[String/Number/Array/Function/Error]
//true/false
Object.prototype.toString.call([var])==
"[object String/Number/Array/Date/Function/Error]"
//true/false
正则和字符串
[pattern].test([string]);//true/false
[pattern].exec([string]);//返回匹配数组
[string].match([pattern]);//返回匹配数组
[string].search([pattern]);//返回索引
[string].replace([pattern],[newstring]);//更改,替换
[string].split([pattern],[len]);
//返回以[pattern]为间隔的len长的数组
链式调用
return this
(function(){
function _$(eles){
this.elements=[];
for(let i=0;i<eles.length;i++){
let element=eles[i];
if(typeof element==='string'){
element=document.getElementById(element);
}
this.elements.push(element);
console.log(this.elements);
}
}
_$.prototype={
each: function(fn){
for(let i= 0;i<this.elements.length;i++){
fn.call(this,this.elements[i]);
}
return this; //在每个方法的最后return this;
},
setStyle:function(prop,val){
this.each(function(el){
el.style[prop]=val;
})
},
show:function(){
var that=this;
this.each(function(ele){
that.setStyle('display','block');
});
return this;
},
hide:function(){
var that=this;
this.each(function(ele){
that.setStyle('display','none');
});
return this;
}
}
window.$=function(){
return new _$(arguments);
}
})();
事件委托
事件委托——给父元素绑定事件,用来监听子元素的冒泡事件,并找到是哪个子元素的事件。适用于当子元素有很多,需要对子元素的时间进行监听的时候。
优点:
- 事件委托技术可以避免对每个字元素添加事件监听器,减少操作DOM节点的次数,从而减少浏览器的重绘和重排,提高代码的性能。
- 使用事件委托,只有父元素与DOM存在交互,其他的操作都是在JS虚拟内存中完成的,这样就大大提高了性能。
event.target
window.onload = function(){
var oUl = document.getElementById("ul");
oUl.onclick = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
alert(target.innerHTML);
}
}
}
CDN
CDN的全称是Content Delivery Network,即内容分发网络。其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络”边缘”,使用户可 以就近取得所需的内容,解决Internet**网络拥挤的状况,提高用户访问网站的响应速度**。从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均 等原因所造成的用户访问网站响应速度慢的问题。
css hack
由于不同厂商的流览器或某浏览器的不同版本(如IE6-IE11,Firefox/Safari/Opera/Chrome等),对CSS的支持、 解析不一样,导致在不同浏览器的环境中呈现出不一致的页面展现效果。这时,我们为了获得统一的页面效果,就需要针对不同的浏览器或不同版本写特定的CSS 样式,我们把这个针对不同的浏览器/不同版本写相应的CSS code的过程,叫做CSS hack!
分类
CSS Hack大致有3种表现形式,CSS属性前缀法、选择器前缀法以及IE条件注释法(即HTML头部引用if IE)Hack,实际项目中CSS Hack大部分是针对IE浏览器不同版本之间的表现差异而引入的。
- 属性前缀法(即类内部Hack):例如 IE6能识别下划线”“和星号” * “,IE7能识别星号” * “,但不能识别下划线”“,IE6~IE10都认识”\9”,但firefox前述三个都不能认识。
- 选择器前缀法(即选择器Hack):例如 IE6能识别html .class{},IE7能识别+html .class{}或者*:first-child+html .class{}。
- IE条件注释法(即HTML条件注释Hack): 针对所有IE(注:IE10+已经不再支持条件注释):
<!--[if IE]>IE浏览器显示的内容 <![endif]-->
,针对IE6及以下版本:<!--[if lt IE 6]>只在IE6-显示的内容 <![endif]--
>。这类Hack不仅对CSS生效,对写在判断语句里面的所有代码都会生效。
@import和link之间的区别
两者都是外部引用CSS的方式,但是存在一定的区别:
- 老祖宗的差别。link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。
- 加载顺序,link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载。
- 兼容性,llink没有兼容性问题,@import 需要在IE5以上才生效
- 引入方式,link是html标签,通过在html文件中引入,@import在css文件中引入
@import url(style.css) 和@import url(“style.css”)是最优的选择,兼容的浏览器最多。
页面重构
页面重构就是根据原有页面内容和结构的基础上,通过div+css写出符合web标准的页面结构。
具体实现要达到以下三点:
- 结构完整,可通过标准验证
- 标签语义化,结构合理
- 充分考虑到页面在站点中的“作用和重要性”,并对其进行有针对性的优化
HTML5的离线储存
使用 HTML5,通过创建 cache manifest 文件,可以轻松地创建 web 应用的离线版本。
如上面提到的HTML5的离线存储是基于一个新建的.appcache
文件的,通过这个文件上的解析清单
离线存储资源,这些资源就会像cookie一样被存储了下来。之后当网络在处于离线状态下时,浏览器会通过被离线存储的数据进行页面展示。
HTML5引入了应用程序缓存,这意味着 web 应用可进行缓存,并可在没有因特网连接时进行访问。 应用程序缓存为应用带来三个优势:
- 离线浏览 – 用户可在应用离线时使用它们
- 速度 – 已缓存资源加载得更快
- 减少服务器负载 – 浏览器将只从服务器下载更新过或更改过的资源。
跨域资源共享 CORS
CORS是一个W3C标准,全称是“跨域资源共享”(Cross-origin resource sharing)。CORS允许浏览器向跨源服务器发出XMLHttpRequest**请求,以克服AJAX只能基于同源策略的使用限制**。
CORS需要浏览器与服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求(如添加了Origin : http://localhost:63343,Access-Control-Request-Headers : accept, content-type,Access-Control-Request-Method : POST),但是用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口或者约定,就可以跨源通信。
CORS与JSONP的使用目的相同,但是比JSONP更强大。JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
Localstrage
html5新特性,本地存储,解决了cookie存储空间不足的问题(cookie中每条cookie的存储空间为4k),localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中localStorage会有所不同。
localStorage与sessionStorage的唯一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对会被清空。
if(window.localStorage){
console.log("浏览器支持localStorage");
var storage=window.localStorage;
// 三种设置方法
storage["a"]=1;
storage.b=2;
storage.setItem("c",3);
// 三种获取方法
console.log(storage["a"]);
console.log(storage.b);
console.log(storage.getItem("c"));
// 遍历获取key
for(let i=0;i<storage.length;i++){
console.log(storage.key(i));
}
// 删除一条
storage.removeItem("a");
console.log(storage);
// 删除所有
storage.clear();
console.log(storage);
// json格式处理,locaStorage是字符串类型
var data={
'd':4,
'e':5,
'f':6
};
storage.setItem('data',JSON.stringify(data));//json-->string
var sdata=storage.getItem('data');
console.log(JSON.parse(sdata));//string-->json
}else{
console.log("浏览器不支持localStorage");
}
Post Get
GET - 从指定的资源请求数据;POST - 向指定的资源提交要被处理的数据
GET 方法
请注意,查询字符串(名称/值对)是在 GET 请求的 URL 中发送的:
/test/demo_form.asp?name1=value1&name2=value2;
POST 方法
请注意,查询字符串(名称/值对)是在 POST 请求的 HTTP 消息主体中发送的:
POST /test/demo_form.asp HTTP/1.1;
Host: w3schools.com; name1=value1&name2=value2;
GET |
POST |
|
后退按钮/刷新 |
无害 |
数据会被重新提交(浏览器应该告知用户数据会被重新提交)。 |
书签 |
可收藏为书签 |
不可收藏为书签 |
缓存 |
能被缓存 |
不能缓存 |
编码类型 |
application/x-www-form-urlencoded |
application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。 |
历史 |
参数保留在浏览器历史中。 |
参数不会保存在浏览器历史中。 |
对数据长度的限制 |
是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 |
无限制。 |
对数据类型的限制 |
只允许 ASCII 字符。 |
没有限制。也允许二进制数据。 |
安全性 |
与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET ! |
POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。 |
可见性 |
数据在 URL 中对所有人都是可见的。 |
数据不会显示在 URL 中。 |
Cookie、sessionStorage 和 localStrorage
sessionStorage 和 localStorage 是HTML5 Web Storage API 提供的,可以方便的在web请求之间保存数据。有了本地数据,就可以避免数据在浏览器和服务器间不必要地来回传递。
共同点:都是保存在浏览器端,且同源的。
区别:
- cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。
- 存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
- 数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
- 作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。
- Web Storage 支持事件通知机制,可以将数据更新的通知发送给监听者。
- Web Storage 的 api 接口使用更方便。
HTML5新特性及兼容问题
新特性
- 语义化标签
- 增强型表单(类型、元素、属性)
- 视频和音频(audio、video)
- canvas绘图(js脚本绘图)
- svg绘图(xml)
- 地理定位(navigator.geolocation )
- 拖放API
- webworker(独立的不影响页面的性能的后台js脚本)
- webstorage(localstorage(离线长期储存)、sessionstorage(关闭后自动删除))
- websocket (TCP全双工通信)
兼容问题
IE8/IE7/IE6支持通过document.createElement方法产生的标签,可以利用这一特性让这些浏览器支持HTML5新标签,浏览器支持新标签后,还需要添加标签默认的样式。当然也可以直接使用成熟的框架、比如html5shim
<!--[if lt IE 9]>
<![endif]-->
简述一下你对HTML语义化的理解?
- 用正确的标签做正确的事情。
- html语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析;
- 即使在没有样式CSS情况下也以一种文档格式显示,并且是容易阅读的;
- 搜索引擎的爬虫也依赖于HTML标记来确定上下文和各个关键字的权重,利于seo;
- 使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。
label for
显示 联系:label的for与input的id要一致
隐式联系:input放在label内
input type
button submit reset checkbox radio text password email tel url file number range date datetime datetime-local month week time image hidden search color
form表单属性
属性 |
描述 |
accept-charset |
字符集,”utf-8” |
action |
提交表单的地址(URL),”[].php” |
autocomplete |
浏览器应该自动完成表单(默认:开启)。 |
enctype |
被提交数据的编码(默认:url-encoded),“application/x-www-form-urlencoded” |
method |
提交表单时所用的 HTTP 方法(默认:GET)。 |
name |
识别表单的名称(对于 DOM 使用:document.forms.name)。 |
novalidate |
浏览器不验证表单。 |
target |
规定 action 属性中地址的目标(默认:_self),”_blank” |
MVC、MVP、MVVM
MVC
Model(模型)+View(视图)+controller(控制器),主要是基于分层的目的,让彼此的职责分开。
View通过Controller来和Model联系,Controller是View和Model的协调者,View和Model不直接联系,基本联系都是单向的。
用户User通过控制器Controller来操作模板Model从而达到视图View的变化。
MVP
是从MVC模式演变而来的,都是通过Controller/Presenter负责逻辑的处理+Model提供数据+View负责显示。
在MVP中,Presenter完全把View和Model进行了分离,主要的程序逻辑在Presenter里实现。
并且,Presenter和View是没有直接关联的,是通过定义好的接口进行交互,从而使得在变更View的时候可以保持Presenter不变。
MVP模式的框架:Riot,js。
MVVM
MVVM是把MVC里的Controller和MVP里的Presenter改成了ViewModel。Model+View+ViewModel。
View的变化会自动更新到ViewModel,ViewModel的变化也会自动同步到View上显示。
这种自动同步是因为ViewModel中的属性实现了Observer,当属性变更时都能触发对应的操作。
MVVM模式的框架有:AngularJS+Vue.js
angular、vue、react
vue
不是一个框架,因为它只聚焦视图层,是一个构建数据驱动的Web界面的库
- 轻量级的框架
- 双向数据绑定
- 指令
- 插件化
与angular相比:都是双向数据绑定,但学习成本低,不够成熟
与react相比:都是组件思想,但学习成本低,不够成熟
angular
一款优秀的前端JS框架,已经被用于Google的多款产品当中
- 良好的应用程序结构
- 双向数据绑定
- 指令
- HTML模板
- 可嵌入、注入和测试
完善、强大、丰富
入门容易深入难
react
主要用于构建UI,采用特殊的JSX语法
- 声明式设计:React采用声明范式,可以轻松描述应用。
- .高效:React通过对DOM的模拟,最大限度地减少与DOM的交互。
- 灵活:React可以与已知的库或框架很好地配合。
速度快、模块化、单向数据流、兼容性、社区丰富
学习曲线陡峭
清除浮动
.clearfix::before,.clearfix::after {
content: ".";
display: block;
height: 0;
visibility: hidden;
}
.clearfix:after {clear: both;}
.clearfix {zoom: 1;}
浏览器内核
浏览器内核可以分为两部分,一部分是渲染引擎(render engineer或layout engineer);另一部分是JS引擎。
渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。
浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。
JS引擎:解析和执行javascript来实现网页的动态效果。
最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
1、Trident ([‘traɪd(ə)nt])
Trident是IE的内核,也就是国内双核浏览器的内核之一。Trident内核一直延续到IE11,IE11的后继者Edge采用了新内核EdgeHTML。
2、 Gecko ([‘gekəʊ])(开源)
Gecko是Netscape6Z开始采用的内核,是一个开源内核,后来被FF(FireFox)采用。
3、Webkit(开源)
Webkeit的鼻祖是Safari, 其前身是KDE(Linux的桌面系统)的KHTML(开源的)。Webkit也是开源的。
注意:Webkit其实包括是渲染引擎Webcore(前身是KHTML),以及JS引擎JSCore
4、Chromium(Blink,V8)(开源)
chromium fork自webkit,代码可读性和编译速度得到提升。值得一提是谷歌专门研发了自己的JS引擎——V8,极大地提高了JS的运算速度。由于chromium也是开源的,所以搜狗、QQ、360都用chromium内核。
自13年4月后,谷歌开始在Chromium项目中研发Blink渲染引擎,之前一直用的是Webkit的渲染引擎。之所以研发独立的渲染引擎,是因为苹果推出的Webkit2与chromium的设计存在冲突,影响了chromium的架构移植工作。
5、Presto ([‘prestəʊ])(已废弃)
自**Opera**7.0开始使用。13年2月后为了减少研发成本,放弃Presto,采用
chromium,之后也紧跟Blink的脚步。
- IE:Trident(IE8->IE8:Jscript->Chakra)
- Edge:EdgeHTML
- FF:Gecko
- Safari:KHTML->Webkit(WebCore+JSCore)->Webkit2
- Chrome:Webkit->Chromium(V8)->Chromium(Blink+V8)
- Opera:Presto->Chromium(V8)->Chromium(Blink+V8)
常用那几种浏览器测试?有哪些内核(Layout Engine)?
浏览器:IE,Chrome,Safar,FireFoxi,Opera。
内核:Trident,Webkit,Gecko,Presto。
线程与进程的区别
一个程序至少有一个进程,一个进程至少有一个线程。
- 进程是资源分配的最小单位,线程是程序执行的最小单位。
- 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
- 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
- 但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
JS运行机制
JavaScript 运行机制详解:再谈Event Loop
JS是单线程语言
JS需要异步
JS通过事件循环(event loop)在单线程上实现异步
console.log(1)//同步,主线
setTimeout(function(){
console.log(2)
},0)//异步,放入事件列表,0秒后推入事件队列,主线空闲
console.log(3)//同步,主线
//132
- 首先判断JS是同步还是异步,同步就进入主线程,异步就进入event table
- 异步任务在event table中注册函数,当满足触发条件后,被推入event queue
- 同步任务进入主线程后一直执行,直到主线程空闲时,才会去event queue中查看是否有可执行的异步任务,如果有就推入主线程中
setTimeout(function(){
console.log('定时器开始啦')
});//异步,事件列表,宏任务
new Promise(function(resolve){
console.log('马上执行for循环啦');
//同步,主线程,直接执行,宏任务
for(var i = 0; i < 10000; i++){
i == 99 && resolve();
}
}).then(function(){
console.log('执行then函数啦')//异步,事件列表,微任务
});
console.log('代码执行结束');//同步,主线程,直接执行,宏任务
//马上执行for循环啦 --- 代码执行结束
//--- 执行then函数啦 --- 定时器开始啦
macro-task(宏任务):包括整体代码script,setTimeout,setInterval
micro-task(微任务):Promise,process.nextTick
- 执行一个宏任务,过程中如果遇到微任务,就将其放到微任务的【事件队列】里
- 当前宏任务执行完成后,会查看微任务的【事件队列】,并将里面全部的微任务依次执行完
首先执行script下的宏任务,遇到setTimeout,将其放到宏任务的【队列】里
遇到 new Promise直接执行,打印"马上执行for循环啦"
遇到then方法,是微任务,将其放到微任务的【队列里】
打印 "代码执行结束"
本轮宏任务执行完毕,查看本轮的微任务,发现有一个then方法里的函数,
打印"执行then函数啦"
到此,本轮的event loop 全部完成。
下一轮的循环里,先执行一个宏任务,发现宏任务的【队列】里有一个
setTimeout里的函数,执行打印"定时器开始啦"
setTimeout(function(){
console.log('执行了')
},3000)
3秒后,会执行setTimeout里的那个函数,这准说法并不严谨,应该是 3秒后,setTimeout里的函数被会推入event queue,而event queue(事件队列)里的任务,只有在主线程空闲时才会执行
Css渲染机制
1、DOM:Document Object Model,浏览器将HTML解析成树形的数据结构,简称DOM。
2、CSSOM:CSS Object Model,浏览器将CSS代码解析成树形的数据结构。
3、DOM 和 CSSOM 都是以 Bytes → characters → tokens → nodes → object model.这样的方式生成最终的数据。如下图所示:
DOM树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
4、Render Tree:DOM 和 CSSOM 合并后生成 Render Tree,如下图:
Render Tree 和DOM一样,以多叉树的形式保存了每个节点的css属性、节点本身属性、以及节点的孩子节点。
浏览器渲染的整个流程
1、 首先当用户输入一个URL的时候,浏览器就会发送一个请求,请求URL对应的资源。
2、 然后浏览器的HTML解析器会将这个文件解析,并且构建成一棵DOM树。
3、 在构建DOM树的时候,遇到JS和CSS元素,HTML解析器就换将控制权转让给JS解析器或者是CSS解析器。
4、 JS解析器或者是CSS解析器解析完这个元素时候,HTML又继续解析下个元素,直到整棵DOM树构建完成。
5、 DOM树构建完之后,浏览器把DOM树中的一些不可视元素去掉,然后与CSSOM合成一棵render树。
6、 接着浏览器根据这棵render树,计算出各个节点(元素)在屏幕的位置。这个过程叫做layout,输出的是一棵layout树。
7、 最后浏览器根据这棵layout树,将页面渲染到屏幕上去。
获取url后面的参数并变为对象
// 获取URL后面的参数变为对象
(function(){
var urlToObject=function(url){
var urlObject={};
if(/\?/.test(url)){
var urlString=url.substring(url.indexOf("?")+1);
var urlArray=urlString.split("&");
for (var i = 0; i < urlArray.length; i++) {
var urlItem=urlArray[i];
var item=urlItem.split("=");
urlObject[item[0]]=item[1];
}
}
return urlObject;
}
var testUrl="http://tools.jb51.net/index.php?key0=0&key1=1"
var result=urlToObject(testUrl);
console.log(result);
})();
行内元素和块级元素的区别?行内块元素的兼容性使用?(IE8 以下)
行内元素:会在水平方向排列,不能包含块级元素,设置width无效,height无效(可以设置line-height),margin上下无效,padding上下无效。
块级元素:各占据一行,垂直方向排列。从新行开始结束接着一个断行。
兼容性:
//*zoom:1作用是 在IE下触发hasLayout
//*display:inline作用是 一旦触发了hasLayout
//设置display:inline和display:block效果相似。
display:inline-block;
*display:inline;
*zoom:1;
box-sizing常用的属性有哪些?分别有什么作用?
box-sizing: content-box|border-box|inherit;
content-box:宽度和高度分别应用到元素的内容框。在宽度和高度之外绘制元素的内边距和边框(元素默认效果)。
border-box:元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。
Doctype作用?标准模式与兼容模式各有什么区别?
告知浏览器的解析器用什么文档标准解析这个文档。DOCTYPE**不存在或格式不正确会导致文档以兼容模式**呈现。
标准模式的排版和JS运作模式都是以该浏览器支持的最高标准运行。
兼容模式中,页面以宽松的向后兼容的方式显示,模拟老式浏览器的行为以防止站点无法工作。
HTML5 为什么只需要写 ?
HTML5不基于 SGML,因此不需要对DTD进行引用,但是需要doctype来规范浏览器的行为(让浏览器按照它们应该的方式来运行)。
HTML4.01基于SGML,所以需要对DTD进行引用,才能告知浏览器文档所使用的文档类型。
介绍js的数据类型
六大数据类型
Undefined、Null、Boolean、Number、String、Object
五大基本类型
Undefined、Null、Boolean、Number、String
三大引用类型
Object、Array、Function
js有哪些内置对象?
本地对象:
Date、Number、 Boolean、String、Array、RegExp、Function、Object
内置对象:
Global、Math
null和undefined的区别?
null是一个表示”无”的对象,转为数值时为0;undefined是一个表示”无”的原始值,转为数值时为NaN。
undefined:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
null:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
new操作符具体干了什么呢?
(1)创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
(2)属性和方法被加入到 this 引用的对象中。
(3)新创建的对象由 this 所引用,并且最后隐式的返回 this 。
this对象的理解
- this总是指向函数的直接调用者(而非间接调用者);
- 如果有new关键字,this指向new出来的那个对象;
- 在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window。
JSON 的了解?
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小。
格式:采用键值对,例如:{‘age’:’12’, ‘name’:’back’}
eval是做什么的?
它的功能是把对应的字符串解析成JS代码并运行;
应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。
由JSON字符串转换为JSON对象的时候可以用eval,var obj =eval(‘(‘+ str +’)’)。
DOM怎样添加、移除、移动、复制、创建和查找节点
创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
添加、移除、替换、插入
appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子节点前插入一个新的子节点
查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
call() 和 apply() 的区别和作用?
apply()函数有两个参数:第一个参数是上下文,第二个参数是参数组成的数组。如果上下文是null,则使用全局对象代替。
如:function.apply(this,[1,2,3]);
call()的第一个参数是上下文,后续是实例传入的参数序列。
如:function.call(this,1,2,3);
如何获取UA?
User Agent是Http协议中的一部分,属于头域的组成部分,User Agent也简称UA。通俗地讲,UA是一种向访问网站提供你所使用的浏览器类型、操作系统、浏览器内核等信息的标识。通过这个标识,用户所访问的网站可以显示不同的排版,从而为用户提供更好的体验或者进行信息统计。
(function whatBrowser(){
console.log("浏览器名称:"+navigator.appName);
console.log("版本号:"+navigator.appVersion);
console.log("代码名称:"+navigator.appCodeName);
console.log("用户代理标识:"+navigator.userAgent);
})()
//判断访问终端
var browser={
versions:function(){
var u = navigator.userAgent, app = navigator.appVersion;
return {
trident: u.indexOf('Trident') > -1,
//IE内核
presto: u.indexOf('Presto') > -1,
//opera内核
webKit: u.indexOf('AppleWebKit') > -1,
//苹果、谷歌内核
gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1,
//火狐内核
mobile: !!u.match(/AppleWebKit.*Mobile.*/),
//是否为移动终端
ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),
//ios终端
android: u.indexOf('Android') > -1 || u.indexOf('Adr') > -1,
//android终端
iPhone: u.indexOf('iPhone') > -1 ,
//是否为iPhone或者QQHD浏览器
iPad: u.indexOf('iPad') > -1,
//是否iPad
webApp: u.indexOf('Safari') == -1,
//是否web应该程序,没有头部与底部
weixin: u.indexOf('MicroMessenger') > -1,
//是否微信 (2015-01-22新增)
qq: u.match(/\sQQ/i) == " qq"
//是否QQ
};
}(),
language:(navigator.browserLanguage || navigator.language)
.toLowerCase()
}
//判断是否IE内核
if(browser.versions.trident){ alert("is IE"); }
//判断是否webKit内核
if(browser.versions.webKit){ alert("is webKit"); }
//判断是否移动端
if(browser.versions.mobile||browser.versions.android
||browser.versions.ios){ alert("移动端"); }
你有哪些性能优化的方法?
(1) 减少http请求次数:CSS Sprites, JS、CSS源码压缩、图片大小控制合适;网页Gzip,CDN**托管,data缓存** ,图片服务器。
(2) 前端模板 JS+数据,减少由于HTML标签导致的带宽浪费,前端用变量保存ajax请求结果,每次操作本地变量,不用请求,减少请求次数
(3) 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能。
(4) 当需要设置的样式很多时设置className而不是直接操作style。
(5) 少用全局变量、缓存DOM节点查找的结果。减少IO读取操作。
(6) 避免使用CSS Expression(css表达式)又称Dynamic properties(动态属性)。
(7) 图片预加载,将样式表放在顶部,将脚本放在底部 加上时间戳。
什么叫优雅降级和渐进增强?
优雅降级:web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会检查以确认它们是否能正常工作。
由于IE独特的盒模型布局问题,针对不同版本的IE的hack实践过优雅降级了,为那些无法支持功能的浏览器增加候选方案,使之在旧式浏览器上以某种形式降级体验却不至于完全失效。
渐进增强:从被所有浏览器支持的基本功能开始,逐步地添加那些只有新式浏览器才支持的功能,向页面增加无害于基础浏览器的额外样式和功能的。当浏览器支持时,它们会自动地呈现出来并发挥作用。
在网页中的应该使用奇数还是偶数的字体?为什么呢?
- 比例关系
相对来说偶数字号比较容易和页面中其他部分的字号构成一个比例关系。如我使用14px的字体作为正文字号,那么其他部分的字体(如标题)就可以使用14×1.5 =21px的字体,或者在一些地方使用到了14×0.5=7px的padding或者margin,如果你是在用sass或者less编写css,这时候用处就凸显出来了。 - UI设计师的缘故
大多数设计师用的软件如ps提供的字号是偶数,自然到了 前端那边也是用的是偶数。 - 浏览器缘故
其一是低版本的浏览器ie6会把奇数字体强制转化为偶数,即13px渲染为14px。
其二是为了平分字体。偶数宽的汉字,如12px的汉子,去掉1像素的字体间距,填充了的字体像素宽度其实就是11px,这样的汉字中竖线左右是平分的,如“中”子,左右就是5px了。 - 系统差别
Windows 自带的点阵宋体(中易宋体)从 Vista 开始只提供 12、14、16 px 这三个大小的点阵,而 13、15、17 px 时用的是小一号的点阵(即每个字占的空间大了 1 px,但点阵没变),于是略显稀疏。
而在Linux和其他手持设备上,奇数偶数的渲染效果其实相差不大。
水平竖直居中
- flex
- position+transform
- position+margin
来源:CSDN
作者:lorogy
链接:https://blog.csdn.net/lorogy/article/details/80627522