小宋爱睡觉 小宋爱睡觉
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
首页
  • HTML
  • CSS
  • JavaScript
  • Vue
  • React
  • 计算机网络
  • 浏览器原理
  • 性能优化
  • 设计模式
手写系列
  • 字符串
  • 数组
  • 链表
  • 树
  • 动态规划
  • 排序算法
  • GitHub (opens new window)
  • JueJin (opens new window)
  • 数据类型
  • ES6
  • JS基础
    • map和object的区别
    • map和weakMap、 set和weakSet区别
    • var / let 未定义时报什么错?为什么错误不一样
    • 常见的正则表达式
    • 介绍一下js脚本延迟加载的方式
    • 常见的类数组转数组方法
    • 什么是DOM和BOM
    • ES6模块和CommonJS模块的异同
    • export和module.export的区别
    • 还了解AMD和CMD吗
    • AMD 和 CMD 规范的区别?
    • 谈谈对模块化开发的理解
    • use strict是什么 使用它区别是什么
    • 如何判断一个对象属于某个类
    • 如何用for...of遍历对象
    • offsetWidth/offsetHeight,clientWidth/clientHeight与scrollWidth/scrollHeight的区别
    • web开发中会话跟踪的方法有哪些
    • javascript 代码中的"use strict";是什么意思
    • JSON 的了解
    • 什么是面向对象编程及面向过程编程,它们的异同和优缺点
    • 谈一谈你理解的函数式编程
    • 异步编程的实现方式
    • 区分什么是“客户区坐标”、“页面坐标”、“屏幕坐标”
    • 如何删除一个cookie
    • encodeURI()、encodeURIComponent()区别及使用场景
    • 页面编码和被请求的资源编码如果不一致如何处理
  • 执行上下文/ 闭包/ 作用域链
  • 原型和原型链
  • 情景题
  • JavaScript
Crucials
2021-11-28

JS基础

# Javascript基础

# map和object的区别重要

map object
意外的键 默认不包含任何键 在原型上可能有与自己冲突的键
键的类型 可以是任何类型 包括函数 对象 任何基本类型 必须是String 或 Symbol
size 可以通过size属性获取 手动计算
迭代 是iterable 可以直接迭代 需要获取键再进行迭代
性能 在频繁增删表现较好 频繁增删没有优化

# map和weakMap、 set和weakSet区别

  1. Set
    • 成员唯一、无序且不重复
    • [value, value],键值与键名是一致的(或者说只有键值,没有键名)
    • 可以遍历,方法有:add、delete、has
  2. WeakSet
    • 成员都是对象
    • 成员都是弱引用,可以被垃圾回收机制回收,可以用来保存DOM节点,不容易造成内存泄漏
    • 不能遍历,方法有add、delete、has
  3. Map
    • 本质上是键值对的集合,类似集合
    • 可以遍历,方法很多可以跟各种数据格式转换
  4. WeakMap
    • 只接受对象作为键名(null除外),不接受其他类型的值作为键名
    • 键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的(也就是说 一旦不需要 weakmap里面的键名对象和所对应的键值会自动消失 不用手动删除引用)
    • 不能遍历,方法有get、set、has、delete

# var / let 未定义时报什么错?为什么错误不一样

声明方式 报错或输出 解释
var undefined var 声明会被提升(hoisting),变量存在但值是 undefined。
let/const ReferenceError: Cannot access 'a' before initialization let/const也会被提升,但存在暂时性死区(TDZ),不能访问。
未声明变量 ReferenceError: a is not defined 真正没有声明变量时访问,会直接报 ReferenceError。

# 常见的正则表达式

// (1)匹配 16 进制颜色值
var regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;

// (2)匹配日期,如 yyyy-mm-dd 格式
var regex = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;

// (3)匹配 qq 号
var regex = /^[1-9][0-9]{4,10}$/g;

// (4)手机号码正则
var regex = /^1[34578]\d{9}$/g;

