前端面经基础部分总结(1)

对于null: 可以使用String(null)判断,如果使用typeof对其进行判定返回会是object,这是因为历史遗留原因对于其余的基本类型:使用typeof进行判断,返回的格式就是字符串类型的变量的类型

  1. 引用类型部分:

可以使用Object.prototype.toString.call()方法来进行判定

闭包


对于闭包,通俗来说,闭包产生于多个函数嵌套之间,当内层函数被保存到外面时,就会产生。这样说有点抽象看一个实际例子

funciton foo(){

var a = ‘hello word’

function bar(){

console.log(a);

}

return bar;

}

foo()

可以参考https://juejin.im/post/5b081f8d6fb9a07a9b3664b6博客来理解

闭包的优点:

  • 函数累加

  • 用作缓存结构

  • 封装

  • 模块化

闭包的坏处:

  • 造成原有作用域链不释放,造成内存泄漏

隐式类型转化


与隐式类型转化相对的就是显示类型转化,常使用ParseInt() ParseFloat() Number()方法,对于这几种,可以参考具体的方法来理解

对于隐式类型转化,其实常存在于下面的这几种情况

  1. 使用 == 符号时,使用+ - 符号来计算值时,需要记住的几个常用的案列有null == undefined 这个打印的结果为true

  2. 12 == ‘12’ 对于这种表示的形式其结果会为true,因为等式右边的这个字符串常量都会被Number()先将这个字符串类型的数据,转为数值,然后才来进行比较

[ ] == ![ ] 这个表示的结果为true,类似于这种你就可以记住

推荐一篇博客https://juejin.im/post/5a7172d9f265da3e3245cbca,在这上面有具体的关于隐式类型转化的方式与案列

变量提升


对于变量提升,发生的情况主要是用了var这个声明变量的方式,在es6之后出现的let, const这两种声明变量的方式,并不会出现这种变量声明。

那么对于变量提升,我们需要掌握的其实就是js中预编译的过程,当你了解到预编译之后,对于整个的变量提升就非常的清楚明白了。

掌握预编译首先要掌握的就是在js当中的全局变量与局部变量

  • 全局变量
  1. 在全局显示的定义: var(关键字) + (标识符),如 var t = 2;

  2. 隐式的定义:无论你在函数的内部还是在全局中写 t = 2,类似与这种形式的方式,都可以称t为全局变量,具体例子

如: function (){ var a = b = 3;}

此时的b为全局变量,而这里的a就为局部变量

  • 局部变量

在function内部,定义变量时,采用上面所说的显示定义全局变量的方式,如 var a = 3;则此表示的就是局部变量,如上面所举出的那个例子,a为局部变量,b为全局变量。

当了解完这两个概念之后,那么就来理解函数的预编译过程,首先讨论是在函数中讨论函数的预编译发生过程,总共有四步:

  1. 生成一个AO对象(AO为执行期上下文)

  2. 找形参和变量声明,作为AO对象的属性,其值为underfine

  3. 形参和实参值相统一

  4. 在函数中找函数声明

举个栗子,来加深对方面的四句话的理解

function bar(a){

console.log(a,b); // funtion a() {}, undefined

var b = 3;

console.log(a,b);//function a() {}, 3

var a = 1;

console.log(a,b); // 1,3

function a(){}

console.log(a); //1

}

bar(3);

对于上面的例子,首先先看到第一句话,生成了一个AO对象,然后,再来看第二句,在整个函数的形参和变量声明,在这个例子中只有a和b两个变量。在此时,两者的值都为undefined,然后再来看第三句话,形参和实参相统一,这时a由于传入的实参的值为3,那么此时a的值为3,b的值还是undefined,再来到第四句话,此时有个a的函数声明,那么此时a的值就变为了function,所以此时打印的结果就如上面注释后打印出的结果一样

全局中的预编译过程

  1. 生成一个GO对象(GO为执行期上下文)

  2. 找形参和变量声明,作为GO对象的属性,其值为undefined

  3. 在函数中找函数声明

