对this对象的了解

this 是执行上下文中的一个属性,它指向最初一次调用这个办法的对象。在理论开发中,this 的指向能够通过四种调用模式来判断。

  • 第一种是函数调用模式,当一个函数不是一个对象的属性时,间接作为函数来调用时,this 指向全局对象。
  • 第二种是办法调用模式,如果一个函数作为一个对象的办法来调用时,this 指向这个对象。
  • 第三种是结构器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
  • 第四种是 apply 、 call 和 bind 调用模式,这三个办法都能够显示的指定调用函数的 this 指向。其中 apply 办法接管两个参数:一个是 this 绑定的对象,一个是参数数组。call 办法接管的参数,第一个是 this 绑定的对象,前面的其余参数是传入函数执行的参数。也就是说,在应用 call() 办法时,传递给函数的参数必须一一列举进去。bind 办法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了应用 new 时会被扭转,其余状况下都不会扭转。

这四种形式,应用结构器调用模式的优先级最高,而后是 apply、call 和 bind 调用模式,而后是办法调用模式,而后是函数调用模式。

说一下HTTP 3.0

HTTP/3基于UDP协定实现了相似于TCP的多路复用数据流、传输可靠性等性能,这套性能被称为QUIC协定。

  1. 流量管制、传输可靠性性能:QUIC在UDP的根底上减少了一层来保障数据传输可靠性,它提供了数据包重传、拥塞管制、以及其余一些TCP中的个性。
  2. 集成TLS加密性能:目前QUIC应用TLS1.3,缩小了握手所破费的RTT数。
  3. 多路复用:同一物理连贯上能够有多个独立的逻辑数据流,实现了数据流的独自传输,解决了TCP的队头阻塞问题。
  4. 疾速握手:因为基于UDP,能够实现应用0 ~ 1个RTT来建设连贯。

原型/原型链

__proto__和prototype关系__proto__constructor对象独有的。2️prototype属性是函数独有的

在 js 中咱们是应用构造函数来新建一个对象的,每一个构造函数的外部都有一个 prototype 属性值,这个属性值是一个对象,这个对象蕴含了能够由该构造函数的所有实例共享的属性和办法。当咱们应用构造函数新建一个对象后,在这个对象的外部将蕴含一个指针,这个指针指向构造函数的 prototype 属性对应的值,在 ES5 中这个指针被称为对象的原型。一般来说咱们是不应该可能获取到这个值的,然而当初浏览器中都实现了 proto 属性来让咱们拜访这个属性,然而咱们最好不要应用这个属性,因为它不是标准中规定的。ES5 中新增了一个 Object.getPrototypeOf() 办法,咱们能够通过这个办法来获取对象的原型。

当咱们拜访一个对象的属性时,如果这个对象外部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有本人的原型,于是就这样始终找上来,也就是原型链的概念。原型链的止境一般来说都是 Object.prototype 所以这就是咱们新建的对象为什么可能应用 toString() 等办法的起因。

特点:JavaScript 对象是通过援用来传递的,咱们创立的每个新对象实体中并没有一份属于本人的原型正本。当咱们批改原型时,与 之相干的对象也会继承这一扭转
  • 原型(prototype): 一个简略的对象,用于实现对象的 属性继承。能够简略的了解成对象的爹。在 FirefoxChrome 中,每个JavaScript对象中都蕴含一个__proto__(非标准)的属性指向它爹(该对象的原型),可obj.__proto__进行拜访。
  • 构造函数: 能够通过new来 新建一个对象 的函数。
  • 实例: 通过构造函数和new创立进去的对象,便是实例。 实例通过__proto__指向原型,通过constructor指向构造函数。
Object为例,咱们罕用的Object便是一个构造函数,因而咱们能够通过它构建实例。
// 实例const instance = new Object()
则此时, 实例为instance, 构造函数为Object,咱们晓得,构造函数领有一个prototype的属性指向原型,因而原型为:
// 原型const prototype = Object.prototype

这里咱们能够来看出三者的关系:

  • 实例.__proto__ === 原型
  • 原型.constructor === 构造函数
  • 构造函数.prototype === 原型
