JS阶段学习
基础理解
- 尚硅谷-js从入门到精通-笔记
- 尚硅谷-js高级-笔记(先收集,稍后处理)
网课的课件就是这个mind
JS基础
数据类型和类型转换
数组
DOM
BOM
定时器
原型和原型链
执行上下文、作用域链、闭包
this、call、apply、bind
异步编程
网络请求-Ajax
promise和事件循环机制
- promise状态如何判断
new promise中
then中
- 事件循环机制
- 定时器
- Uncaught (in promise) 问题探究
Demo练手
- 学习记录
项目搭建
JS面试八股
高频题目
一、数据类型
- JavaScript有哪些数据类型,它们的区别?JavaScript共有八种数据类型,分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。
其中 Symbol 和 BigInt 是ES6 中新增的数据类型:
- Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
- BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。
这些数据可以分为原始数据类型和引用数据类型:
- 栈:原始数据类型(Undefined、Null、Boolean、Number、String)
- 堆:引用数据类型(对象、数组和函数)
两种类型的区别在于存储位置的不同:
- 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
- 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:
- 在数据结构中,栈中数据的存取方式为先进后出。
- 堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。
在操作系统中,内存被分为栈区和堆区:
- 栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
- 堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。
- 数据类型检测的方式有哪些(1)typeof
其中数组、对象、null都会被判断为object,其他判断都正确。console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof []); // object
console.log(typeof function(){}); // function
console.log(typeof {}); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object
(2)instanceof
instanceof 可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型 。
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
可以看到, instanceof 只能正确判断引用数据类型,而不能判断基本数据类型。 instanceof 运算符可以用来测试一个对象在其原型链中是否存在一个构造函数的 prototype属性。
(3) constructor
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
constructor
有两个作用,一是判断数据的类型,二是对象实例通过 constrcu tor 对象访问它的构造函数。需要注意,如果创建一个对象来改变它的原型, constructor 就不能用来判断数据类型了:
function Fn(){};
Fn.prototype = new Array();
var f = new Fn();
console.log(f.constructor===Fn); // false
console.log(f.constructor===Array); // true
(4)Object.prototype.toString.call()
Object.prototype.toString.call() 使用 Object 对象的原型方法 toString 来判断数据类型:
var a = Object.prototype.toString;
console.log(a.call(2));
console.log(a.call(true));
console.log(a.call('str'));
console.log(a.call([]));
console.log(a.call(function(){}));
console.log(a.call({}));
console.log(a.call(undefined));
console.log(a.call(null));
同样是检测对象obj调用toString方法,obj.toString()的结果和Object.prototype.toString.call(obj)的结果不一样,这是为什么?<br />这是因为toString是Object的原型方法,而Array、function等**类型作为Object的实例,都重写了toString方法**。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object原型上的toString方法。
- 判断数组的方式有哪些
通过Object.prototype.toString.call()做判断
Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
通过原型链做判断
obj.__proto__ === Array.prototype;
通过ES6的Array.isArray()做判断
Array.isArrray(obj);
通过instanceof做判断
obj instanceof Array
通过Array.prototype.isPrototypeOf
Array.prototype.isPrototypeOf(obj)
- null和undefined区别首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。
undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。
undefined 在 JavaScript 中不是一个保留字,这意味着可以使用 undefined 来作为一个变量名,但是这样的做法是非常危险的,它会影响对 undefined 值的判断。我们可以通过一些方法获得安全的undefined 值,比如说 void 0。
当对这两种类型使用 typeof 进行判断时,Null 类型化会返回 “object”,这是一个历史遗留的问题。当使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。 - typeof null 的结果是什么,为什么?typeof null 的结果是Object。
在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3bits) 以及当前要存储值的真实数据。类型标签存储在每个单元的低位中,共有五种数据类型:
000: object - 当前存储的数据指向一个对象。
1: int - 当前存储的数据是一个 31 位的有符号整数。
010: double - 当前存储的数据指向一个双精度的浮点数。
100: string - 当前存储的数据指向一个字符串。
110: boolean - 当前存储的数据是布尔值。
如果最低位是 1,则类型标签标志位的长度只有一位;如果最低位是 0,则类型标签标志位的长度占三位,为存储其他四种数据类型提供了额外两个 bit 的长度。
有两种特殊数据类型:
- undefined的值是 (-2)30(一个超出整数范围的数字);
- null 的值是机器码 NULL 指针(null 指针的值全是 0)
那也就是说null的类型标签也是000,和Object的类型标签一样,所以会被判定为Object。
- intanceof 操作符的实现原理及实现 instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
function myInstanceof(left, right) {
// 获取对象的原型
let proto = Object.getPrototypeOf(left)
// 获取构造函数的 prototype 对象
let prototype = right.prototype;
// 判断构造函数的 prototype 对象是否在对象的原型链上
while (true) {
if (!proto) return false; if (proto === prototype) return true;
// 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型
proto = Object.getPrototypeOf(proto);
}
}
- 为什么0.1+0.2 ! == 0.3,如何让其相等
- isNaN 和 Number.isNaN 函数的区别?
- == 操作符的强制类型转换规则?
- 其他值到字符串的转换规则?
- 其他值到数字值的转换规则?
- 其他值到布尔类型的值的转换规则?
- Object.is() 与比较操作符 “=”、“” 的区别?
- JavaScript 中如何进行隐式类型转换?
二、ES6
- let、const、var的区别
- const对象的属性可以修改吗
- 如果new一个箭头函数的会怎么样
- 箭头函数与普通函数的区别
- 箭头函数的this指向哪⾥?
- 对 rest 参数的理解
- ES6中模板语法与字符串处理
三、JavaScript基础
- new操作符的实现原理
- map和Object的区别
- JavaScript脚本延迟加载的方式有哪些?
- JavaScript 类数组对象的定义?
- 数组有哪些原生方法?
为什么函数的 arguments 参数是类数组而不是数组?如何遍历类数组?
什么是 DOM 和 BOM?
- 对类数组对象的理解,如何转化为数组
- 对AJAX的理解,实现一个AJAX请求
- JavaScript为什么要进行变量提升,它导致了什么问题?
- ES6模块与CommonJS模块有什么异同?
- 如何判断一个对象是否属于某个类?
- for…in和for…of的区别
- 数组的遍历方法有哪些
- forEach和map方法有什么区别
四、原型与原型链
- 对原型、原型链的理解
- 原型修改、重写
- 原型链指向
五、执行上下文/作用域链/闭包
1. 对闭包的理解 2. 对作用域、作用域链的理解 3. 对执行上下文的理解
六、this/call/apply/bind
1. 对this对象的理解 2. call() 和 apply() 的区别? 3. 实现call、apply 及 bind 函数
七、异步编程
1. 异步编程的实现方式? 2. setTimeout、Promise、Async/Await 的区别 3. 对Promise的理解 4. Promise的基本用法 5. Promise解决了什么问题 6. Promise.all和Promise.race的区别的使用场景 7. 对async/await 的理解 8. await 到底在等啥? 9. async/await的优势 10. async/await对比Promise的优势
八、面向对象
1. 对象创建的方式有哪些? 2. 对象继承的方式有哪些?
九、垃圾回收与内存泄漏
1. 浏览器的垃圾回收机制 2. 哪些情况会导致内存泄漏