在全局中预编译的过程和在函数中,类似,只是少了一个形参和实参相统一的步骤。这里就不多余的复述

作用域链与原型链


  • 作用域链:

  • 作用域链,对于作用域链,首先需要认识什么是自由变量,如果当前的作用域中想要输出一个变量,但是该变量在当前的作用域并没有声明。这种就叫做自由变量,举个栗子:

var a = 100;

function test(){

var b = 1;

console.log(a,b); //这里的a就是自由变量

}

test();

  • 作用域链含义:如果当前变量是自由变量,那么就会再向上一层寻找该自由变量,直到找到全局作用域还没有找到,就会宣布放弃,这种一层一层的关系就是作用域链。

  • 原型链

  • 原型对象:原型对象也是普通的对象,其带有一个自带的隐式的_proto_属性,原型也又可能是有自己的原型,如果一个对象的原型不为null的话,就称为原型链。原型链是由一些用来继承的共享的对象组成的(有限的)对象链。

  • 构造函数,实例原型以及实例之间的关系:

  1. 构造函数通过prototype指向实例原型,如:Person构造函数通过prototype指向Person.prototype

  2. 实例原型通过constructor指向构造函数,如:Person.prototype通过constructor指向Person构造函数

  3. 实例通过__proto__隐式的指向实例原型,如: person实例通过__proto__指向实例原型

数组与字符串常用方法


数组

对于数组,其基本的方法有

  • pop()

  • push()

  • shift()

  • unshift()

  • forEach()

  • filter()

  • map()

  • includes()

  • indexOf()

  • reduce()

  • reduceRight()

  • join()

  • slice()

  • splice()

举一个简单的例子,这个很简单的例子也有在面试中被要求写过

如:一个数组为[1,2,5,7,10,46,90],选出大于5的数并用’-'连接起来,如这个例子中输出 7-10-46-90

其实这个很简单先创建一个空串,用for循环,然后字符串拼接。实现的方式很多这里用一种较为简单的方法实现

function getStr(arr){

return arr.filter(item => item > 5).join(‘-’);

}

在日常写程序的过程中,数组的使用场景非常的多,对于里面的方法,都需要去掌握,具体关于每个方法参数以及性质可以参考https://developer.mozilla.org/zhCN/docs/Web/JavaScript/Reference/Global_Objects/Array这个网站,该网站比w3c上更新的更加的快并且健全,建议去参考api时,就可以在里面去参考

字符串

常用的一些方法如下:

  • split()

  • indexOf()

  • slice()

  • sub()

  • substr()

  • toString()

具体这些方法的使用,可以参考上面数组中提供的那个网站上去参考

事件循环


EventLoop:即事件循环,指浏览器或Node的一种解决js单线程不会阻塞的机制,其是一种执行模型,在不同的地方有不同的实现,浏览器和NodeJs都是基于不同的

技术实现了各自的EventLoop,可以概述为以下两点:

  1. 浏览器的EventLoop是在h5规范中所写

  2. noeJs的EventLoop是基于libvue实现的

理解事件循环,首先需要区分两个任务

  • 宏任务(macrotask),也叫tasks,一些异步执行的任务的回调会依次的进入macro task queue,等待后续被调用,这些任务包括
  1. setTimeout

  2. setInterval

  3. setImmediate(node独有)

  4. requestAnimation(浏览器独有)

  5. I/O

  6. UI rendering(浏览器独有)

  • 微任务(microtasks),也叫jobs,这些异步任务包括
  1. process.nextTick(node独有)

  2. Promise.then()

  3. object.observe()

  4. MutationObserve(注意: promise构造函数里的代码是同步执行的)

上面的这些任务,只需要记住就行了

浏览器中事件循环的机制

在浏览器中,只有一个执行栈和一个任务队列,在任务队列中放的是宏任务浏览器中事件循环的执行方式为:每从事件队列中取出一个事件时,有微任务就把微任务执行完,然后才开始执行事件(即从任务队列中去拿一个宏任务)

