javascript 有哪些原始类型
Undefined,Null,Boolean,Number,String,Symbol,Bigint (一项新的提案让这个答案可能增加 Record 和 Tuple 这两个不可变数据类型)
执行上下文和作用域链
变量或者函数的执行上下文决定了他们可以访问那些数据,每个函数都有自己的执行上下文,当函数被执行的时候, 它的上下文会被推入 执行栈 ,并创建一个作用域链,执行时沿着作用域链查找变量, 函数执行完毕后,执行上下文也会被弹出。
闭包是指那些引用了另一个函数作用域中的变量的函数,通常在嵌套函数中实现。内部的函数作为参数传递或结果返回, 仍能访问到其所在的外部函数的变量。闭包形成的原因是当一个函数执行完毕时,将会销毁其执行上下文以及附带的活 动对象, 但由于外部函数的活动对象已被添加到内部函数的作用域链中,故无法被销毁,仍然保留在内存中,供内部函 数使用。 闭包的使用场景包括防抖、节流、单次调用函数等。
尾调用优化
尾调用优化是 ES6 规范新增的内存管理优化机制(严格模式下开启),当一个函数的返回值是是它内部返回值的时候, 通过重用执行栈栈帧的 方式优化内存管理(内部函数执行上下文执行完毕后不会直接弹出,而是先判断它的外部栈帧 是否有存在必要)。
构造函数
任何函数只要通过 new 操作符调用就是构造函数(一个函数也可以通过 new.target 来判断自己是否最为构造函数 被调用)。当使用 new 操作符执行构造函数时,js 解释器会在内存中新建一个对象,并将该对象的 __proto__ 属性 赋值为构造函数的原型对象 prototype ,然后构造函数内部的 this 被赋值为这个新对象,执行完内部代码后返回 这个对象(如果构造函数直接返回了一个对象,除非手动操作否则原型链会断掉)。
原型和原型链
每个函数(包括 ES6 类)都会创建一个 prototype 属性指向它的原型对象,原型对象的 constructor 属性也会 指向这个函数(或类),当这个函数作为构造函数使用,实例化出一个对象时,这个实例对象的 __proto__ 属性也会 指向构它的原型对象。当一个函数的原型对象是另一个构造函数的实例时,就会形成原型链。
任何使用了 IEEE754 浮点规范的语言都会存在这个问题,双精度浮点数的可靠位为 15 位,16 位之后的可能是对不上的。 0.1 和 0.2 储存值都比实际值要大一些,所以结果不等于 0.3,比较小数是否相当,应该使用两者的差值与 ES6 新增的 Number.EPSILON 属性比较:
if (0.1 + 0.2 - 0.3 < Number.EPSILON) {
console.log(`0.1+0.2=0.3`);
}
原型链、借用构造函数、组合继承、原型式继承、寄生式继承、寄生式组合继承。详见这里
自己实现 call 或者 apply
Function.prototype.myApplay = function (newThis, argArray) {
const tempObj = newThis ?? window;
const funcSymb = Symbol("tempFunc");
// 当一个函数作为对象的属性调用时,函数内this指向这个对象
// 利用这点来达到绑定传入的newThis的目的
tempObj[funcSymb] = this;
tempObj[funcSymb](...argArray);
};
自己实现 bind
Function.prototype.myBind = function (newThis) {
const self = this;
// 利用闭包,绑定this
return function () {
self.apply(newthis, arguments);
};
};
浏览器每次发起请求,都会现在浏览器缓存中查找该请求的结果以及缓存标识,且每次拿到结果,都会将该结果 和缓存标识存入浏览器缓存中,而这个缓存过程又分为强制缓存和协商缓存。服务端控制缓存规则的字段包括 Expires (HTTP1.0 的字段,客户端对比时间存在缺陷,已被后者取代)和 Cache-Control (优先级更高), Cache-Control<