// (5)用户名正则
var regex = /^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 介绍一下js脚本延迟加载的方式特别重要

  • defer属性:让脚本加载和文档的解析同步进行 在文档解析完成再执行 使页面的渲染不被阻塞,多个设置defer会按顺序执行

  • async属性:解析顺序同defer属性一样 但是多个设置了async属性的脚本谁先加载完谁先执行 没有顺序 ,而且不会等文档解析完再执行,容易造成阻塞

  • 动态创建DOM:对文档的加载事件进行监听 当文档加载完成再动态创建script引入脚本

  • 使用setTimeout

  • 让js最后加载:把js脚本放在文档最底部

# 常见的类数组转数组方法

Array.prototype.slice.call(arrayLike);

Array.prototype.splice.call(arrayLike, 0);

Array.prototype.concat.apply([], arrayLike);

Array.from(arrayLike);
1
2
3
4
5
6
7

# 什么是DOM和BOM

  • dom是文档对象类型 将文档当做一个对象 主要处理网页内容的方法和接口

  • bom是指浏览器对象模型 将浏览器当成一个对象 定义了与浏览器进行交互的方法和接口 BOM的核心对象是window 而window既是通过js访问浏览器窗口的接口 又是一个global对象,存在location navigator screen对象等,最根本的是document对象

# ES6模块和CommonJS模块的异同特别重要

  • commonjs的语法是同步的(只有加载完成,才能执行后面的操作) 不适用于浏览器是因为一些文件放在服务器或CDN上,用同步导入可能时间很长

  • commonjs是对模块的浅拷贝 es6模块是对模块的引用 换句话说 就是es6只存只读 不改变他的值(指针指向不变)import的接口是readonly,不修改其变量的值

  • commonjs是运行时加载 es6模块是编译是输出接口

    • 意思就是CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
  • 加载机制不同 commonjs遇到循环依赖只会输出已经执行的那部分 后续的输出是不会影响已经输出的变量 而es6的import加载一个变量 变量不会被缓存 真正取值的时候才能取到最终的值

  • 模块顶层this的指向问题 cmj指向当前模块 es6指向undefined

  • 两个模块相互引用 es6指向加载cmj cmj不能require es6模块

# export和module.export的区别重要

// 基本实现
var module = {
  exports: {} // exports 就是个空对象
}
// 这个是为什么 exports 和 module.exports 用法相似的原因
var exports = module.exports
var load = function (module) {
    // 导出的东西
    var a = 1
    module.exports = a
    return module.exports
};
1
2
3
4
5
6
7
8
9
10
11
12

其实就是export -> 内存 <- module.export

理论上最后导出的还是module.export 如果exports重新赋值,那就是指向另外的对象

// 🌰
// m1.js
// 1. 正确
module.exports = {
    name: 'crucials',
    sex: 'boy'
}

// 2. 正确
exports.name = 'crucials';
exports.sex = 'boy'

// 3. 正确
module.exports.name = 'crucials';
module.exports.sex = 'boy'

// 4. 无效
exports = {
    name: 'crucials',
    sex: 'boy'
}
//可以看到

// exports.name = xxx是module.exports.name = xxx的缩写。
// exports = {}确不是module.exports = {}的缩写。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 还了解AMD和CMD吗重要

  • AMD 方案,这种方案采用异步加载的方式来加载模块,模块的加载不影响后面语句的执行,所有依赖这个模块的语句都定义在一个回调函数里,等到加载完成后再执行回调函数。require.js 实现了 AMD 规范

  • CMD 方案,这种方案和 AMD 方案都是为了解决异步模块加载的问题,sea.js 实现了 CMD 规范。它和require.js的区别在于模块定义时对依赖的处理不同和对依赖模块的执行时机的处理不同。

# AMD 和 CMD 规范的区别?重要

  • 第一个方面是在模块定义时对依赖的处理不同。AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块。而 CMD 推崇就近依赖,只有在用到某个模块的时候再去 require。
  • 第二个方面是对依赖模块的执行时机处理不同。首先 AMD 和 CMD 对于模块的加载方式都是异步加载,不过它们的区别在于模块的执行时机,AMD 在依赖模块加载完成后就直接执行依赖模块,依赖模块的执行顺序和我们书写的顺序不一定一致。而 CMD在依赖模块加载完成后并不执行,只是下载而已,等到所有的依赖模块都加载好后,进入回调函数逻辑,遇到 require 语句的时候才执行对应的模块,这样模块的执行顺序就和我们书写的顺序保持一致了。