// 这条线其实是是基于原型进行获取的,能够了解成一条基于原型的映射线// 例如: // const o = new Object()// o.constructor === Object   --> true// o.__proto__ = null;// o.constructor === Object   --> false实例.constructor === 构造函数

原型链

原型链是由原型对象组成,每个对象都有 __proto__ 属性,指向了创立该对象的构造函数的原型,__proto__ 将对象连接起来组成了原型链。是一个用来实现继承和共享属性的无限的对象链
  • 属性查找机制: 当查找对象的属性时,如果实例对象本身不存在该属性,则沿着原型链往上一级查找,找到时则输入,不存在时,则持续沿着原型链往上一级查找,直至最顶级的原型对象Object.prototype,如还是没找到,则输入undefined
  • 属性批改机制: 只会批改实例对象自身的属性,如果不存在,则进行增加该属性,如果须要批改原型的属性时,则能够用: b.prototype.x = 2;然而这样会造成所有继承于该对象的实例的属性产生扭转。

js 获取原型的办法

  • p.proto
  • p.constructor.prototype
  • Object.getPrototypeOf(p)

总结

  • 每个函数都有 prototype 属性,除了 Function.prototype.bind(),该属性指向原型。
  • 每个对象都有 __proto__ 属性,指向了创立该对象的构造函数的原型。其实这个属性指向了 [[prototype]],然而 [[prototype]]是外部属性,咱们并不能拜访到,所以应用 _proto_来拜访。
  • 对象能够通过 __proto__ 来寻找不属于该对象的属性,__proto__ 将对象连接起来组成了原型链。

为什么0.1+0.2 ! == 0.3,如何让其相等

在开发过程中遇到相似这样的问题:

let n1 = 0.1, n2 = 0.2console.log(n1 + n2)  // 0.30000000000000004

这里失去的不是想要的后果,要想等于0.3,就要把它进行转化:

(n1 + n2).toFixed(2) // 留神,toFixed为四舍五入

toFixed(num) 办法可把 Number 四舍五入为指定小数位数的数字。那为什么会呈现这样的后果呢?

计算机是通过二进制的形式存储数据的,所以计算机计算0.1+0.2的时候,实际上是计算的两个数的二进制的和。0.1的二进制是0.0001100110011001100...(1100循环),0.2的二进制是:0.00110011001100...(1100循环),这两个数的二进制都是有限循环的数。那JavaScript是如何解决有限循环的二进制小数呢?

个别咱们认为数字包含整数和小数,然而在 JavaScript 中只有一种数字类型:Number,它的实现遵循IEEE 754规范,应用64位固定长度来示意,也就是规范的double双精度浮点数。在二进制迷信表示法中,双精度浮点数的小数局部最多只能保留52位,再加上后面的1,其实就是保留53位有效数字,残余的须要舍去,听从“0舍1入”的准则。

依据这个准则,0.1和0.2的二进制数相加,再转化为十进制数就是:0.30000000000000004

上面看一下双精度数是如何保留的:

  • 第一局部(蓝色):用来存储符号位(sign),用来辨别正负数,0示意负数,占用1位
  • 第二局部(绿色):用来存储指数(exponent),占用11位
  • 第三局部(红色):用来存储小数(fraction),占用52位

对于0.1,它的二进制为:

0.00011001100110011001100110011001100110011001100110011001 10011...

转为迷信计数法(迷信计数法的后果就是浮点数):

1.1001100110011001100110011001100110011001100110011001*2^-4

能够看出0.1的符号位为0,指数位为-4,小数位为:

1001100110011001100110011001100110011001100110011001

那么问题又来了,指数位是正数,该如何保留呢?

IEEE标准规定了一个偏移量,对于指数局部,每次都加这个偏移量进行保留,这样即便指数是正数,那么加上这个偏移量也就是负数了。因为JavaScript的数字是双精度数,这里就以双精度数为例,它的指数局部为11位,能示意的范畴就是0~2047,IEEE固定双精度数的偏移量为1023

  • 当指数位不全是0也不全是1时(规格化的数值),IEEE规定,阶码计算公式为 e-Bias。 此时e最小值是1,则1-1023= -1022,e最大值是2046,则2046-1023=1023,能够看到,这种状况下取值范畴是-1022~1013
  • 当指数位全副是0的时候(非规格化的数值),IEEE规定,阶码的计算公式为1-Bias,即1-1023= -1022。
  • 当指数位全副是1的时候(非凡值),IEEE规定这个浮点数可用来示意3个非凡值,别离是正无穷,负无穷,NaN。 具体的,小数位不为0的时候示意NaN;小数位为0时,当符号位s=0时示意正无穷,s=1时候示意负无穷。