举个栗子

console.log(1)

setTimeout(function(){

console.log(2);

},0)

new Promise(() => {

console.log(3);

setTimeout(() => {

console.log(4);

})

})

console.log(5);

具体的结果可以自己试试,然后结合在浏览器中的事件循环的执行方式来理解对于node中的事件循环机制,会涉及到六个队列,执行的方式也不一样,具体可以在网上看看博客

this指向


对于this指向只需要记住下面的几个点

  • 函数预编译过程中指向的就是window对象。

  • 全局作用域——>指向window

  • call/apply会改变函数运行的指向

  • obj.function(); function()里面的this指向的就是obj.谁调用了这个方法,this就指向谁。

上面的四点只需要记住就是了,这里就举一个例子说明下

var a = 5;

function test(){

a = 0;

console.log(a);

console.log(this.a);

var a;

console.log(a);

}

test();

new test();

上面这两种打印出的结果分别为 0 5 0 和 0 undefined 0;对于test()执行的这种方式,就是一个方法的调用,此时并没有某个对象去调用这个方法,因此此时this.a指的就是全局变量中的a,因此打印出的就是5。而在new test()就是新建一个对象的过程,在新建对象的过程中,this.a并没有指向的是window对象,也没有指明是当前的实例对象,因此在这里输出的就是undefined

数组去重


对于数组的去重方式有很多种,这里列举了其中的一些方法,关于去重,自己可以想一下或者去实现自己所能够想到的数组去重的方式

  • 利用Set数据结构进行去重

function unique(arr){

return Array.from(new Set(arr));

}

这种方法所实现的去重无法去掉空对象

  • 使用双重for循环,然后使用splice去重

function unique(arr){

for(let i = 0; i < arr.length - 1; i++){

for(let j = i + 1; j < arr.length; j++){

if(arr[i] == arr[j]){

arr.splice(j, 1);

j–;

}

}

}

}

  • 使用indexOf去重

function unique(arr){

if(! Array.isArray(arr)){

console.log(‘type error’);

return;

}

var array = [ ];

for(let i = 0; i < arr.length; i++){

if(array.indexOf(arr[i]) === -1){

array.push(arr[i]);

}

}

return array;

}

  • 利用sort()

function unique(arr){

if(! Array.isArray(arr)){

console.log(‘type error’);

return;

}

arr = arr.sort(); //使用此方法的目的是为了将重复的内容放在一起

let array = [arr[0]];

for(let i = 1; i < arr.length; i++){

if(arr[i] !== arr[i - 1]){

array.push(arr[i]);

}

}

return array;

}

  • 利用includes方法

function unique(arr){

if(! Array.isArray(arr)){

console.log(‘type error’);

return;

}

let array = [ ];

for(let i = 0; i < arr.length; i++){

if(!array.includes(arr[i])){

array.push(arr[i]);

}

}

return array;

}

  • 利用hasOwnproperty

function unique(arr){

let obj = { };

return arr.filter(function(item, index, arr){

return obj.hasOwnProperty(typeof, item + item) ? false : (obj[typeof item + item] = true)

})

}

使用hasOwnProperty判断是否存在对象属性

  • 利用filter

function unique(arr){

return arr.filter((item, index, arr) => {

return arr.indexOf(item, 0) === index;

})

}

这里就不全部举例完了,还有一些方式,可以自行参考一些博客

深浅克隆


对于深度克隆与浅度克隆,无非就是对于对象的拷贝问题进行的一个探讨,对于基本类型的赋值就是值传递,对于特殊类型对象的赋值,是将对象地址的引用赋值,这时候修改对象中的属性或者值,会导致所有引用的这个对象的值得改变,如果想要真正的赋值一个新的对象,而不是复制对象的引用就会用到深拷贝

  • 浅拷贝:
  1. 使用=符号

let str1 = {

a: 1,

b: 2,

c: 3,

d: {

e: 5

}

}

