1、什么是变量提升?
量提升是当栈内存作用域形成时,JS代码执行前,浏览器会将带有var, function关键字的变量提前进行声明(值默认就是 undefined),定义 (就是赋值操作),这种预先处理的机制就叫做变量提升机制也叫预定义。
2、带var和不带var的区别
- 全局作用域中不带var声明变量虽然也可以但是建议带上 var声明变量,不带 var 的相当于给window对象设置一个属性罢了。
- 私有作用域(函数作用域),带 var 的是私有变量。不带 var 的是会向上级作用域查找,如果上级作用域也没有那么就一直找到 window 为止,这个查找过程叫作用域链。
- 全局作用域中使用 var 申明的变量会映射到 window 下成为属性。
3、JS中的堆栈
堆和栈都是运行时内存中分配的一个数据区,因此也被称为堆区和栈区;
- 堆(heap)用于复杂数据类型(引用类型)分配空间,例如数组对象、object对象;它是运行时动态分配内存的,因此存取速度较慢。
- 栈(stack)中主要存放一些基本类型的变量和对象的引用,(包含池,池存放常量),其优势是存取速度比堆要快,并且栈内的数据可以共享,但缺点是存在栈中的数据大小与生存期必须是确定的,缺乏灵活性
4、作用域
- 作用域是指程序源代码中定义变量的区域。也就是程序可以生效并运行的空间。
- 全局作用域是指变量可以在当前脚本的任意位置访问,拥有全局作用域的变量也被称为“全局变量”
- 在函数内部声明的变量具有局部作用域,拥有局部作用域的变量也被称为“局部变量”,局部变量只能在其作用域中(函数内部)使用
5、JS检测数据类型的四种办法
- typeof对于基本数据类型判断是没有问题的,但是遇到引用数据类型(如:Array)是不起作用的
- instanceof可以用来判断数组和对象,但不能用于基础数据类型。
- constructor(康斯抓课t)来判断数据的类型,但是除了null、undefined,因为他们不是由对象构建。
- Object.prototype.toString.call(); 任何类型都可以精准检测出来
6、闭包
- 内部函数可以访问外部函数的值,该值会长期存储在内存中,因此产生了闭包
- 闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。 直观的说就是形成一个不销毁的栈环境, 闭包实现了传递值和功能的调用。
- 优点:避免变量污染全局,变量的叠加使用
- 缺点:因为常驻内存,如果有大量闭包不被释放,容易造成内存溢出
7、递归
- 程序自我调用,简单理解就是函数自己调用自己。目的是为了处理不确定层级的相同数据结构的数据处理。
- 优点:代码更简洁清晰,可读性更好;
- 缺点:时间和空间消耗比较大、很多计算都是重复的、调用栈可能会溢出。
8、深拷贝和浅拷贝
- 浅拷贝只是拷贝一层,对更深层次对象级别的只拷贝引用(地址)
- 深拷贝拷贝多层,每一级别的数据都会拷贝
- Object.assign(target,...sources(搜我c子)) es6新增方法可以浅拷贝
- JSON.parse(JSON.stringify(obj)) 可以实现暴力深拷贝
- 一般深拷贝使用递归去实现
9、字符串常用方法
- 获取字符串长度:length
- 获取字符串指定位置的值:charAt() 方法获取到的是指定位置的字符
- 查询是否包含某字符:indexOf、lastIndexOf、includes、search。
- 字符串拼接:出了使用+号,应该使用concat
- 字符串分割成数组:split
- 截取字符串:substr()、substring()和 slice()
- 字符串大小写转换:toLowerCase转小写、toUpperCase转大写
- 字符串转数字:parseInt转整数、parseFloat转小数
参考:JavaScript 28个常用字符串方法及使用技巧 - 掘金 (juejin.cn)
10、数组方法
- 合并数组:concat
- 指定字符数组转字符串:join
- 添加元素操作:push()尾部 和unshift()头部
- shift() & pop() 删除元素操作
- sort() 数组排序,改变原数组
- reverse() 反转数组,改变原数组
- slice() 截取数组,不改变原数组
- splice() 更新数组,改变原数组
- indexOf() & lastIndexOf() 索引方法,不改变原数组
- find() & findIndex() 根据函数内的判断返回找到的数组内的第一个元素。不改变原数组。 (es6新增方法)
- forEach()、map()、filter()、some()、every() 迭代方法,不改变原数组。
- reduce()、reduceRight() 归并方法,不改变原数组
- keys()、values()、entries() 遍历数组方法,不改变原数组。 (es6新增方法)
- includes() 不改变原数组。 (es6新增方法)
- 参考:JavaScript中数组的常用方法(含ES6) - 简书 (jianshu.com)
11、对象
- 创建对象的三种方式: 1、var obj = {} 字面量 2、Object.create() 对象方法创建 3、New Object() 构造函数方式
- Object.entries(obj): 把对象转成键值对的数组
- Object.definedProperty() 监听对象属性的变化,vue2的数据响应式原理。
- Object.assign() 合并对个对象为一个对象
- Object.values() 把对象的值序列化为数组
- Object.keys() 把对象的属性名序列化为数组
12、JavaScript的基本规范
- 不要在同一行声明多个变量
- 使用 ===或!==来比较true/false或者数值
- switch必须带有default分支
- 函数应该有返回值
- for if else 必须使用大括号
- 语句结束加分号
- 命名要有意义,使用驼峰命名法
13、堆和栈的区别
- 栈(stack):由编译器自动分配释放,存放函数的参数值,局部变量等;
- 堆(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统释放。
14、谈谈this的理解
- this总是指向函数的直接调用者(而非间接调用者)
- 如果有new关键字,this指向new出来的那个对象
- 在事件中,this指向目标元素,特殊的是IE的attachEvent中的this总是指向全局对象window。
15、什么是window对象?什么是document对象?
- window对象代表浏览器中打开的一个窗口。
- document对象代表整个html文档。实际上,document对象是window对象的一个属性。
16、null和undefined的区别
- null表示一个对象被定义了,但存放了空指针,转换为数值时为0。
- undefined表示声明的变量未初始化,转换为数值时为NAN。
- typeof(null) -- object;
- typeof(undefined) -- undefined
17、JS垃圾回收机制
- 标记清除:这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。 1、这个算法假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象)。 定期的,垃圾回收器将从根开始,找所有从根开始引用的对象,然后找这些对象引 用的对象。从根开始,垃圾回收器将找到所有可以获得的对象和所有不能获得的对象
- 引用计数:这是最简单的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。该算法有个限制:无法处理循环引用。两个对象被创建,并互相引用,形成了一个循环。它们被调用之后不会离开函数作用域,所以它们已经没有用了,可以被回收了。然而,引用计数算法考虑到它们互相都有至少一次引用,所以它们不会被回收。