对于下面的0.1的指数位为-4,-4+1023 = 1019 转化为二进制就是:1111111011.

所以,0.1示意为:

0 1111111011 1001100110011001100110011001100110011001100110011001

说了这么多,是时候该最开始的问题了,如何实现0.1+0.2=0.3呢?

对于这个问题,一个间接的解决办法就是设置一个误差范畴,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只有判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就能够判断为0.1+0.2 ===0.3

function numberepsilon(arg1,arg2){                     return Math.abs(arg1 - arg2) < Number.EPSILON;        }        console.log(numberepsilon(0.1 + 0.2, 0.3)); // true

escape、encodeURI、encodeURIComponent 的区别

  • encodeURI 是对整个 URI 进行本义,将 URI 中的非法字符转换为非法字符,所以对于一些在 URI 中有非凡意义的字符不会进行本义。
  • encodeURIComponent 是对 URI 的组成部分进行本义,所以一些特殊字符也会失去本义。
  • escape 和 encodeURI 的作用雷同,不过它们对于 unicode 编码为 0xff 之外字符的时候会有区别,escape 是间接在字符的 unicode 编码前加上 %u,而 encodeURI 首先会将字符转换为 UTF-8 的格局,再在每个字节前加上 %。

什么是物理像素,逻辑像素和像素密度,为什么在挪动端开发时须要用到@3x, @2x这种图片?

以 iPhone XS 为例,当写 CSS 代码时,针对于单位 px,其宽度为 414px & 896px,也就是说当赋予一个 DIV元素宽度为 414px,这个 DIV 就会填满手机的宽度;

而如果有一把尺子来理论测量这部手机的物理像素,理论为 1242*2688 物理像素;通过计算可知,1242/414=3,也就是说,在单边上,一个逻辑像素=3个物理像素,就说这个屏幕的像素密度为 3,也就是常说的 3 倍屏。

对于图片来说,为了保障其不失真,1 个图片像素至多要对应一个物理像素,如果原始图片是 500300 像素,那么在 3 倍屏上就要放一个 1500900 像素的图片能力保障 1 个物理像素至多对应一个图片像素,能力不失真。 当然,也能够针对所有屏幕,都只提供最高清图片。尽管低密度屏幕用不到那么多图片像素,而且会因为下载多余的像素造成带宽节约和下载提早,但从后果上说能保障图片在所有屏幕上都不会失真。

还能够应用 CSS 媒体查问来判断不同的像素密度,从而抉择不同的图片:

my-image { background: (low.png); }@media only screen and (min-device-pixel-ratio: 1.5) {  #my-image { background: (high.png); }}

参考 前端进阶面试题具体解答

line-height 的了解及其赋值形式

(1)line-height的概念:

  • line-height 指一行文本的高度,蕴含了字间距,实际上是下一行基线到上一行基线间隔;
  • 如果一个标签没有定义 height 属性,那么其最终体现的高度由 line-height 决定;
  • 一个容器没有设置高度,那么撑开容器高度的是 line-height,而不是容器内的文本内容;
  • 把 line-height 值设置为 height 一样大小的值能够实现单行文字的垂直居中;
  • line-height 和 height 都能撑开一个高度;

(2)line-height 的赋值形式:

  • 带单位:px 是固定值,而 em 会参考父元素 font-size 值计算本身的行高
  • 纯数字:会把比例传递给后辈。例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px
  • 百分比:将计算后的值传递给后辈

display:inline-block 什么时候会显示间隙?

  • 有空格时会有间隙,能够删除空格解决;
  • margin正值时,能够让margin应用负值解决;
  • 应用font-size时,可通过设置font-size:0letter-spacingword-spacing解决;

for...in和for...of的区别

for…of 是ES6新增的遍历形式,容许遍历一个含有iterator接口的数据结构(数组、对象等)并且返回各项的值,和ES3中的for…in的区别如下

  • for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;
  • for… in 会遍历对象的整个原型链,性能十分差不举荐应用,而 for … of 只遍历以后对象不会遍历原型链;
  • 对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包含原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;

总结: for...in 循环次要是为了遍历对象而生,不适用于遍历数组;for...of 循环能够用来遍历数组、类数组对象,字符串、Set、Map 以及 Generator 对象。

call() 和 apply() 的区别?

它们的作用截然不同,区别仅在于传入参数的模式的不同。

  • apply 承受两个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数为一个带下标的汇合,这个汇合能够为数组,也能够为类数组,apply 办法把这个汇合中的元素作为参数传递给被调用的函数。
  • call 传入的参数数量不固定,跟 apply 雷同的是,第一个参数也是代表函数体内的 this 指向,从第二个参数开始往后,每个参数被顺次传入函数。

Promise的根本用法

(1)创立Promise对象

Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已胜利)和rejected(已失败)。