// AMD 默认推荐
define(["./a", "./b"], function(a, b) {
  // 依赖必须一开始就写好
  a.doSomething();
  // 此处略去 100 行
  b.doSomething();
  // ...
})

// CMD
define(function(require, exports, module) {
  var a = require("./a");
  a.doSomething();
  // 此处略去 100 行
  var b = require("./b"); // 依赖可以就近书写
  b.doSomething();
  // ...
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • AMD:requirejs 在推广过程中对模块定义的规范化产出,提前执行,推崇依赖前置
  • CMD:seajs 在推广过程中对模块定义的规范化产出,延迟执行,推崇依赖就近
  • CommonJs:模块输出的是一个值的 copy,运行时加载,加载的是一个对象(module.exports 属性),该对象只有在脚本运行完才会生成
  • ES6 Module:模块输出的是一个值的引用,编译时输出接口,ES6模块不是对象,它对外接口只是一种静态定义,在代码静态解析阶段就会生成

# 谈谈对模块化开发的理解加分

我对模块的理解是,一个模块是实现一个特定功能的一组方法。在最开始的时候,js 只实现一些简单的功能,所以并没有模块的概念,但随着程序越来越复杂,代码的模块化开发变得越来越重要。

由于函数具有独立作用域的特点,最原始的写法是使用函数来作为模块,几个函数作为一个模块,但是这种方式容易造成全局变量的污染,并且模块间没有联系。

后面提出了对象写法,通过将函数作为一个对象的方法来实现,这样解决了直接使用函数作为模块的一些缺点,但是这种办法会暴露所有的所有的模块成员,外部代码可以修改内部属性的值。

现在最常用的是 立即执行函数 的写法,通过利用闭包来实现模块私有作用域的建立,同时不会对全局作用域造成污染

var module1 = (function(){
    var _count = 0;
    var m1 = function(){
      //...
    };
    var m2 = function(){
      //...
    };
    return {
      m1 : m1,
      m2 : m2
    };
})();
1
2
3
4
5
6
7
8
9
10
11
12
13

# use strict是什么 使用它区别是什么

是es5一种运行模式 使js在更严格的条件下运行

目的:

  • 消除js语法的不合理 不严谨的地方

  • 保证代码运行的安全

  • 提高编译器效率,提高运行速度

区别:

  • 禁止使用with语句

  • 禁止this指向全局对象

  • 对象不能有重名

# 如何判断一个对象属于某个类

  • 使用instanceof 判断构造函数的prototype是否出现在原型链的任何位置

  • 通过constructor属性 但是constructor可以被改写 不安全

  • 使用Object.prototype.toString() 方法来打印对象的[[Class]]属性来进行判断

# 如何用for...of遍历对象重要

const obj = {
  a: 1,
  b: 2,
  c: 3
}

for(let i of obj) {
	console.log(i)
}
// obj is not iterable
// 法一
const obj = {
  a: 1,
  b: 2,
  c: 3
}

obj[Symbol.iterator] = function() {
  const keys = Object.keys(this)
	var count = 0
  return {
    next() {
  		if(count < keys.length) {
      	return {value: obj[keys[count++]], done: false}
      } else {
      	return {value: undefined, done: true}
      }
  	}
  }
}

for(let i of obj) {
	console.log(i)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# offsetWidth/offsetHeight,clientWidth/clientHeight与scrollWidth/scrollHeight的区别

  • offsetWidth/offsetHeight返回值包含 content + padding + border ,效果与e.getBoundingClientRect()相同
  • clientWidth/clientHeight返回值只包含 content + padding ,如果有滚动条,也不包含滚动条
  • scrollWidth/scrollHeight返回值包含 content + padding + 溢出内容的尺寸

# web开发中会话跟踪的方法有哪些

  • cookie
  • session
  • url重写
  • 隐藏input
  • ip地址

# javascript 代码中的"use strict";是什么意思

  • use strict是一种ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严格的条件下运行,使JS编码更加规范化的模式,消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为

    • 变量必须声明后再使用

    • 函数的参数不能有同名属性,否则报错

    • 不能使用with语句

    • 不能对只读属性赋值,否则报错

    • 不能使用前缀0表示八进制数,否则报错

    • 不能删除不可删除的属性,否则报错

    • 不能删除变量delete prop,会报错,只能删除属性delete global[prop]

    • eval不会在它的外层作用域引入变量

    • eval和arguments不能被重新赋值

    • arguments不会自动反映函数参数的变化

    • 不能使用arguments.callee

    • 不能使用arguments.caller

    • 禁止this指向全局对象

    • 不能使用fn.caller和fn.arguments获取函数调用的堆栈

    • 增加了保留字(比如protected、static和interface)

# JSON 的了解

  • JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式
  • 它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小
  • JSON字符串转换为JSON对象:
var obj =eval('('+ str +')');
var obj = str.parseJSON();
var obj = JSON.parse(str);
1
2
3
  • JSON对象转换为JSON字符串:
var last=obj.toJSONString();
var last=JSON.stringify(obj);
1
2

# 什么是面向对象编程及面向过程编程,它们的异同和优缺点

  • 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了
  • 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为
  • 面向对象是以功能来划分问题,而不是步骤

# 谈一谈你理解的函数式编程

  • 简单说,"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论
  • 它具有以下特性:闭包和高阶函数、惰性计算、递归、函数是"第一等公民"、只用"表达式"

# 异步编程的实现方式

  • 回调函数
    • 优点:简单、容易理解
    • 缺点:不利于维护,代码耦合高
  • 事件监听(采用时间驱动模式,取决于某个事件是否发生):
    • 优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数
    • 缺点:事件驱动型,流程不够清晰
  • 发布/订阅(观察者模式)
    • 类似于事件监听,但是可以通过‘消息中心’,了解现在有多少发布者,多少订阅者
  • Promise对象
    • 优点:可以利用then方法,进行链式写法;可以书写错误时的回调函数;
    • 缺点:编写和理解,相对比较难
  • Generator函数
    • 优点:函数体内外的数据交换、错误处理机制
    • 缺点:流程管理不方便
  • async函数
    • 优点:内置执行器、更好的语义、更广的适用性、返回的是Promise、结构清晰。
    • 缺点:错误处理机制

# 区分什么是“客户区坐标”、“页面坐标”、“屏幕坐标”

  • 客户区坐标:鼠标指针在可视区中的水平坐标(clientX)和垂直坐标(clientY)
  • 页面坐标:鼠标指针在页面布局中的水平坐标(pageX)和垂直坐标(pageY)
  • 屏幕坐标:设备物理屏幕的水平坐标(screenX)和垂直坐标(screenY)

# 如何删除一个cookie

  • 将时间设为当前时间往前一点
var date = new Date();

date.setDate(date.getDate() - 1);//真正的删除
1
2
3

setDate()方法用于设置一个月的某一天

  • expires的设置
document.cookie = 'user='+ encodeURIComponent('name')  + ';expires = ' + new Date(0)
1

# encodeURI()、encodeURIComponent()区别及使用场景

encodeURI()

encodeURI()通常用于转码整个 URL,不会对 URL 元字符以及语义字符进行转码

URL元字符:分号(;),逗号(,),斜杠(/),问号(?),冒号(:),at(@),&,等号(=),加号(+),美元符号($),井号(#)

语义字符:a-z,A-Z,0-9,连词号(-),下划线(_),点(.),感叹号(!),波浪线(~),星号(*),单引号('),圆括号(())

encodeURIComponent()

encodeURIComponent()通常只用于转码URL组成部分,如URL中?后的一串;

如上面的expires的设置就是转码URL后面的一串

# 页面编码和被请求的资源编码如果不一致如何处理

  • 后端响应头设置 charset
  • 前端页面<meta>设置 charset
上次更新: 2025/06/08, 23:39:58
ES6
执行上下文/ 闭包/ 作用域链

← ES6 执行上下文/ 闭包/ 作用域链→

Copyright © 2021-2025 粤ICP备2021165371号
  • 跟随系统
  • 浅色模式
  • 深色模式