关于javascript:前端经典面试题有答案

38次阅读

共计 13317 个字符,预计需要花费 34 分钟才能阅读完成。

对 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.2
console.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

javascript
let 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%;
}

为什么须要浏览器缓存?

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

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

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

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

正文完
 0