let str2 = str1;

str2.d.e = 4;

console.log(str1,str2)

对于这种形式的对象的拷贝,当更改掉str2中的内容后,会导致str1中的改变

  1. Object.assign()

该方法实际上是一个浅拷贝的过程,与=的区别在与Object.assign()可以处理一层深拷贝

  • 深拷贝
  1. 使用JSON.parse(JSON.stringify(str))进行拷贝,但是该方法对于function不进行任何拷贝

  2. 使用for in进行深拷贝具体实现方式如下

function deepclone(target, origin){

var target = target || {},

toStr = Object.prototype.toString;

arrStr = ‘[object Array]’;

for(var item in origin){

if(origin.hasOwnProperty(item)){

if(origin[item] !== null && typeof(origin[item]) == ‘object’){

if(toStr.call(origin[item]) === arrStr){

target[item] = [];

}else{

target[item] = {};

}

deepclone(target[item],origin[item]);

}else{

target[item] = origin[item];

}

}

}

}

内存泄漏


  • 内存泄漏指得是任何对象在不再拥有或需要它之后缓存在的情况

  • 垃圾回收机制,会定时扫描对象,并计算引用每个对象的其他对象的数量,如果一个对象的引用数量为0(即没有其他对象引用该对象),或该对象的唯一引用是循环的,那么该对象的内存即可回收

  • 造成内存泄漏的几种情况

  1. setTimeout中的第一个参数使用字符串而不是函数时

  2. 闭包

  3. 控制台日志

  4. 循环(两个对象彼此引用,并且彼此保留时,就会产生一个循环)

函数柯里化


即通过多次的传参使得某个函数的参数达到饱和,具体实现思想如下

  1. 首先实现将函数的参数拆分为两个部分,即下面的FixedParame方法的实现

  2. 然后再采用递归的思想,将函数传入的参数进行多次划分,直到达到最大化

function FixedParame(fn){

var _args = [].slice.call(arguments, 1);

return function(){

var newArgs = _args.concat([].slice.call(arguments, 0));

return fn.apply(this, newArgs);

}

}

function newCurry(fn, length){

var length = length || fn.length;

return function(){

if(arguments.length < length){

var cobined = [fn].concat([].slice.call(arguments, 0));

return newCurry(FixedParame.apply(this, cobined),length - arguments.length);

}else{

return fn.apply(this, arguments);

}

}

}

组合函数


其目的就是将几个函数的功能给组合在一起,下面封装一个组合函数,在使用函数时,只需要将函数传入即可

function compose(){

//将类数组转化为数组,这样才能使用数组方法

var args = Array.prototype.slice.call(arguments);

var len = args.length - 1;

return function(x){

var result = argslen;

while(len–){

result = argslen;

}

return result;

}

}

抖动与节流


  • 节流

对于节流要明白两个点:

  1. 节流的目的是为了防止网站遭到恶意的攻击

  2. 节流函数的封装过程

下面就是封装的一个节流函数

function throttle(handler, wait){

var initTime = 0;

return function (e){

var nowTime = new Date().getTime();

if(nowTime - initTime > wait){

handler.apply(this, arguments);

initTime = nowTime;

}

}

}

  • 抖动

对于抖动函数明白两点:

  1. 抖动函数的目的函数在频繁发生时,在等待一段时间后去执行的行为

  2. 抖动函数的封装过程

下面就是抖动函数的封装实现

function debounce(handler, delay){

var timer = null;

return function(){

var _self = this, _args = arguments;

clearTimeout(timer);

timer = setTimeout(function(){

handler.apply(_self, _args);

},delay);

}

}

函数扁平化


函数的扁平化,其目的其实就是将一个多维数组变为一个一维数组的过程。在Array中有一个flat(),其作用就是如此,接下来就手动实现falt()函数

function flatten(){

var arr = arr || [];

var toStr = Object.prototype.toString;

this.forEach(item => {

return toStr.call(item) == ‘[object Array]’ ? arr = arr.concat(item.flatten()): arr.push(item);

})

}