Promise构造函数承受一个函数作为参数,该函数的两个参数别离是resolvereject

const promise = new Promise(function(resolve, reject) {  // ... some code  if (/* 异步操作胜利 */){    resolve(value);  } else {    reject(error);  }});

个别状况下都会应用new Promise()来创立promise对象,然而也能够应用promise.resolvepromise.reject这两个办法:

  • Promise.resolve

Promise.resolve(value)的返回值也是一个promise对象,能够对返回值进行.then调用,代码如下:

Promise.resolve(11).then(function(value){  console.log(value); // 打印出11});

resolve(11)代码中,会让promise对象进入确定(resolve状态),并将参数11传递给前面的then所指定的onFulfilled 函数;

创立promise对象能够应用new Promise的模式创建对象,也能够应用Promise.resolve(value)的模式创立promise对象;

  • Promise.reject

Promise.reject 也是new Promise的快捷模式,也创立一个promise对象。代码如下:

Promise.reject(new Error(“我错了,请原谅俺!!”));

就是上面的代码new Promise的简略模式:

new Promise(function(resolve,reject){   reject(new Error("我错了!"));});

上面是应用resolve办法和reject办法:

function testPromise(ready) {  return new Promise(function(resolve,reject){    if(ready) {      resolve("hello world");    }else {      reject("No thanks");    }  });};// 办法调用testPromise(true).then(function(msg){  console.log(msg);},function(error){  console.log(error);});

下面的代码的含意是给testPromise办法传递一个参数,返回一个promise对象,如果为true的话,那么调用promise对象中的resolve()办法,并且把其中的参数传递给前面的then第一个函数内,因而打印出 “hello world”, 如果为false的话,会调用promise对象中的reject()办法,则会进入then的第二个函数内,会打印No thanks

(2)Promise办法

Promise有五个罕用的办法:then()、catch()、all()、race()、finally。上面就来看一下这些办法。

  1. then()

当Promise执行的内容合乎胜利条件时,调用resolve函数,失败就调用reject函数。Promise创立完了,那该如何调用呢?

promise.then(function(value) {  // success}, function(error) {  // failure});

then办法能够承受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中第二个参数能够省略。 then办法返回的是一个新的Promise实例(不是原来那个Promise实例)。因而能够采纳链式写法,即then办法前面再调用另一个then办法。

当要写有程序的异步事件时,须要串行时,能够这样写:

let promise = new Promise((resolve,reject)=>{    ajax('first').success(function(res){        resolve(res);    })})promise.then(res=>{    return new Promise((resovle,reject)=>{        ajax('second').success(function(res){            resolve(res)        })    })}).then(res=>{    return new Promise((resovle,reject)=>{        ajax('second').success(function(res){            resolve(res)        })    })}).then(res=>{})

那当要写的事件没有程序或者关系时,还如何写呢?能够应用all 办法来解决。

2. catch()

Promise对象除了有then办法,还有一个catch办法,该办法相当于then办法的第二个参数,指向reject的回调函数。不过catch办法还有一个作用,就是在执行resolve回调函数时,如果呈现谬误,抛出异样,不会进行运行,而是进入catch办法中。

p.then((data) => {     console.log('resolved',data);},(err) => {     console.log('rejected',err);     }); p.then((data) => {    console.log('resolved',data);}).catch((err) => {    console.log('rejected',err);});

3. all()

all办法能够实现并行任务, 它接管一个数组,数组的每一项都是一个promise对象。当数组中所有的promise的状态都达到resolved的时候,all办法的状态就会变成resolved,如果有一个状态变成了rejected,那么all办法的状态就会变成rejected

javascriptlet promise1 = new Promise((resolve,reject)=>{    setTimeout(()=>{       resolve(1);    },2000)});let promise2 = new Promise((resolve,reject)=>{    setTimeout(()=>{       resolve(2);    },1000)});let promise3 = new Promise((resolve,reject)=>{    setTimeout(()=>{       resolve(3);    },3000)});Promise.all([promise1,promise2,promise3]).then(res=>{    console.log(res);    //后果为:[1,2,3] })

调用all办法时的后果胜利的时候是回调函数的参数也是一个数组,这个数组按程序保留着每一个promise对象resolve执行时的值。

(4)race()

race办法和all一样,承受的参数是一个每项都是promise的数组,然而与all不同的是,当最先执行完的事件执行完之后,就间接返回该promise对象的值。如果第一个promise对象状态变成resolved,那本身的状态变成了resolved;反之第一个promise变成rejected,那本身状态就会变成rejected

let promise1 = new Promise((resolve,reject)=>{    setTimeout(()=>{       reject(1);    },2000)});let promise2 = new Promise((resolve,reject)=>{    setTimeout(()=>{       resolve(2);    },1000)});let promise3 = new Promise((resolve,reject)=>{    setTimeout(()=>{       resolve(3);    },3000)});Promise.race([promise1,promise2,promise3]).then(res=>{    console.log(res);    //后果:2},rej=>{    console.log(rej)};)

那么race办法有什么理论作用呢?当要做一件事,超过多长时间就不做了,能够用这个办法来解决:

Promise.race([promise1,timeOutPromise(5000)]).then(res=>{})

5. finally()

finally办法用于指定不论 Promise 对象最初状态如何,都会执行的操作。该办法是 ES2018 引入规范的。

promise.then(result => {···}).catch(error => {···}).finally(() => {···});

下面代码中,不论promise最初的状态,在执行完thencatch指定的回调函数当前,都会执行finally办法指定的回调函数。

上面是一个例子,服务器应用 Promise 解决申请,而后应用finally办法关掉服务器。

server.listen(port)  .then(function () {    // ...  })  .finally(server.stop);

finally办法的回调函数不承受任何参数,这意味着没有方法晓得,后面的 Promise 状态到底是fulfilled还是rejected。这表明,finally办法外面的操作,应该是与状态无关的,不依赖于 Promise 的执行后果。finally实质上是then办法的特例:

promise.finally(() => {  // 语句});// 等同于promise.then(  result => {    // 语句    return result;  },  error => {    // 语句    throw error;  });

下面代码中,如果不应用finally办法,同样的语句须要为胜利和失败两种状况各写一次。有了finally办法,则只须要写一次。

margin 和 padding 的应用场景

  • 须要在border外侧增加空白,且空白处不须要背景(色)时,应用 margin;
  • 须要在border内测增加空白,且空白处须要背景(色)时,应用 padding。

伪元素和伪类的区别和作用?

  • 伪元素:在内容元素的前后插入额定的元素或款式,然而这些元素实际上并不在文档中生成。它们只在内部显示可见,但不会在文档的源代码中找到它们,因而,称为“伪”元素。例如:
p::before {content:"第一章:";}p::after {content:"Hot!";}p::first-line {background:red;}p::first-letter {font-size:30px;}
  • 伪类:将非凡的成果增加到特定选择器上。它是已有元素上增加类别的,不会产生新的元素。例如:
a:hover {color: #FF00FF}p:first-child {color: red}

总结: 伪类是通过在元素选择器上加⼊伪类扭转元素状态,⽽伪元素通过对元素的操作进⾏对元素的扭转。

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(构造函数, 初始化参数);

暗藏元素的办法有哪些

  • display: none:渲染树不会蕴含该渲染对象,因而该元素不会在页面中占据地位,也不会响应绑定的监听事件。
  • visibility: hidden:元素在页面中仍占据空间,然而不会响应绑定的监听事件。
  • opacity: 0:将元素的透明度设置为 0,以此来实现元素的暗藏。元素在页面中依然占据空间,并且可能响应元素绑定的监听事件。
  • position: absolute:通过应用相对定位将元素移除可视区域内,以此来实现元素的暗藏。
  • z-index: 负值:来使其余元素遮盖住该元素,以此来实现暗藏。
  • clip/clip-path :应用元素裁剪的办法来实现元素的暗藏,这种办法下,元素仍在页面中占据地位,然而不会响应绑定的监听事件。
  • transform: scale(0,0):将元素缩放为 0,来实现元素的暗藏。这种办法下,元素仍在页面中占据地位,然而不会响应绑定的监听事件。

transition和animation的区别

  • transition是适度属性,强调适度,它的实现须要触发一个事件(比方鼠标挪动下来,焦点,点击等)才执行动画。它相似于flash的补间动画,设置一个开始关键帧,一个完结关键帧。
  • animation是动画属性,它的实现不须要触发事件,设定好工夫之后能够本人执行,且能够循环一个动画。它也相似于flash的补间动画,然而它能够设置多个关键帧(用@keyframe定义)实现动画。

iframe 有那些长处和毛病?

iframe 元素会创立蕴含另外一个文档的内联框架(即行内框架)。

长处:

  • 用来加载速度较慢的内容(如广告)
  • 能够使脚本能够并行下载
  • 能够实现跨子域通信

毛病:

  • iframe 会阻塞主页面的 onload 事件
  • 无奈被一些搜索引擎索辨认
  • 会产生很多页面,不容易治理

CSS预处理器/后处理器是什么?为什么要应用它们?

预处理器, 如:lesssassstylus,用来预编译sass或者less,减少了css代码的复用性。层级,mixin, 变量,循环, 函数等对编写以及开发UI组件都极为不便。

后处理器, 如: postCss,通常是在实现的样式表中依据css标准解决css,让其更加无效。目前最常做的是给css属性增加浏览器公有前缀,实现跨浏览器兼容性的问题。

css预处理器为css减少一些编程个性,无需思考浏览器的兼容问题,能够在CSS中应用变量,简略的逻辑程序,函数等在编程语言中的一些根本的性能,能够让css更加的简洁,减少适应性以及可读性,可维护性等。

其它css预处理器语言:Sass(Scss), Less, Stylus, Turbine, Swithch css, CSS Cacheer, DT Css

应用起因:

  • 构造清晰, 便于扩大
  • 能够很不便的屏蔽浏览器公有语法的差别
  • 能够轻松实现多重继承
  • 完满的兼容了CSS代码,能够利用到老我的项目中

实现一个宽高自适应的正方形

  • 利用vw来实现:
.square {  width: 10%;  height: 10vw;  background: tomato;}
  • 利用元素的margin/padding百分比是绝对父元素width的性质来实现:
.square {  width: 20%;  height: 0;  padding-top: 20%;  background: orange;}
  • 利用子元素的margin-top的值来实现:
.square {  width: 30%;  overflow: hidden;  background: yellow;}.square::after {  content: '';  display: block;  margin-top: 100%;}

为什么须要浏览器缓存?

对于浏览器的缓存,次要针对的是前端的动态资源,最好的成果就是,在发动申请之后,拉取相应的动态资源,并保留在本地。如果服务器的动态资源没有更新,那么在下次申请的时候,就间接从本地读取即可,如果服务器的动态资源曾经更新,那么咱们再次申请的时候,就到服务器拉取新的资源,并保留在本地。这样就大大的缩小了申请的次数,进步了网站的性能。这就要用到浏览器的缓存策略了。

所谓的浏览器缓存指的是浏览器将用户申请过的动态资源,存储到电脑本地磁盘中,当浏览器再次拜访时,就能够间接从本地加载,不须要再去服务端申请了。

应用浏览器缓存,有以下长处:

  • 缩小了服务器的累赘,进步了网站的性能
  • 放慢了客户端网页的加载速度
  • 缩小了多余网络数据传输