「2023」前端面试知识点复盘——JS篇

写在前面

哈喽,小伙伴们,我是泽南👨‍🎓。近期我会整理一系列针对前端面试的知识点供大家复习,不管你是准备跳槽还是正在面试,都赶快来恶补一下~

本系列文章主要以知识总结为主,不是面试题哈,主要目的是方便自己复习以及为大家提供便利,所以大部分知识点来源于网上,侵权联系删除。如有不对的地方欢迎大家评论区批评指正,一起进步!

此系列会陆续更新如下文章:

「2023」前端面试知识点复盘------浏览器篇

「2023」前端面试知识点复盘------计算机网络篇

「2023」前端面试知识点复盘------JS篇

「2023」前端面试知识点复盘------CSS篇(整理中。。。)

「2023」前端面试知识点复盘------React篇(整理中。。。)

「2023」前端面试知识点复盘------工程化篇(整理中。。。)

介绍JS的基本数据类型

stringnumberbooleanundefinednull

介绍JS有哪些内置对象

  • 数据封装类对象 : StringNumberBooleanArrayObject
  • 其他对象 : FunctionMathDateErrorArgumentsRegExp

宿主对象和原生对象的区别

  • 原生对象(native object)是由ECMAScript规范定义的JavaScript内置对象,如 String、 Number 、Boolean 、Array 、Object 、Function 、Math 、Date 、Error 、Arguments 、RegExp等。
  • 宿主对象(host object)是由运行时的环境(浏览器或node)决定的,如window、XMLHTTPRequest等。

null、undefined及未声明变量之间的区别。如何区分?

  • 未声明变量默认值为undefined
  • typeof null === 'object' // true
  • typeof undefined === 'undefined' // true

==和===的区别

  • ==比较之前会先进行类型转换,即不会对类型进行比较。例如:

    ini 复制代码
      12 == '12'  // true
      true == 1   // true
      false == '0' // true
  • ===会比较数值和类型。例如:

    ini 复制代码
      12 === '12' // false
      12 === 12 // true
      true === 1 // false
      false === '0' // false

JS隐式转换及应用场景

JS在使用运算符号或者对比符时,会自带隐式转换,规则如下:

  • -、*、/、% :一律转换成数值后计算

  • +

    • 数字 + 字符串 = 字符串, 运算顺序是从左到右
    • 数字 + 对象, 优先调用对象的valueOf -> toString
    • 数字 + boolean/null -> 数字
    • 数字 + undefined -> NaN
  • [1].toString() === '1'

  • {}.toString() === '[object object]'

  • NaN !== NaN 、+undefined 为 NaN

Attribute 和 Property 的区别

Attribute是在HTML中定义的,而property是在DOM上定义的。为了说明区别,假设我们在HTML中有一个文本框:
<input type="text" value="Hello">

javascript 复制代码
const input = document.querySelector('input');
console.log(input.getAttribute('value')); // Hello
console.log(input.value); // Hello

但是在文本框中键入" World!"后:

arduino 复制代码
console.log(input.getAttribute('value')); // Hello
console.log(input.value); // Hello World!

NaN是什么?如何判断是否是NaN类型

  • 定义: 全局属性 NaN 的值表示不是一个数字(Not-A-Number)

  • 如何判断一个值是否是NaN : 等号运算符(== 和 ===) 不能被用来判断一个值是否是 NaN。必须使用 Number.isNaN() 或 isNaN() 函数。

    ini 复制代码
      NaN === NaN;        // false
      Number.NaN === NaN; // false
      isNaN(NaN);         // true
      isNaN(Number.NaN);  // true

如何判断两个对象相等

需要考虑三个问题:

  1. 如果对象的属性值之一本身就是一个对象
  2. 如果属性值中的一个是NaN(在JavaScript中,是不是等于自己唯一的价值?)
  3. 如果一个属性的值为undefined,而另一个对象没有这个属性(因而计算结果为不确定?)

检查对象的 值相等 的一个强大的方法,最好是依靠完善的测试库,涵盖了各种边界情况。Underscore和Lo-Dash有一个名为_.isEqual()方法,用来比较好的处理深度对象的比较。您可以使用它们像这样:

