共计 11595 个字符,预计需要花费 29 分钟才能阅读完成。
v-model 语法糖是怎么实现的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- v-model 只是语法糖而已 -->
<!-- v-model 在外部为不同的输出元素应用不同的 property 并抛出不同的事件 -->
<!-- text 和 textarea 元素应用 value property 和 input 事件 -->
<!-- checkbox 和 radio 应用 checked property 和 change 事件 -->
<!-- select 字段将 value 作为 prop 并将 change 作为事件 -->
<!-- 留神:对于须要应用输入法 (如中文、日文、韩文等) 的语言,你将会发现 v -model 不会再输入法 组合文字过程中失去更新 -->
<!-- 再一般标签上 -->
<input v-model="sth" /> // 这一行等于下一行
<input v-bind:value="sth" v-on:input="sth = $event.target.value" />
<!-- 再组件上 -->
<currency-input v-model="price"></currentcy-input>
<!-- 上行代码是上行的语法糖 <currency-input :value="price" @input="price = arguments[0]"></currency-input> -->
<!-- 子组件定义 -->
Vue.component('currency-input', {
template: `
<span>
<input
ref="input"
:value="value"
@input="$emit('input', $event.target.value)"
>
</span>
`,
props: ['value'],
})
</body>
</html>
数字证书是什么?
当初的办法也不肯定是平安的,因为没有方法确定失去的公钥就肯定是平安的公钥。可能存在一个中间人,截取了对方发给咱们的公钥,而后将他本人的公钥发送给咱们,当咱们应用他的公钥加密后发送的信息,就能够被他用本人的私钥解密。而后他伪装成咱们以同样的办法向对方发送信息,这样咱们的信息就被窃取了,然而本人还不晓得。为了解决这样的问题,能够应用数字证书。
首先应用一种 Hash 算法来对公钥和其余信息进行加密,生成一个信息摘要,而后让有公信力的认证核心(简称 CA)用它的私钥对音讯摘要加密,造成签名。最初将原始的信息和签名合在一起,称为数字证书。当接管方收到数字证书的时候,先依据原始信息应用同样的 Hash 算法生成一个摘要,而后应用公证处的公钥来对数字证书中的摘要进行解密,最初将解密的摘要和生成的摘要进行比照,就能发现失去的信息是否被更改了。
这个办法最要的是认证核心的可靠性,个别浏览器里会内置一些顶层的认证核心的证书,相当于咱们主动信赖了他们,只有这样能力保证数据的平安。
其余值到布尔类型的值的转换规则?
以下这些是假值:
• undefined
• null
• false
• +0、-0 和 NaN
• “”
假值的布尔强制类型转换后果为 false。从逻辑上说,假值列表以外的都应该是真值。
intanceof 操作符的实现原理及实现
instanceof 运算符用于判断构造函数的 prototype 属性是否呈现在对象的原型链中的任何地位。
function myInstanceof(left, right) {
// 获取对象的原型
let proto = Object.getPrototypeOf(left)
// 获取构造函数的 prototype 对象
let prototype = right.prototype;
// 判断构造函数的 prototype 对象是否在对象的原型链上
while (true) {if (!proto) return false;
if (proto === prototype) return true;
// 如果没有找到,就持续从其原型上找,Object.getPrototypeOf 办法用来获取指定对象的原型
proto = Object.getPrototypeOf(proto);
}
}
参考:前端进阶面试题具体解答
当在浏览器中输出 Google.com 并且按下回车之后产生了什么?
(1)解析 URL: 首先会对 URL 进行解析,剖析所须要应用的传输协定和申请的资源的门路。如果输出的 URL 中的协定或者主机名不非法,将会把地址栏中输出的内容传递给搜索引擎。如果没有问题,浏览器会查看 URL 中是否呈现了非法字符,如果存在非法字符,则对非法字符进行本义后再进行下一过程。
(2)缓存判断: 浏览器会判断所申请的资源是否在缓存里,如果申请的资源在缓存里并且没有生效,那么就间接应用,否则向服务器发动新的申请。
(3)DNS 解析: 下一步首先须要获取的是输出的 URL 中的域名的 IP 地址,首先会判断本地是否有该域名的 IP 地址的缓存,如果有则应用,如果没有则向本地 DNS 服务器发动申请。本地 DNS 服务器也会先查看是否存在缓存,如果没有就会先向根域名服务器发动申请,取得负责的顶级域名服务器的地址后,再向顶级域名服务器申请,而后取得负责的权威域名服务器的地址后,再向权威域名服务器发动申请,最终取得域名的 IP 地址后,本地 DNS 服务器再将这个 IP 地址返回给申请的用户。用户向本地 DNS 服务器发动申请属于递归申请,本地 DNS 服务器向各级域名服务器发动申请属于迭代申请。
(4)获取 MAC 地址: 当浏览器失去 IP 地址后,数据传输还须要晓得目标主机 MAC 地址,因为应用层下发数据给传输层,TCP 协定会指定源端口号和目标端口号,而后下发给网络层。网络层会将本机地址作为源地址,获取的 IP 地址作为目标地址。而后将下发给数据链路层,数据链路层的发送须要退出通信单方的 MAC 地址,本机的 MAC 地址作为源 MAC 地址,目标 MAC 地址须要分状况解决。通过将 IP 地址与本机的子网掩码相与,能够判断是否与申请主机在同一个子网里,如果在同一个子网里,能够应用 APR 协定获取到目标主机的 MAC 地址,如果不在一个子网里,那么申请应该转发给网关,由它代为转发,此时同样能够通过 ARP 协定来获取网关的 MAC 地址,此时目标主机的 MAC 地址应该为网关的地址。
(5)TCP 三次握手: 上面是 TCP 建设连贯的三次握手的过程,首先客户端向服务器发送一个 SYN 连贯申请报文段和一个随机序号,服务端接管到申请后向服务器端发送一个 SYN ACK 报文段,确认连贯申请,并且也向客户端发送一个随机序号。客户端接管服务器的确认应答后,进入连贯建设的状态,同时向服务器也发送一个 ACK 确认报文段,服务器端接管到确认后,也进入连贯建设状态,此时单方的连贯就建设起来了。
(6)HTTPS 握手: 如果应用的是 HTTPS 协定,在通信前还存在 TLS 的一个四次握手的过程。首先由客户端向服务器端发送应用的协定的版本号、一个随机数和能够应用的加密办法。服务器端收到后,确认加密的办法,也向客户端发送一个随机数和本人的数字证书。客户端收到后,首先查看数字证书是否无效,如果无效,则再生成一个随机数,并应用证书中的公钥对随机数加密,而后发送给服务器端,并且还会提供一个后面所有内容的 hash 值供服务器端测验。服务器端接管后,应用本人的私钥对数据解密,同时向客户端发送一个后面所有内容的 hash 值供客户端测验。这个时候单方都有了三个随机数,依照之前所约定的加密办法,应用这三个随机数生成一把秘钥,当前单方通信前,就应用这个秘钥对数据进行加密后再传输。
(7)返回数据: 当页面申请发送到服务器端后,服务器端会返回一个 html 文件作为响应,浏览器接管到响应后,开始对 html 文件进行解析,开始页面的渲染过程。
(8)页面渲染: 浏览器首先会依据 html 文件构建 DOM 树,依据解析到的 css 文件构建 CSSOM 树,如果遇到 script 标签,则判端是否含有 defer 或者 async 属性,要不然 script 的加载和执行会造成页面的渲染的阻塞。当 DOM 树和 CSSOM 树建设好后,依据它们来构建渲染树。渲染树构建好后,会依据渲染树来进行布局。布局实现后,最初应用浏览器的 UI 接口对页面进行绘制。这个时候整个页面就显示进去了。
(9)TCP 四次挥手: 最初一步是 TCP 断开连接的四次挥手过程。若客户端认为数据发送实现,则它须要向服务端发送连贯开释申请。服务端收到连贯开释申请后,会通知应用层要开释 TCP 链接。而后会发送 ACK 包,并进入 CLOSE_WAIT 状态,此时表明客户端到服务端的连贯曾经开释,不再接管客户端发的数据了。然而因为 TCP 连贯是双向的,所以服务端仍旧能够发送数据给客户端。服务端如果此时还有没发完的数据会持续发送,结束后会向客户端发送连贯开释申请,而后服务端便进入 LAST-ACK 状态。客户端收到开释申请后,向服务端发送确认应答,此时客户端进入 TIME-WAIT 状态。该状态会继续 2MSL(最大段生存期,指报文段在网络中生存的工夫,超时会被摈弃)工夫,若该时间段内没有服务端的重发申请的话,就进入 CLOSED 状态。当服务端收到确认应答后,也便进入 CLOSED 状态。
对 rest 参数的了解
扩大运算符被用在函数形参上时,它还能够把一个拆散的参数序列整合成一个数组:
function mutiple(...args) {
let result = 1;
for (var val of args) {result *= val;}
return result;
}
mutiple(1, 2, 3, 4) // 24
这里,传入 mutiple 的是四个拆散的参数,然而如果在 mutiple 函数里尝试输入 args 的值,会发现它是一个数组:
function mutiple(...args) {console.log(args)
}
mutiple(1, 2, 3, 4) // [1, 2, 3, 4]
这就是 … rest 运算符的又一层威力了,它能够把函数的多个入参收敛进一个数组里。这一点 常常用于获取函数的多余参数,或者像下面这样解决函数参数个数不确定的状况。
HTTP 和 HTTPS 协定的区别
HTTP 和 HTTPS 协定的次要区别如下:
- HTTPS 协定须要 CA 证书,费用较高;而 HTTP 协定不须要;
- HTTP 协定是超文本传输协定,信息是明文传输的,HTTPS 则是具备安全性的 SSL 加密传输协定;
- 应用不同的连贯形式,端口也不同,HTTP 协定端口是 80,HTTPS 协定端口是 443;
- HTTP 协定连贯很简略,是无状态的;HTTPS 协定是有 SSL 和 HTTP 协定构建的可进行加密传输、身份认证的网络协议,比 HTTP 更加平安。
ES6 中模板语法与字符串解决
ES6 提出了“模板语法”的概念。在 ES6 以前,拼接字符串是很麻烦的事件:
var name = 'css'
var career = 'coder'
var hobby = ['coding', 'writing']
var finalString = 'my name is' + name + ', I work as a' + career + ', I love' + hobby[0] + 'and' + hobby[1]
仅仅几个变量,写了这么多加号,还要时刻小心外面的空格和标点符号有没有跟错中央。然而有了模板字符串,拼接难度直线降落:
var name = 'css'
var career = 'coder'
var hobby = ['coding', 'writing']
var finalString = `my name is ${name}, I work as a ${career} I love ${hobby[0]} and ${hobby[1]}`
字符串不仅更容易拼了,也更易读了,代码整体的品质都变高了。这就是模板字符串的第一个劣势——容许用 ${}的形式嵌入变量。但这还不是问题的要害,模板字符串的要害劣势有两个:
- 在模板字符串中,空格、缩进、换行都会被保留
- 模板字符串齐全反对“运算”式的表达式,能够在 ${}里实现一些计算
基于第一点,能够在模板字符串里无障碍地间接写 html 代码:
let list = ` <ul> <li> 列表项 1 </li> <li> 列表项 2 </li> </ul>`;
console.log(message); // 正确输入,不存在报错
基于第二点,能够把一些简略的计算和调用丢进 ${} 来做:
function add(a, b) {const finalString = `${a} + ${b} = ${a+b}`
console.log(finalString)
}
add(1, 2) // 输入 '1 + 2 = 3'
除了模板语法外,ES6 中还新增了一系列的字符串办法用于晋升开发效率:
(1)存在性断定:在过来,当判断一个字符 / 字符串是否在某字符串中时,只能用 indexOf > -1 来做。当初 ES6 提供了三个办法:includes、startsWith、endsWith,它们都会返回一个布尔值来通知你是否存在。
- includes:判断字符串与子串的蕴含关系:
const son = 'haha'
const father = 'xixi haha hehe'
father.includes(son) // true
- startsWith:判断字符串是否以某个 / 某串字符结尾:
const father = 'xixi haha hehe'
father.startsWith('haha') // false
father.startsWith('xixi') // true
- endsWith:判断字符串是否以某个 / 某串字符结尾:
const father = 'xixi haha hehe'
father.endsWith('hehe') // true
(2)主动反复:能够应用 repeat 办法来使同一个字符串输入屡次(被间断复制屡次):
const sourceCode = 'repeat for 3 times;'
const repeated = sourceCode.repeat(3)
console.log(repeated) // repeat for 3 times;repeat for 3 times;repeat for 3 times;
常见的 HTTP 申请头和响应头
HTTP Request Header 常见的申请头:
- Accept: 浏览器可能解决的内容类型
- Accept-Charset: 浏览器可能显示的字符集
- Accept-Encoding:浏览器可能解决的压缩编码
- Accept-Language:浏览器以后设置的语言
- Connection:浏览器与服务器之间连贯的类型
- Cookie:以后页面设置的任何 Cookie
- Host:发出请求的页面所在的域
- Referer:发出请求的页面的 URL
- User-Agent:浏览器的用户代理字符串
HTTP Responses Header 常见的响应头:
- Date:示意音讯发送的工夫,工夫的形容格局由 rfc822 定义
- server: 服务器名称
- Connection:浏览器与服务器之间连贯的类型
- Cache-Control:管制 HTTP 缓存
- content-type: 示意前面的文档属于什么 MIME 类型
常见的 Content-Type 属性值有以下四种:
(1)application/x-www-form-urlencoded:浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 形式提交数据。该种形式提交的数据放在 body 外面,数据依照 key1=val1&key2=val2 的形式进行编码,key 和 val 都进行了 URL 转码。
(2)multipart/form-data:该种形式也是一个常见的 POST 提交形式,通常表单上传文件时应用该种形式。
(3)application/json:服务器音讯主体是序列化后的 JSON 字符串。
(4)text/xml:该种形式次要用来提交 XML 格局的数据。
new 操作符的实现原理
new 操作符的执行过程:
(1)首先创立了一个新的空对象
(2)设置原型,将对象的原型设置为函数的 prototype 对象。
(3)让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象增加属性)
(4)判断函数的返回值类型,如果是值类型,返回创立的对象。如果是援用类型,就返回这个援用类型的对象。
具体实现:
function objectFactory() {
let newObject = null;
let constructor = Array.prototype.shift.call(arguments);
let result = null;
// 判断参数是否是一个函数
if (typeof constructor !== "function") {console.error("type error");
return;
}
// 新建一个空对象,对象的原型为构造函数的 prototype 对象
newObject = Object.create(constructor.prototype);
// 将 this 指向新建对象,并执行函数
result = constructor.apply(newObject, arguments);
// 判断返回对象
let flag = result && (typeof result === "object" || typeof result === "function");
// 判断返回后果
return flag ? result : newObject;
}
// 应用办法
objectFactory(构造函数, 初始化参数);
margin 和 padding 的应用场景
- 须要在 border 外侧增加空白,且空白处不须要背景(色)时,应用 margin;
- 须要在 border 内测增加空白,且空白处须要背景(色)时,应用 padding。
原型链指向
p.__proto__ // Person.prototype
Person.prototype.__proto__ // Object.prototype
p.__proto__.__proto__ //Object.prototype
p.__proto__.constructor.prototype.__proto__ // Object.prototype
Person.prototype.constructor.prototype.__proto__ // Object.prototype
p1.__proto__.constructor // Person
Person.prototype.constructor // Person
什么是 margin 重叠问题?如何解决?
问题形容: 两个块级元素的上外边距和下外边距可能会合并(折叠)为一个外边距,其大小会取其中外边距值大的那个,这种行为就是外边距折叠。须要留神的是,浮动的元素和相对定位 这种脱离文档流的元素的外边距不会折叠。重叠只会呈现在 垂直方向。
计算准则: 折叠合并后外边距的计算准则如下:
- 如果两者都是负数,那么就去最大者
- 如果是一正一负,就会正值减去负值的绝对值
- 两个都是负值时,用 0 减去两个中绝对值大的那个
解决办法: 对于折叠的状况,次要有两种:兄弟之间重叠 和父子之间重叠(1)兄弟之间重叠
- 底部元素变为行内盒子:
display: inline-block
- 底部元素设置浮动:
float
- 底部元素的 position 的值为
absolute/fixed
(2)父子之间重叠
- 父元素退出:
overflow: hidden
- 父元素增加通明边框:
border:1px solid transparent
- 子元素变为行内盒子:
display: inline-block
- 子元素退出浮动属性或定位
Proxy 能够实现什么性能?
在 Vue3.0 中通过 Proxy
来替换本来的 Object.defineProperty
来实现数据响应式。
Proxy 是 ES6 中新增的性能,它能够用来自定义对象中的操作。
let p = new Proxy(target, handler)
target
代表须要增加代理的对象,handler
用来自定义对象中的操作,比方能够用来自定义 set
或者 get
函数。
上面来通过 Proxy
来实现一个数据响应式:
let onWatch = (obj, setBind, getLogger) => {
let handler = {get(target, property, receiver) {getLogger(target, property)
return Reflect.get(target, property, receiver)
},
set(target, property, value, receiver) {setBind(value, property)
return Reflect.set(target, property, value)
}
}
return new Proxy(obj, handler)
}
let obj = {a: 1}
let p = onWatch(
obj,
(v, property) => {console.log(` 监听到属性 ${property}扭转为 ${v}`)
},
(target, property) => {console.log(`'${property}' = ${target[property]}`)
}
)
p.a = 2 // 监听到属性 a 扭转
p.a // 'a' = 2
在上述代码中,通过自定义 set
和 get
函数的形式,在本来的逻辑中插入了咱们的函数逻辑,实现了在对对象任何属性进行读写时发出通知。
当然这是简略版的响应式实现,如果须要实现一个 Vue 中的响应式,须要在 get
中收集依赖,在 set
派发更新,之所以 Vue3.0 要应用 Proxy
替换本来的 API 起因在于 Proxy
无需一层层递归为每个属性增加代理,一次即可实现以上操作,性能上更好,并且本来的实现有一些数据更新不能监听到,然而 Proxy
能够完满监听到任何形式的数据扭转,惟一缺点就是浏览器的兼容性不好。
CSS 选择器及其优先级
选择器 | 格局 | 优先级权重 |
---|---|---|
id 选择器 | #id | 100 |
类选择器 | #classname | 10 |
属性选择器 | a[ref=“eee”] | 10 |
伪类选择器 | li:last-child | 10 |
标签选择器 | div | 1 |
伪元素选择器 | li:after | 1 |
相邻兄弟选择器 | h1+p | 0 |
子选择器 | ul>li | 0 |
后辈选择器 | li a | 0 |
通配符选择器 | * | 0 |
对于选择器的 优先级:
- 标签选择器、伪元素选择器:1
- 类选择器、伪类选择器、属性选择器:10
- id 选择器:100
- 内联款式:1000
注意事项:
- !important 申明的款式的优先级最高;
- 如果优先级雷同,则最初呈现的款式失效;
- 继承失去的款式的优先级最低;
- 通用选择器(*)、子选择器(>)和相邻同胞选择器(+)并不在这四个等级中,所以它们的权值都为 0;
- 样式表的起源不同时,优先级程序为:内联款式 > 外部款式 > 内部款式 > 浏览器用户自定义款式 > 浏览器默认款式。
如何判断一个对象是否属于某个类?
- 第一种形式,应用 instanceof 运算符来判断构造函数的 prototype 属性是否呈现在对象的原型链中的任何地位。
- 第二种形式,通过对象的 constructor 属性来判断,对象的 constructor 属性指向该对象的构造函数,然而这种形式不是很平安,因为 constructor 属性能够被改写。
- 第三种形式,如果须要判断的是某个内置的援用类型的话,能够应用 Object.prototype.toString() 办法来打印对象的[[Class]] 属性来进行判断。
为什么须要革除浮动?革除浮动的形式
浮动的定义: 非 IE 浏览器下,容器不设高度且子元素浮动时,容器高度不能被内容撑开。此时,内容会溢出到容器里面而影响布局。这种景象被称为浮动(溢出)。
浮动的工作原理:
- 浮动元素脱离文档流,不占据空间(引起“高度塌陷”景象)
- 浮动元素碰到蕴含它的边框或者其余浮动元素的边框停留
浮动元素能够左右挪动,直到遇到另一个浮动元素或者遇到它外边缘的蕴含框。浮动框不属于文档流中的一般流,当元素浮动之后,不会影响块级元素的布局,只会影响内联元素布局。此时文档流中的一般流就会体现得该浮动框不存在一样的布局模式。当蕴含框的高度小于浮动框的时候,此时就会呈现“高度塌陷”。
浮动元素引起的问题?
- 父元素的高度无奈被撑开,影响与父元素同级的元素
- 与浮动元素同级的非浮动元素会追随其后
- 若浮动的元素不是第一个元素,则该元素之前的元素也要浮动,否则会影响页面的显示构造
革除浮动的形式如下:
- 给父级 div 定义
height
属性 - 最初一个浮动元素之后增加一个空的 div 标签,并增加
clear:both
款式 - 蕴含浮动元素的父级标签增加
overflow:hidden
或者overflow:auto
- 应用 :after 伪元素。因为 IE6- 7 不反对 :after,应用 zoom:1 触发 hasLayout**
.clearfix:after{
content: "\200B";
display: table;
height: 0;
clear: both;
}
.clearfix{*zoom: 1;}
如何应用 for…of 遍历对象
for…of 是作为 ES6 新增的遍历形式,容许遍历一个含有 iterator 接口的数据结构(数组、对象等)并且返回各项的值,一般的对象用 for..of 遍历是会报错的。
如果须要遍历的对象是类数组对象,用 Array.from 转成数组即可。
var obj = {
0:'one',
1:'two',
length: 2
};
obj = Array.from(obj);
for(var k of obj){console.log(k)
}
如果不是类数组对象,就给对象增加一个 [Symbol.iterator] 属性,并指向一个迭代器即可。
// 办法一:var obj = {
a:1,
b:2,
c:3
};
obj[Symbol.iterator] = function(){var keys = Object.keys(this);
var count = 0;
return {next(){if(count<keys.length){return {value: obj[keys[count++]],done:false};
}else{return {value:undefined,done:true};
}
}
}
};
for(var k of obj){console.log(k);
}
// 办法二
var obj = {
a:1,
b:2,
c:3
};
obj[Symbol.iterator] = function*(){var keys = Object.keys(obj);
for(var k of keys){yield [k,obj[k]]
}
};
for(var [k,v] of obj){console.log(k,v);
}
数组有哪些原生办法?
- 数组和字符串的转换方法:toString()、toLocalString()、join() 其中 join() 办法能够指定转换为字符串时的分隔符。
- 数组尾部操作的办法 pop() 和 push(),push 办法能够传入多个参数。
- 数组首部操作的办法 shift() 和 unshift() 重排序的办法 reverse() 和 sort(),sort() 办法能够传入一个函数来进行比拟,传入前后两个值,如果返回值为负数,则替换两个参数的地位。
- 数组连贯的办法 concat(),返回的是拼接好的数组,不影响原数组。
- 数组截取方法 slice(),用于截取数组中的一部分返回,不影响原数组。
- 数组插入方法 splice(),影响原数组查找特定项的索引的办法,indexOf() 和 lastIndexOf() 迭代办法 every()、some()、filter()、map() 和 forEach() 办法
- 数组归并办法 reduce() 和 reduceRight() 办法
单行、多行文本溢出暗藏
- 单行文本溢出
overflow: hidden; // 溢出暗藏
text-overflow: ellipsis; // 溢出用省略号显示
white-space: nowrap; // 规定段落中的文本不进行换行
- 多行文本溢出
overflow: hidden; // 溢出暗藏
text-overflow: ellipsis; // 溢出用省略号显示
display:-webkit-box; // 作为弹性伸缩盒子模型显示。-webkit-box-orient:vertical; // 设置伸缩盒子的子元素排列形式:从上到下垂直排列
-webkit-line-clamp:3; // 显示的行数
留神:因为下面的三个属性都是 CSS3 的属性,没有浏览器能够兼容,所以要在后面加一个-webkit-
来兼容一部分浏览器。