- js的类型
- 运行时类型是代码实际执行过程中我们用到的类型。所有的类型数据都会属于 7 个类型之一。从变量、参数、返回值到表达式中间结果,任何 JavaScript 代码运行过程中产生的数据,都具有运行时类型
- 为什么有的编程规范要求用 void 0 代替 undefined?
- 因为在JavaScript的代码中 undefined 是一个变量,而并非是一个关键字,这是 JavaScript 语言公认的设计失误之一,所以我们为了避免无意中被篡改,建议使用 void 0 来获取undefined
- 字符串有最大长度吗?
- 字符串是有最大长度的,最大长度为 2^53 - 1,但是有趣的是,这个长度指的并不是文本的长度,而是 UTF16编码的长度
- 0.1 + 0.2 不是等于0.3吗?
- 这里 js 默认采用了 浮点数的运算方式,所以 这里错误的不是结论,而是比较方法
- console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON); // Number.EPSILON 代表js的最小精度值,浮点数运算最好采用这种方式来进行对比
- es6新加入的 Symbol 是个什么东西?
- Symbol是一切非字符串的对象key的集合
- Symbol可以具有字符串类型的描述,但是即使描述相同,Symbol也不相等
- 为什么给对象添加的方法能用在基本类型上?
- 当我们给 对象 Object 的原型上添加方法时,因为 所有的构造函数都是继承于 Object 对象,所以根据 js 的原型链继承原理,构造函数构建出来的所有基本类都会拥有 该方法
- 当我们不使用 构造函数进行 创建 基本类型,而采用 字面量的形式来进行创建的时候,本质上 在js引擎的内部,它是帮你 自动的 调用了构造函数进行了构造
- . 运算符提供了装箱操作,它会根据基础类型构造一个临时对象,使得我们能在基础类型上调用对应对象的方法。
- [介绍下 Set、Map、WeakSet 和 WeakMap 的区别?]
- 共性:都是新加的集合类型,提供了更加方便的获取属性值的方法
- set:伪数组,具有不可重复性,元素是唯一的
- Map:解决的是Object的键值对中 键 只能是字符串的问题。各种类型的值(包括对象)都可以当做 键
- WeakSet:类似 set 的结构,但是 WeakSet 只能存储 对象,不能存储其他
- WeakMap:WealMap结构与Map结构基本类似,唯一的区别就是WeakMap只接受 对象 作为 键,而且 键名 所指向的对象不计入垃圾回收机制
- 区别:
- Map和Set都为内部的每个键或值保持了强引用,也就是说,如果一个对象被移除了,回收机制无法取回它占用的内存 ,除非在Map或者Set中删除它。
- WeakSet并不对其中对象保持强引用。当WeakSet中的一个对象被回收时,它会简单地被从WeakSet中移除。WeakMap也类似地不为它的键保持强引用。如果一个键仍被使用,相应的值也就仍被使用 。
- [什么是防抖和节流?有什么区别?如何实现?]
- 防抖:resize 和 scroll 等事件操作的时候,会非常频繁的触发导致页面不断的重新渲染,非常影响性能,加重浏览器负担,导致体验不好,防抖函数就是当时间持续触发事件时,debounce函数会把事件合并且不会触发回调,当停止触发事件delay时长的时候才会触发事件
- 节流:节流也是解决类似的问题,节流只允许回调函数在规定时间内只执行一次,和防抖的最大区别是,无论多频繁的触发时间,都会保证在规定时间内执行一次回调
- 两者最大的区别是:防抖 是在所有操作停止的时候,触发一次回调。节流是一旦操作触发,在规定时间内 只触发一次回调
- 防抖:
function debounce(fn, delay, immediate){ // fn是回调函数,delay是延迟时间,immediate是否先执行一次再节流 var timer = null, _this, args; return function(){ _this = this; args = arguments; // 如果有定时器先清除,让定时器的函数不执行 timer && clearTimeout(timer); if(immediate){ // 没有定时器的话,告诉后面的函数可以先执行一次,首次进入函数没有定义定时器,do为true var do = !timer; // 然后在delay时间以后将timer设置为null,首次执行之后,只有在timer为null之后才会再次执行 timer = setTimer(function(){ timer = null }, delay); if(do){ fn.apply(_this, args); } } else { // 如果没设置第三个参数,就是什么时候停止,之后delay时间才执行 timer = setTimer(function(){ fn.apply(_this, args); }, delay); } } }
- 节流:
function throttle(fn, delay){ var before = Date.now(); return function(){ var _this = this, args = arguments, bow = Date.now(); if(now - before - delay >= 0){ before = now setTimeout(function(){ fn.apply(_this, args); }, delay); } } }
- [['1', '2', '3'].map(parseInt) what & why ?]
- 首先,这里会设置到 一个 parseInt 的 api应用,parseInt 是支持2个参数的传递的,第一个参数 是需要转换的值,第二个参数是 转换的进制,parseInt 默认第二个参数为 10,所以我们一般使用 parseInt 都是单参数的使用
- 这里 返回的 [1, 2, 3]
- 同理:parseInt('1', 1, [1, 2, 3]);
- 这里又是一个陷阱,首先 上面说了 parseInt 只支持2个参数,所以第三个参数是会被忽略掉的,其次,第二个参数,如果 小于2 或者 大于 36 则会 返回 NaN
- [写 React / Vue 项目时为什么要在组件中写 key,其作用是什么?]
- 其主要目的是为了 diff 算法的优化,在 react 和 vue 中,通过虚拟dom对比,来进行 动态更新 视图。用了这个key 可以很好的判断出 这个dom是新增的还是从其他地方 剪切过来的
- key 的作用主要是为了 高效的更新虚拟dom,另外vue 中在使用相同标签名元素的过渡切换时,也会使用到 key 属性,其目的也是为了让vue可以区分他们,否则vue只会替换其内部属性 而不会 触发过渡效果