来,帮你夯实下前端基础

255 阅读9分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1、模块化发展历程

模块化方案全称适用范围
CJSCommonJSNode 端
AMDAsync Module Definition浏览器
CMDCommon Module Definition浏览器
UMDUniversal Module DefinitionNode 端和浏览器
ESMES ModuleNode 端和浏览器

可从AMD、CMD、CommonJS、UMD、ES Module 这几个角度考虑。

模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。

AMD: 使用requireJS 来编写模块化,特点:依赖必须提前声明好

define('./index.js',function(code){
    // code 就是index.js 返回的内容
})

CMD: 使用seaJS 来编写模块化,特点:支持动态引入依赖文件

define(function(require, exports, module) {  
  var indexCode = require('./index.js');
})

UMD:兼容AMDCommonJS 模块化语法。

其中 AMDCMDUMD 都已经属于有点过去式的模块化方案了,在新的业务里,结合各种编译工具,可以直接用最新的 ESM 方案来实现模块化。

CommonJSnodejs 中自带的模块化。原本是服务端的模块化标准(设计之初也叫 ServerJS ),是为 JavaScript 设计的用于浏览器之外的一个模块化方案, Node 默认支持了该规范,在 Node 12 之前也只支持 CJS ,但从 Node 12 开始,已经同时支持 ES Module 的使用

var fs = require('fs');

ES Modules: ES6 引入的模块化,支持import 来引入另一个 js 。
ESM 使用 export default (默认导出)和 export (命名导出)这两个语法导出模块,和 CJS 一样, ESM 也可以导出任意合法的 JavaScript 类型,例如:字符串、布尔值、对象、数组、函数等等。 使用 import ... from ... 导入模块,在导入的时候,如果文件扩展名是 .js 则可以省略文件名后缀,否则需要把扩展名也完整写出来。

import a from 'a';

2、什么是防抖和节流?有什么区别?如何实现?

防抖

触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
解题思路 : 每次触发事件时都取消之前的延时调用方法

 function  debounce(func, delay) {
     let timer = null;// 创建一个标记用来存放定时器的返回值
     return function(...args) {
       timer && clearTimeout(timer) // 清除定时器(存在时)
       timer = setTimeout(() => { // 创建一个新的定时器, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
         func.apply(this, args)
       }, delay)
     }
   },
 function sayHi() {
      console.log('防抖成功');
    }
    var inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(sayHi)); // 防抖

节流

高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。
解题思路 : 每次触发事件时都判断当前是否有等待执行的延时函数

function throttle(fn) {
      let runTime = true; 
      return function () {
        if (!runTime) return; 
        runTime = false; 
        setTimeout(() => {
          fn.apply(this, arguments);
          runTime = true;
        }, 500);
      };
    }
    function sayHi(e) {
      console.log(e.target.innerWidth, e.target.innerHeight);
    }
    window.addEventListener('resize', throttle(sayHi));

3、meta viewport

 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

width:控制 viewport 的大小,可以指定的一个值,如 600,或者特殊的值,如 device-width 为设备的宽度(单位为缩放为 100% 时的 CSS 的像素)。
height:和 width 相对应,指定高度。
initial-scale:初始缩放比例,也即是当页面第一次 load 的时候缩放比例。
maximum-scale:允许用户缩放到的最大比例。
minimum-scale:允许用户缩放到的最小比例。
user-scalable:用户是否可以手动缩放

4、Cookie、sessionStorage、localStorage的区别

共同点:都是保存在浏览器端,并且是同源的

  • Cookie:cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下,存储的大小很小只有4K左右。 (tip:可以在浏览器和服务器端来回传递,存储容量小,只有大约4K左右,sessionStorage 和 localStorage 虽然也有存储大小的限制,但比 cookie 大得多,可以达到 5M 或更大。)
  • sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持,localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。(key:本身就是一个回话过程,关闭浏览器后消失,session为一个回话,当页面不同即使是同一页面打开两次,也被视为同一次回话)
  • localStorage:localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。(key:同源窗口都会共享,并且不会失效,不管窗口或者浏览器关闭与否都会始终生效)