css 复制代码
// Outputs: true
console.log(_.isEqual(obj1, obj2));

什么是'user strict',使用它有什么优缺点?

'use strict' 是用于对整个脚本或单个函数启用严格模式的语句。严格模式是可选择的一个限制 JavaScript 的变体一种方式 。
优点:

  • 无法再意外创建全局变量。
  • 会使引起静默失败(silently fail,即:不报错也没有任何效果)的赋值操抛出异常。
  • 试图删除不可删除的属性时会抛出异常(之前这种操作不会产生任何效果)。
  • 要求函数的参数名唯一。
  • 全局作用域下,this的值为undefined。
  • 捕获了一些常见的编码错误,并抛出异常。
  • 禁用令人困惑或欠佳的功能。

缺点:

  • 缺失许多开发人员已经习惯的功能。
  • 无法访问function.caller和function.arguments。
  • 以不同严格模式编写的脚本合并后可能导致问题。

总的来说,我认为利大于弊,我从来不使用严格模式禁用的功能,因此我推荐使用严格模式。

call,apply和bind的作用是什么?两者区别是什么?

.call.apply都用于调用函数,第一个参数将用作函数内 this 的值。然而,.call接受逗号分隔的参数作为后面的参数,而.apply接受一个参数数组作为后面的参数。一个简单的记忆方法是,从call中的 C 联想到逗号分隔(comma-separated),从apply中的 A 联想到数组(array)。

javascript 复制代码
function add(a, b) {
return a + b;
}

console.log(add.call(null, 1, 2)); // 3
console.log(add.apply(null, [1, 2])); // 3

.call.apply是立即执行的, .bind 返回函数的副本,但带有绑定上下文!它不是立即执行的。

javascript 复制代码
const person = { name: 'Lydia' }

function sayHi(age) {
console.log(`${this.name} is ${age}`)
}

sayHi.call(person, 21)
sayHi.bind(person, 21)

结果: Lydia is 21 function

请说明Function.prototype.bind的用法

摘自MDN:

bind()方法创建一个新的函数, 当被调用时,将其 this 关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

根据我的经验,将this的值绑定到想要传递给其他函数的类的方法中是非常有用的。在 React 组件中经常这样做。

如何判断是否为空数组

javascript 复制代码
var arr = [];
if (Array.isArray(arr) && arr.length === 0) {
    console.log('是空数组');
}
// Array.isArray是ES5提供的,如果不支持。用下面的方案。
if (!Array.isArray) {
    Array.isArray = function(arg) {
        return Object.prototype.toString.call(arg) === '[object Array]';
    };
}

数组方法

  • map: 遍历数组,返回回调返回值组成的新数组
  • forEach: 无法break,可以用try/catch中throw new Error来停止
  • filter: 过滤
  • some: 有一项返回true,则整体为true
  • every: 有一项返回false,则整体为false
  • join: 通过指定连接符生成字符串
  • sort(fn) / reverse: 排序与反转,改变原数组
  • concat: 连接数组,不影响原数组, 浅拷贝
  • slice(start, end): 返回截断后的新数组,不改变原数组
  • splice(start, number, value...): 返回删除元素组成的数组,value 为插入项,改变原数组
  • indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标
  • reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始)

数组乱序:

ini 复制代码
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.sort(function () {
    return Math.random() - 0.5;
});

数组拆解:

javascript 复制代码
// flat: [1,[2,3]] --> [1, 2, 3]

Array.prototype.flat = function() {
    return this.toString().split(',').map(item => +item )
}

push、pop、shift、unshift功能及返回值

  • push:添加新元素到数组末尾,返回数组长度
  • pop:移除数组最后一个元素,返回元素本身
  • unshift:添加新元素到数组开头,返回数组长度
  • shift:移除数组首个元素,返回元素本身

以上4种操作均会改变数组本身

.forEach和.map()循环的主要区别,使用场景举例

map用法:

c 复制代码
let array = [1, 2, 3, 4, 5];
let newArray = array.map((item, i, arr) => {
    return item * 2;
});
console.log("array:", array);       // [1, 2, 3, 4, 5]
console.log("newArray:", newArray); // [2, 4, 6, 8, 10]
// 此处的array接受map方法运算之后的返回值
// 但是map方法并不能改变原来的数组

