前段时间刷掘金发现一篇很不错的文章(清单),觉得挺有道理的。有些知识点以前看过后,过段时间后发现又忘了,然后又去查找资料,反反复复 感觉知识点永远不是自己的且学的又比较零散。所以按照 一名【合格】前端工程师的自检清单去完善自己知识体系(根据自身情况稍作调整)。
这里说明下大部分知识点详解都是引用下面链接的,都是很不错的文章,值得去研究,在此感谢各位作者大大了。 如果引用涉及作者版权之类,请私信我,会尽快删掉的。
参考
知识体系
一、JavaScript 基础
变量和类型:
-
JavaScript
规定了几种语言类型?- 基本数据类型:
Number
,Undefined
,Boolean
,String
,Null
,Symbol
,BigInt
- 引用数据类型:
Object
- 基本数据类型和引用类型的区别?
- 基本数据类型:
-
JavaScript
对象的底层数据结构是什么?:HashMap
-
Symbol
类型在实际开发中的应用、可手动实现一个简单的Symbol
-
JavaScript
中的变量在内存中的具体存储形式 -
基本类型对应的内置对象,以及他们之间的装箱拆箱操作
-
理解值类型和引用类型
-
null
和undefined
的区别- undefined 表示根本不存在定义
- null 表示一个值被定义了,定义为“空值”;
-
至少可以说出三种判断
JavaScript
数据类型的方式,以及他们的优缺点,如何准确的判断数组类型 ES6 有个Array.isArray
可以很好的判断是否为数组类型。 判断 JS 数据类型的四种方法:-
typeof
:- 对于基本类型,除
null
以外,均可以返回正确的结果。 - 对于引用类型,除
function
以外,一律返回object
类型。 - 对于
null
,返回object
类型。 - 对于
function
返回function
类型。
- 对于基本类型,除
-
instanceof
:instanceof
只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型
-
constructor
:- null 和 undefined 是无效的对象,因此是不会有
constructor
存在的,这两种类型的数据需要通过其他方式来判断。 - 函数的
constructor
是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的constructor
引用会丢失,constructor
会默认为Object
- null 和 undefined 是无效的对象,因此是不会有
-
toString
:-
toString()
是Object
的原型方法,调用该方法,默认返回当前对象的[[Class]]
。这是一个内部属性,其格式为[object Xxx]
,其中 Xxx 就是对象的类型。 此方法也有缺点,不能精确的判断自定义类型,对于自定义类型只会返回[object Object]
,不过可以用instanceof
代替判断。function Person () {} const p = new Person(); Object.prototype.toString.call(p); // [object Object] p instanceof Person; // true
-
-
-
可能发生隐式类型转换的场景以及转换原则,应如何避免或巧妙应用。
-
出现小数精度丢失的原因,JavaScript可以存储的最大数字、最大安全数字,JavaScript处理大数字的方法、避免精度丢失的方法。
- JavaScript可以存储最大的数字:
Number.MAX_VALUE
它的值可以通过Number.MAX_VALUE得到,在控制台打印得到值:1.7976931348623157e+308。 - 最大安全数字:
Number.MAX_SAFE_INTEGER
: 9007199254740991
- JavaScript可以存储最大的数字:
原型及原型链
-
理解原型设计模式以及
JavaScript
中的原型规则-
原型规则
- 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性;
var arr = [];arr.a = 1;
- 所有的引用类型(数组、对象、函数),都有一个_proto_属性(隐式原型),属性值是一个普通的对象;
- 所有的函数,都具有一个
prototype
(显式原型),属性值也是一个普通对象; - 所有的引用类型(数组、对象、函数),其隐式原型指向其构造函数的显式原型;
(obj._proto_ === Object.prototype)
; - 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的
_proto_
(即它的构造函数的prototype
)中去寻找; - JS中的原型规则与原型链
- 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性;
-
-
instanceof
的底层实现原理,手动实现一个instanceof
-
实现继承的几种方式以及他们的优缺点
-
至少说出一种开源项目(如
Node
)中应用原型继承的案例[暂时没看过源码,看了之后再来回答] -
可以描述
new
一个对象的详细过程,手动实现一个new
操作符 -
理解es6
class
构造以及继承的底层实现原理es6 引入的
class
类实质上是JavaScript
基于原型继承的语法糖。class Animal { constructor(name) { this.name = name; } sayHi() { return `Hello ${this.name}`; } } // es5 function Animal(name) { this.name = name; } Animal.prototype.sayHi = () => { return `Hello ${this.name}`; };
让我们来看看通过
babel
转换的Animal
类,是否跟上面es5类似呢?"use strict"; /** * 判断left 是否是 right 的实例, 底层利用 instanceof, */ function _instanceof(left, right) { if ( right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance] ) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } } function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * 利用Object.defineProperty添加对象属性 */ function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } /** * 给构造函数or构造函数原型添加属性or方法 */ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var Animal = /*#__PURE__*/ (function() { // 构造函数 function Animal(name) { // 检测 this(this 指向生成的实例)是否是构造函数Animal的实例 _classCallCheck(this, Animal); this.name = name; } // 向构造函数添加方法 _createClass(Animal, [ { key: "sayHi", value: function sayHi() { return "Hello ".concat(this.name); } } ]); return Animal; })();
从以上转义后的代码来看,底层还是采用了原型的继承方式。
作用域和闭包
-
理解词法作用域和动态作用域
-
理解
JavaScript
的作用域和作用域链 -
理解
JavaScript
的执行上下文栈,可以应用堆栈信息快速定位问题 -
this
的原理以及几种不同使用场景的取值。this
是什么?this
就是函数运行时所在的环境对象。 -
闭包的实现原理和作用,可以列举几个开发中闭包的实际应用
// 1. 经典闭包面试题 for (var i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }) } for (var i = 0; i < 5; i++) { (function (j) { setTimeout(() => { console.log(j) }) }(i)) } // 2. 模块化方案 const module = (function() { var name = 'rudy'; var getName = function () { return name; } var changeName = function (newName) { name = newName; return name; } return { getName: getName, changeName: changeName } }()) // 私有变量 var privateNum = (function () { var num = 0; return function () { return num++; } }()) privateNum(); // 0 privateNum(); // 1 privateNum(); // 2
必要应用场景实在是太多了,以上只列举了部分场景。
-
理解堆栈溢出和内存泄漏的原理,如何防止
-
如何处理循环的异步操作;
如果需要简单的处理下for循环的异步操作,就是让每个循环体拥有自己的作用域,可以利用
es6
中的let
或者闭包来解决。// let for (let i = 0; i < 5; i++) { setTimeout(() => { console.log(i); // do something }) } // 闭包 for (var i = 0; i <5; i++) { (function (j) { setTimeout(() => { console.log(j); // do something }) }(i)) }
-
理解模块化解决的实际问题,可列举几个模块化方案并理解其中原理
执行机制
- 为何try里面放return,finally还会执行,理解其内部机制
- JavaScript如何实现异步编程,可以详细描述EventLoop机制
- 宏任务和微任务分别有哪些