事件冒泡与事件捕获


对于了解事件冒泡和事件捕获,其实就是事件流的一个接收事件顺序,而事件流描述的就是从页面中去接收事件的顺序

事件流分为三类:

  • 事件冒泡流:从内到外进行事件的捕获 (IE事件流)

  • 事件捕获流:从外到内进行事件的捕获(NetScape事件流)

  • DOM事件流:事件捕获阶段——目标——事件冒泡阶段

对于这里需要去加一个问题进行讨论,也是在面试中可能被问道的问题

IE和DOM事件流之间的区别:

  1. 执行顺序不一样

  2. 事件参数和this指向不一样

  3. 事件加不加on

ajax


是一种用于创建快速动态网页的技术,通过在后台与服务器进行少量数据交换,ajax可以使网页实现异步更新,可以在不重新加载整个页面的情况下,对页面的某个部分进行更新。

以下的部分是ajax原理实现过程

  • XMLHttpRequest对象

当前现代浏览器中均支持XMLHttpRequest对象(IE5和IE6使用ActiveXObject),因此为了应对所有的浏览器,包括(IE5和IE6),则在创建xmlhttp时,需要通过下面的这种方式来创建

var xmlHttp;

if(window.XMLHttpRequest){

xmlHttp = new XMLHttpRequest();

}else{

xmlHttp = new ActiveXObject(“Microsoft.XMlHTTP”);

}

当创建好xmlHttp之后,如果需要将请求放到服务器,需要使用XMLHttpRequest对象的open()和send()方法

对于get和post方法,在使用时的情况是不一样的,大多数的情况下都可以使用get请求,但是在下面的情况中使用post请求

  1. 无法使用缓存文件(更新服务器上的文件或数据库中的文件时)

  2. 向服务器发送大量数据(post没有数据量的限制)

  3. 发送包含未知字符的用户输入时,post比get更稳定也更加的可靠

如果需要通过GET方法发送信息,并且向URl添加信息:

xmlhttp.open(“GET”,“demo_get2.asp?fname=Bill&lname=Gates”,true);

xmlhttp.send();

如果需要通过POST那样传送数据,还需要对传入的数据做设置,因此会设置请求头,如下所示:

setRequestHeader()来添加HTTP头

xmlhttp.open(“POST”,“ajax_test.asp”,true);

xmlhttp.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);

xmlhttp.send(“fname=Bill&lname=Gates”);

  • 说到这里需要停顿以下,这里GET和POST请求是什么呢?

这个是应用层中http请求中的两种前后台数据交互的一种方式,在现如今的都是采用这种数据交互方式来实现前后端的交互,这样做的目的是为了前后端的分离,这样做的好处很多如上面所说的加载数据时,只需要更新一部分的内容即可,另外在开发时间上只要前后端做好数据规范,能做到前后端同时进行开发,大大减少开发项目的周期,另外在项目的可维护性上也有很大程度上的帮助等。在这里所涉及到的http协议部分,也是我们前端所需要了解的部分,这部分会在下面的网络部分进行讲解

  • 上面的部分是将前端的数据发送给服务器,那么对于服务器返回的数据应该怎样处理呢?

这时就要用到onreadystatechange事件,当请求被发送到服务器时,需要执行一些基于响应的任务,每当readtState改变时,就会触发onreadystatechange事件。readyState属性存在XMLHttpRequest的状态信息。因此在这里就有关于XMLHttpRequest对象的属性

| 属性 | 描述 |

| — | :-: |

| onreadystatechange | 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。 |

| readyState | 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。0:请求未初始化1: 服务器连接已建立2: 请求已接收3: 请求处理中 4: 请求已完成,且响应已就绪 |

| status | 200: “OK”,404: 未找到页面 |

当服务器响应已经做好被处理的准备时,即就有以下的部分

xmlhttp.onreadystatechange=function()