forEach用法:

javascript 复制代码
let array = [1, 2, 3, 4, 5];
let newArray = array.forEach((item, i, arr) => {
    console.log('item:' + item + ', index:' + i);
    // array[i] = item * 2;    // 可以用这种方式改变原始数组的值
});
console.log("array:", array);       // [1, 2, 3, 4, 5]
console.log("newArray:", newArray); // undefined
// forEach方法没有返回值
  • 能用forEach()做到的,map()同样可以。反过来也是如此。
  • map()会分配内存空间存储新数组并返回,forEach()不会返回数据。
  • forEach()允许callback更改原始数组的元素。map()返回新的数组。

JS执行对象查找时,永远不会去查找原型的函数是哪个?

javascript 复制代码
Object​.prototype​.has​OwnProperty()

如何将arguments转为数组

  1. Array.prototype.slice.call(arguments)
  2. [].slice.call(arguments)

对象的遍历方法

  • for循环

    vbscript 复制代码
      for (let property in obj) {
          console.log(property);
      }

    但是,这还会遍历到它的继承属性,在使用之前,你需要加入obj.hasOwnProperty(property)检查。

  • Object.keys()

    javascript 复制代码
      Object.keys(obj).forEach((property) => { ... })

    Object.keys()方法会返回一个由一个给定对象的自身可枚举属性组成的数组。

  • Object.getOwnPropertyNames()

    javascript 复制代码
      Object.getOwnPropertyNames(obj).forEach((property) => { ... })

    Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组。

数组的遍历方法

  • for loops

    css 复制代码
      for (let i = 0; i < arr.length; i++) { ... }
  • forEach

    less 复制代码
      arr.forEach((item, index, arr) { ... })
  • map

    javascript 复制代码
      arr.map((item, index, arr) => { ... })

匿名函数的典型应用场景

匿名函数可以在 IIFE 中使用,来封装局部作用域内的代码,以便其声明的变量不会暴露到全局作用域。

javascript 复制代码
(function() {
    // 一些代码。
})();

匿名函数可以作为只用一次,不需要在其他地方使用的回调函数。当处理函数在调用它们的程序内部被定义时,代码具有更好地自闭性和可读性,可以省去寻找该处理函数的函数体位置的麻烦。

javascript 复制代码
setTimeout(function() {
    console.log('Hello world!');
}, 1000);

匿名函数可以用于函数式编程或 Lodash(类似于回调函数)。

c 复制代码
const arr = [1, 2, 3];
const double = arr.map(function(el) {
    return el * 2;
});
console.log(double); // [2, 4, 6]

IIFE(立即执行函数)的用法

