2022-09-27 18:23:59
类型判断
JavaScript 有 7 种基本类型(undefined, null, boolean, number, string, symbol, bigint)和对象类型(object)。
类型判断方法:
typeof:判断基本类型(注意 typeof null 返回 "object")。
instanceof:判断对象是否为某构造函数的实例。
Object.prototype.toString.call():精确判断类型。
示例:typeof 42; // "number"typeof null; // "object"[] instanceof Array; // trueObject.prototype.toString.call([]); // "[object Array]"
作用域
JavaScript 有全局作用域、函数作用域和块级作用域(ES6 的 let 和 const)。
作用域链通过词法环境决定变量访问。
示例:let x = 1;function foo() { let x = 2; console.log(x); // 2}foo();console.log(x); // 1
引用传递
JavaScript 中,基本类型按值传递,对象类型(包括数组和函数)按引用传递。
内存释放:JavaScript 使用垃圾回收机制(主要基于标记清除算法)。变量在失去引用后由 V8 引擎自动回收。
ES6 新特性
let 和 const:块级作用域。
箭头函数:简洁语法,无自身 this。
模板字符串:支持插值。
解构赋值:提取数组或对象值。
Promise:异步处理。
模块化:import 和 export。
示例:const [a, b] = [1, 2];const greet = name => `Hello, ${name}`;
JS 中什么类型是引用传递,什么类型是值传递?如何将值类型的变量以引用的方式传递?
值传递:基本类型(number, string, boolean, undefined, null, symbol, bigint)。赋值时复制值,修改不影响原变量。
引用传递:对象类型(object, array, function)。赋值时传递引用,修改会影响原对象。
值类型以引用方式传递:将值包装为对象。
示例:let num = 10;let obj = { value: num };function modify(ref) { ref.value = 20;}modify(obj);console.log(obj.value); // 20
JS 中,0.1 + 0.2 === 0.3 是否为 true?在不知道浮点数位数时怎样判断两个浮点数之和与第三数是否相等?
结果:false,因为 JavaScript 使用 IEEE 754 双精度浮点数,0.1 + 0.2 结果为 0.30000000000000004。
判断方法:使用误差范围比较(如 Number.EPSILON)或转换为整数比较。
示例:console.log(0.1 + 0.2 === 0.3); // falsefunction areEqual(a, b, c) { return Math.abs((a + b) - c) < Number.EPSILON;}console.log(areEqual(0.1, 0.2, 0.3)); // true
const 定义的 Array 中间元素能否被修改?如果可以,那 const 修饰对象的意义是什么?
能否修改:可以,const 只保证变量引用不可变,对象内容可修改。
意义:防止变量被重新赋值,增强代码可预测性。
示例:const arr = [1, 2, 3];arr[1] = 4; // 可以console.log(arr); // [1, 4, 3]arr = [5, 6, 7]; // 错误:Assignment to constant variable
JavaScript 中不同类型及不同环境下变量的内存何时释放?
基本类型:存储在栈中,作用域结束时自动释放。
对象类型:存储在堆中,当无引用时由垃圾回收器释放(标记清除算法)。
环境:
浏览器:全局变量在页面关闭时释放,局部变量在作用域结束时释放。
Node.js:全局变量在进程结束时释放。
示例:function test() { let obj = { a: 1 }; return () => obj = null; // 手动解除引用}const release = test();release(); // obj 可被回收
模块机制
Node.js 使用 CommonJS 模块(require 和 module.exports),ES6 引入了 import/export。
热更新:热更新指在运行时更新模块而不重启进程。
上下文:每个模块有独立上下文,避免全局污染。
包管理:通过 npm 或 yarn 管理依赖。
常见问题及答案
a.js 和 b.js 两个文件互相 require 是否会死循环?双方是否能导出变量?如何避免?
死循环:不会,Node.js 的 require 有缓存机制,循环引用时返回未完成模块的引用。
导出变量:可以,但可能拿到未初始化值。
避免方法:提取公共模块,或调整依赖顺序。
示例:// a.jsconst b = require('./b');module.exports = { a: 1 };console.log(b); // { b: undefined } 或 { b: 2 }(视执行顺序)// b.jsconst a = require('./a');module.exports = { b: 2 };console.log(a); // { a: 1 }
如果 a.js require 了 b.js,那么在 b 中定义全局变量 t = 111 能否在 a 中直接打印出来?
结果:不能,模块有独立作用域,t = 111 只影响 b.js 的全局变量。
访问方法:需通过 global.t 或导出。
示例:// b.jst = 111; // 等价于 global.t = 111module.exports = {};// a.jsrequire('./b');console.log(t); // undefinedconsole.log(global.t); // 111
如何在不重启 Node 进程的情况下热更新一个 JS/JSON 文件?这个问题是否有问题?
方法:清除模块缓存(delete require.cache[modulePath])并重新 require。
问题本身的问题:热更新可能导致状态不一致,需谨慎设计。
示例:const path = require.resolve('./module');delete require.cache[path];const updatedModule = require('./module');