{

if (xmlhttp.readyState == 4 && xmlhttp.status == 200)

{

document.getElementById(“myDiv”).innerHTML=xmlhttp.responseText;

}

}

在上面的代码中if部分就是表示服务器已经准备好了的描述过程,document.getElementById(“myDiv”).innerHTML=xmlhttp.responseText;中的responseText

表示服务器返回给前端的数据。上面的所有部分就是ajax整个原理的过程,在jq中也有封装好的ajax技术参考https://www.w3school.com.cn/jquery/jquery_ajax_get_post.asp,又或者在react或者是vue中(其依赖包axios,在npm官网上可以查看其用法)

js继承实现方式:


  • 原型链继承

function Person(name, age){

this.name = name;

this.age = age;

}

function Student(school){

this.school = school;

}

Student.prototype = new Person();

const student = new Student();

原型链继承缺点:多个实例对引用类型的操作会被篡改

  • 构造函数继承

function Car(name, color, size){

this.name = name;

this.color = color;

this.size = size;

}

function Baoma(name, color, size, model){

Car.call(this, name, color, size);

this.model = model;

}

利用call方法,来实现继承

缺点:

  1. 只能继承父类的实例属性和方法,不能继承原型属性/方法

  2. 无法实现复用,每个子类都有父类实例函数的副本,影响性能

  • 组合函数继承

用原型链实现对原型属性和方法的继承,用构造函数来实现实例属性的继承

function Animal(type, size, food){

this.type = type;

this.size = size;

this.food = food;

}

Animal.prototype.sayName = funciton(){

console.log(this.name);

}

function Dog(type, size, food, age){

Animal.call(this, type, size, food);

this.age = age;

}

Dog.prototype = new Animal();

缺点:在使用子类创建实例对象时,其原型中会存在两份相同的属性/方法

  • 原型式继承

利用一个空对象作为中介,将某个对象直接复制给空对象构造函数的原型

function object(obj){

function F(){};

F.prototype = obj;

return new F();

}

即object()对传入其中的对象执行了一次浅复制,将构造函数F的原型直接指向传入的对象。

缺点:

  1. 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能

  2. 无法传递参数

  • 圣杯模式继承(寄生组合式继承)

这样实现的方式好处在于,当改变继承对象的属性时,并不会更改父类的原型

var inherit = (function(){

var F = function(){};

return function(Target, Origin){

F.prototype = Origin.prototype;

Target.prototype = new F();

Target.prototype.constructor = Target;

Target.prototype.uper = Origin.prototype;

}

})()

也可以使用下面的方式来实现,,借用构造函数传递参数和寄生模式实现继承

function inheritPrototype(target, origin){

var prototype = Object.create(origin.prototype);

prototype.constructor = target;

target.prototype = prototype;

}

  • 使用es6中的extends

图片懒加载与预加载


对于图片的懒加载和预加载可参考博客https://juejin.im/post/5b0c3b53f265da09253cbed0

  • 懒加载:也叫延迟加载,指的是在长网页中延迟加载图想,是一种很好优化网页性能的方式

优点:

  1. 能提升用户的体验

  2. 减少无效资源的加载

  3. 方式并发加载的资源过多会阻塞js的加载

  • 预加载:将所有所需资源提前请求加载到本地,之后再取用时,就直接从缓存中拿资源,具体原理以及实现方式参照上述博客

浏览器部分

======================================================================

浏览器中的缓存


cookie、sessionStorage和localstorage之间的区别

  • sessionStorage: 在sessionStorage中的数据,只能在同一个会话页面才能访问,并且当会话结束后数据也会随之销毁,因此其是一个会话级别的存储。

  • localStorage: 用于持久化的本地存储,除非主动删除数据,否则数据用于不会过期

  • cookie: cookie的作用是与服务器进行交互,作为http规范的一部分而存在,记录客户端的用户信息,其大小限制在4KB左右

  • sessionStorage和localStorage的大小大概为5M左右