备注:(做私有定制)

  • 保存用户登录状态。例如将用户id存储于一个cookie内,这样当用户下次访问该页面时就不需要重新登录了,现在很多论坛和社区都提供这样的功能。 cookie还可以设置过期时间,当超过时间期限后,cookie就会自动消失。因此,系统往往可以提示用户保持登录状态的时间:常见选项有一周、一个月、三个月等。
  • 跟踪用户行为。例如一个天气预报网站,能够根据用户选择的地区显示当地的天气情况。如果每次都需要选择所在地是烦琐的,当利用了 cookie后就会显得很人性化了,系统能够记住上一次访问的地区,当下次再打开该页面时,它就会自动显示上次用户所在地区的天气情况。因为一切都是在后 台完成,所以这样的页面就像为某个用户所定制的一样,使用起来非常方便
  • 定制页面。如果网站提供了换肤或更换布局的功能,那么可以使用cookie来记录用户的选项,例如:背景色、分辨率等。当用户下次访问时,仍然可以保存上一次访问的界面风格。

5、数组扁平化

二维数组时,可以简单使用flat()方法

let arr = [[1,2],[3,4],[5,6]];
let arr = [[1,2],[3,4],[5,6]].flat();
console.log(arr); // [1,2,3,4,5,6]

如果是多维数组,则flat()将达不到效果,需要给flat()传一个参数

var newArray = arr.flat([depth])

参数:depth,可选,指定要提取嵌套数组的结构深度,默认值为 1。

let arr = [[1,2],[3,4],[5,6]].flat(Infinity);
console.log(arr); // [1,2,3,4,5,6]

迭代实现 (ES6扩展运算符…)

const arr = [1,2,[3,4,5,[6,7],8],9,10,[11,[12,13]]];
const flatten = (arr) => {
while(arr.some(item=>Array.isArray(item))){
arr=[].concat(…arr);
}
return arr;
}
console.log(flatten(arr)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

递归实现

const arr = [1,2,[3,4,5,[6,7],8],9,10,[11,[12,13]]];
const flatten = (arr) => {
let result = [];
arr.forEach((item, i, arr) => {
if (Array.isArray(item)) {
result = result.concat(flatten(item));
} else {
result.push(arr[i])
}
})
return result;
};
console.log(flatten(arr));// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

concat + apply实现

const arr = [1,2,[3,4,5,[6,7],8],9,10,[11,[12,13]]];

const flatten = (arr) => {
while (arr.some(item => Array.isArray(item))){
arr = [].concat.apply([], arr);
}
return arr;
}

console.log(flatten(arr));// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

7、while和if的区别

while语句属于循环语句,如果条件为true,则会继续执行,直到false为止,即会进行多次判断(除非一开始条件就是错的)。
if语句属于条件判断语句,如果条件是true,则继续执行,为false则跳出语句不执行,只会进行单次判断。
whileif语句的最大的相同点是都有至少一步的判断。
最大的不同点是:if语句运行完毕后,接着运行下面的语句。而while中的执行语句运行完毕后,还要进行继续判断条件是否符合循环条件,根据判断的条件,返回执行语句或继续运行下面的程序。

8、computed和watch的区别?

计算属性computed :

  • 支持缓存,只有依赖数据发生改变,才会重新进行计算
  • 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
  • computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者 父组件传递的props中的数据通过计算得到的值
  • 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
  • 如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中 的,属性都有一个get和一个set方法,当数据变化时,调用set方法。

侦听属性watch:

  • 不支持缓存,数据变,直接会触发相应的操作;
  • watch支持异步;
  • 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
  • 当一个属性发生变化时,需要执行对应的操作;一对多;
  • 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数。immediate:组件加载立即触发回调函数执行;deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。

:当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。这是watchcomputed最大的区别。

end(持续更新中。。。)