IIFE(立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。

javascript 复制代码
(function () {
    statements
})();

这是一个被称为 自执行匿名函数 的设计模式,主要包含两部分。第一部分是包围在 圆括号运算符 () 里的一个匿名函数,这个匿名函数拥有独立的词法作用域。这不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域。

第二部分再一次使用 () 创建了一个立即执行函数表达式,JavaScript 引擎到此将直接执行函数。

document的load事件和DOMContentLoaded事件之间的区别

当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表、图像和子框架的完成加载。

window的load事件仅在 DOM所有相关资源全部完成加载后才会触发。

数据类型判断方式有几种

下面将对如下数据进行判断它们的类型

ini 复制代码
var bool = true
var num = 1
var str = 'abc'
var und = undefined
var nul = null
var arr = [1, 2, 3]
var obj = {a: 'aa', b: 'bb'}
var fun = function() {console.log('I am a function')}
  • typeof: 适合基本的数据类型和函数

    javascript 复制代码
      console.log(typeof bool);   // boolean
      console.log(typeof num);    // number
      console.log(typeof str);    // string
      console.log(typeof und);    // undefined
      console.log(typeof nul);    // object
      console.log(typeof arr);    // object
      console.log(typeof obj);    // object
      console.log(typeof fun);    // function

    由结果可知typeof可以测试出number、string、boolean、undefined及function,而对于null及数组、对象,typeof均检测出为object,不能进一步判断它们的类型。

  • instanceof: 判断对象类型,基于原型链去判断。
    obj instanceof Object: 左操作数是一个对象,右操作数是一个函数构造器或者函数对象,判断左边的操作数的原型链_proto_属性是否有右边这个函数对象的proptotype属性。

    javascript 复制代码
      console.log(bool instanceof Boolean);// false
      console.log(num instanceof Number); // false
      console.log(str instanceof String); // false
      console.log(und instanceof Object); // false
      console.log(arr instanceof Array);  // true
      console.log(nul instanceof Object); // false
      console.log(obj instanceof Object); // true
      console.log(fun instanceof Function);// true
    
      var bool2 = new Boolean()
      console.log(bool2 instanceof Boolean);// true
    
      var num2 = new Number()
      console.log(num2 instanceof Number);// true
    
      var str2 = new String()
      console.log(str2 instanceof String);//  true
    
      function Animation(){}
      var ani = new Animation()
      console.log(ani instanceof Animation);// true
    
      function Dog(){}
      Dog.prototype = new Animation()
      var dog = new Dog()
      console.log(dog instanceof Dog);    // true
      console.log(dog instanceof Animation);// true
      console.log(dog instanceof Object); // true

    从结果中看出instanceof不能区别 undefinednull,而且对于基本类型如果不是用new声明的则也测试不出来,对于是使用new声明的类型,它还可以检测出多层继承关系。

  • constructor: 返回对创建此对象的函数的引用

    ini 复制代码
      console.log(bool.constructor === Boolean);  // true
      console.log(num.constructor === Number);    // true
      console.log(str.constructor === String);    // true
      console.log(arr.constructor === Array);     // true
      console.log(obj.constructor === Object);    // true
      console.log(fun.constructor === Function);  // true
    
      console.log(ani.constructor === Animation); // true
      console.log(dog.constructor === Dog);       // false
      console.log(dog.constructor ===  Animation);// true

    null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

    函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失。所以dog.constructor === Animation 而不是 Dog

  • Object.prototype.toString.call

    javascript 复制代码
      console.log(Object.prototype.toString.call(bool));  //[object Boolean]
      console.log(Object.prototype.toString.call(num));   //[object Number]
      console.log(Object.prototype.toString.call(str));   //[object String]
      console.log(Object.prototype.toString.call(und));   //[object Undefined]
      console.log(Object.prototype.toString.call(nul));   //[object Null]
      console.log(Object.prototype.toString.call(arr));   //[object Array]
      console.log(Object.prototype.toString.call(obj));   //[object Object]
      console.log(Object.prototype.toString.call(fun));   //[object Function]
    
      console.log(Object.prototype.toString.call(dog));   //[object Object]  

    原理(摘自高级程序设计3):在任何值上调用 Object 原生的 toString() 方法,都会返回一个 [object NativeConstructorName] 格式的字符串。每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名。

    但是它不能检测非原生构造函数的构造函数名。

  • 使用jquery中的$.type

    javascript 复制代码
      console.log($.type(bool));  //boolean
      console.log($.type(num));   //number
      console.log($.type(str));   //string
      console.log($.type(und));   //undefined
      console.log($.type(nul));   //null
      console.log($.type(arr));   //array
      console.log($.type(obj));   //object
      console.log($.type(fun));   //function
    
      console.log($.type(dog));   //object

    $.type()内部原理就是用的Object.prototype.toString.call()

DOM操作(增删改查)

  • 添加操作

    ini 复制代码
      let element = document.createElement("div");   // 创建元素
      body.appendChild(element);  // 将一个节点添加到指定父节点的子节点列表末尾
  • 删除操作

    csharp 复制代码
      var oldChild = node.removeChild(child); // 删除子元素
      ChildNode.remove() // 删除元素
  • 修改操作

    dart 复制代码
      Node.innerText // 修改元素文本内容
      Element.innerHTML // 设置或获取描述元素后代的HTML语句
  • 查找操作

    scss 复制代码
      Document.getElementById() // 返回对拥有指定 id 的第一个对象的引用
      Document.querySelector() // 返回文档中匹配指定的CSS选择器的第一元素
      Document.querySelectorAll() // 返回与指定的选择器组匹配的文档中的元素列表
  • # 文档对象模型 (DOM)

异步加载JS 的方式有哪些

浏览器下载除JS外的资源时,会并行下载,以提高性能。但下载JS脚本时,会禁止并行下载(称为脚本阻塞Scripts Block Downloads)。浏览器遇到JS时,必须等JS下载,解析,执行完后,才能继续并行下载下一个资源。原因是JS可能会改变页面或改变JS间的依赖关系,例如A.js中用document.write改变页面,B.js依赖于A.js。因此要严格保证顺序,不能并行下载。

由于浏览器在遇到标签前是不会渲染页面的,为了避免白屏,通常的建议是将JS放到标签底下,可以有最佳的用户体验。

按推荐度排序:

  1. 动态创建

    ini 复制代码
     var script = document.createElement('script');  // 创建script标签
     script.type = "text/javascript";
     script.src = "A.js";
     document.getElementsByTagName('head')[0].appendChild(script);   // 塞进页面

    先用document.createElement('script')生成一个script标签,再设置它的src属性,最后将其插入到中。

    script标签被插入到页面的DOM树后,就会开始下载src属性指定的脚本。而且通过动态脚本元素下载脚本是异步的,不会阻塞页面的其他下载和处理过程,因此script标签插入中也没问题。

  2. Script async

    xml 复制代码
     <script type="text/javascript" src="A.js" async></script>

    浏览器解析到HTML里的该行script标签,发现指定为async,会异步下载解析执行脚本。

    async 是HTML5里为script标签新增的属性,对于低版本浏览器会存在兼容性问题。

    它会在下载完成后立刻执行,而不是会等到DOM加载完成之后再执行,所以还是有可能会造成阻塞。

    这种方式只适用于引用外部js文件的

    添加async属性的js文件不应该使用document.write方法。

    对多个带有async的js文件,它不能保证按顺序执行,它是哪个js文件先下载完就先执行哪个。

  3. Script defer

    xml 复制代码
     <script type="text/javascript" src="A.js" defer></script>

    浏览器解析到HTML里的该行script标签,发现指定为defer,会暂缓下载解析执行脚本。而是等到页面加载完毕后,才加载脚本(更精确地说,是在DOM树构建完成后,在window.onload触发前,加载defer的脚本)。

    defer也是只适用于外部js文件,也不能在js中使用document.write方法。

    可以保证多个js文件的执行顺序就是它们在页面中出现的顺序。

document.write和innerHTML有何区别

  • document.write会重绘整个页面,如果不指定元素的话,它会覆盖掉整个页面内容。
  • innerHTML只会重绘页面的一部分。

针对jQuery性能的优化方法

如何判断当前脚本运行在浏览器还是node环境中

通过判断Global对象是否为window,如果不为window,则当前脚本运行在node.js环境中。

ini 复制代码
this === window ? 'browser' : 'node';

JS事件委托、事件冒泡

IE和Firefox的事件机制有何区别,如何阻止冒泡?

  • IE只支持事件冒泡 ,火狐同时支持事件捕获事件冒泡两种。
  • 阻止事件冒泡的方式不同
    IE: e.cancelBubble = true
    W3C: e.stopPropagation()

JS内存空间的管理

  • 基础数据类型与栈内存

    JS中的基础数据类型,这些值都有固定的大小,往往都保存在栈内存中,由系统自动分配存储空间。我们可以直接操作保存在栈内存空间的值,因此基础数据类型都是按值访问。

    数据在栈内存中的存储与使用方式类似于数据结构中的堆栈数据结构,遵循后进先出的原则。

    基础数据类型: Number String Null Undefined Boolean

  • 引用数据类型与堆内存

    与其他语言不同,JS的引用数据类型,比如 数组Array、对象Object、函数Function,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JavaScript不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。

在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。这里的引用,我们可以粗浅地理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联。

总结:

栈内存 堆内存
存储基础数据类型 存储引用数据类型
按值访问 按引用访问
存储的值大小固定 存储的值大小不定,可动态调整
由系统自动分配内存空间 由开发人员通过代码分配
主要用来执行程序 主要用来存放对象
空间小,运行效率高 空间大,但是运行效率相对较低
先进后出,后进先出 无序存储,可根据引用直接获取

JS执行上下文

JS变量对象详解

请解释变量提升

JS作用域及作用域链/闭包(closure),常用场景举例说明

请简述JS中的this

JS函数与函数式编程

JS原型,原型链。实现继承的方式

JS有哪几种创建对象的方式

  1. 利用Object构造函数方式创建
  2. 利用对象字面量方式创建
  3. 利用工厂模式创建
  4. 利用构造函数模式创建
  5. 利用原型方式创建
  6. 利用构造函数和原型的组合模式创建

请解释事件循环,调用堆栈和任务队列的区别

谈谈对Promise的理解

ES6知识点

  1. var let const
  2. =>箭头函数
  3. 模版字符串
  4. 解析结构
  5. 函数默认参数
  6. ...展开运算符
  7. class
  8. Promise

防抖与节流

防抖与节流函数是一种最常用的 高频触发优化方式,能对性能有较大的帮助。

  • 防抖 (debounce) : 将多次高频操作优化为只在最后一次执行,通常使用的场景是:用户输入,只需再输入完成后做一次输入校验即可。

  • 节流(throttle): 每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作,通常使用场景: 滚动条事件 或者resize 事件,通常每隔 100~500 ms执行一次即可。

    scss 复制代码
      function throttle(method, context) {
          clearTimeout(method.tID);
          method.tID = setTimeout(function () {
              method.call(context);
          }, 1000);
      }

    用法:

    javascript 复制代码
      function showTime() {
          console.log("nowDate:" + new Date().toLocaleDateString());
      }
    
      setInterval(function () {
          throttle(showTime);
      }, 2000);

模块化

模块化开发在现代开发中已是必不可少的一部分,它大大提高了项目的可维护、可拓展和可协作性。通常,我们 在浏览器中使用 ES6 的模块化支持,在 Node 中使用 commonjs 的模块化支持。

分类:

  • es6: import / export
  • commonjs: require / module.exports / exports
  • amd: require / defined

require与import的区别

  • require支持 动态导入,import不支持,正在提案 (babel 下可支持)
  • require同步 导入,import属于 异步 导入
  • require值拷贝,导出值变化不会影响导入值;import指向 内存地址,导入值会随导出值而变化

oAuth实现方案

如何实现单点登录(Single Sign On)

请解释SPA(单页应用),优缺点是什么?如何使其对SEO友好

单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。

单页应用SPA 多页应用MPA
组成 一个外壳页面和多个页面片段组成 多个完整页面构成
资源共用(css,js) 共用,只需在外壳部分加载 不共用,每个页面都需要加载
刷新方式 页面局部刷新或更改 整页刷新
url 模式 a.com/#/pageone a.com/#/pagetwo a.com/pageone.html a.com/pagetwo.html
用户体验 页面片段间的切换快,用户体验良好 由于要一次加载所有的资源(html/js),故首屏加载慢 页面切换加载缓慢,流畅度不够,用户体验比较差 首屏加载很快
转场动画 容易实现 无法实现
数据传递 容易 依赖 url传参、或者cookie 、localStorage等
搜索引擎优化(SEO) 需要单独方案、实现较为困难、不利于SEO检索。 Prerender预渲染优化SEO 实现方法简易
试用范围 高要求的体验度、追求界面流畅的应用 适用于追求高度支持搜索引擎的应用
开发成本 较高,常需借助专业的框架 较低,但页面重复代码多
维护成本 相对容易 相对复杂

前端性能优化方案

以下是移动端的优化方案,大部分Web端也同样适用

正则表达式

设计模式举例(实现、应用、优缺点)

前端常用框架对比

相关推荐
一颗花生米。21 分钟前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
学习使我快乐0125 分钟前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio199526 分钟前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
勿语&1 小时前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
黄尚圈圈1 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水2 小时前
简洁之道 - React Hook Form
前端
正小安4 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
小飞猪Jay6 小时前
C++面试速通宝典——13
jvm·c++·面试
_.Switch6 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光6 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js