浏览器缓存机制


对于缓存其存在的意义在于可以加快相应事件,提高用户的体验,对于一般的html文件,浏览器会自动访问,对于ajax请求所发送的数据,有时也需要缓存,需要注意的是post请求浏览器是不会进行缓存的。

  • http状态码304

该状态码代表的意思是服务器不会给我们数据,因此当前浏览器中有缓存的数据,此状态码代表使用缓存,当浏览器看到此状态码就应该去拿缓存中的数据

  • 浏览器中缓存方式
  1. 协商缓存:根据前后台状态来判定是否要进行缓存

ETags和If-None-Match

  • ETags是响应头中的内容,If-None-Match是请求头中内容,首次请求结束后会将ETags设置在If-None-Match中,第二次请求时,则会将ETags传输到服务器中

对比ETags如果相同(表示两次请求的内容相同),则服务器会返回304状态码,这时浏览器应该取缓存中的数据

last-Modified和If-Modified-since

  • last-Modified是响应头中的内容,If-Modified-since是请求头中的内容,其发生的过程与上面的类似,如果对比两次结果相同,这时服务器就会返回304状态码

  • 强制缓存:强制设定缓存数据的存储时间,一到时间就清空缓存数据

  1. Cache-control: 请求头部和响应头部都可以包含该字段,此字段是用来设置浏览器缓存的保留时间,可设置为以下值:

  2. no-Cache: 不缓存

  3. no-Store: 用于防止重要的信息被无意的发布

  4. max-age: 指示客户机可以接收生存期不大于指定时间的响应

  5. min-fresh:指示客户机可接收响应时间小于当前时间加上指定时间的响应

  6. max-stale: 指示客户机可以接收超出超时间的响应时间

  7. Expires: 内容保质器,若其和max-age同在则会被覆盖掉,其参数值设定时,可直接设置时间

浏览器内核


  • 浏览器内核主要有以下部分组成

  • 渲染引擎

  • js引擎

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

前15.PNG

前16.PNG

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容,详细完整版的JavaScript面试题文档,或更多前端资料可以点此处免费获取

缓存:根据前后台状态来判定是否要进行缓存

ETags和If-None-Match

  • ETags是响应头中的内容,If-None-Match是请求头中内容,首次请求结束后会将ETags设置在If-None-Match中,第二次请求时,则会将ETags传输到服务器中

对比ETags如果相同(表示两次请求的内容相同),则服务器会返回304状态码,这时浏览器应该取缓存中的数据

last-Modified和If-Modified-since

  • last-Modified是响应头中的内容,If-Modified-since是请求头中的内容,其发生的过程与上面的类似,如果对比两次结果相同,这时服务器就会返回304状态码

  • 强制缓存:强制设定缓存数据的存储时间,一到时间就清空缓存数据

  1. Cache-control: 请求头部和响应头部都可以包含该字段,此字段是用来设置浏览器缓存的保留时间,可设置为以下值:

  2. no-Cache: 不缓存

  3. no-Store: 用于防止重要的信息被无意的发布

  4. max-age: 指示客户机可以接收生存期不大于指定时间的响应

  5. min-fresh:指示客户机可接收响应时间小于当前时间加上指定时间的响应

  6. max-stale: 指示客户机可以接收超出超时间的响应时间

  7. Expires: 内容保质器,若其和max-age同在则会被覆盖掉,其参数值设定时,可直接设置时间

浏览器内核


  • 浏览器内核主要有以下部分组成

  • 渲染引擎

  • js引擎

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-lxtoLfwF-1713729591078)]

[外链图片转存中…(img-IsHuvTNv-1713729591078)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-ayqv7g3P-1713729591078)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-SqA3NgVv-1713729591079)]

最后

[外链图片转存中…(img-kmkxrf6T-1713729591079)]

[外链图片转存中…(img-ZaA02YJh-1713729591079)]

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容,详细完整版的JavaScript面试题文档,或更多前端资料可以点此处免费获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值