1.16 instanceOf作用 即原理
instanceof主要作用就是判断一个实例是否属于某种类型
function new_instance_of(leftVaule, rightVaule) {
let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
while (true) {
if (leftVaule === null) {
return false;
}
if (leftVaule === rightProto) {
return true;
}
leftVaule = leftVaule.__proto__
}
}
其实 instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。
1.17 数组和伪数组的区别?
- 定义
- 数组是一个特殊对象,与常规对象的区别:
- 当由新元素添加到列表中时,自动更新length属性
- 设置length属性,可以截断数组
- 从Array.protoype中继承了方法
- 属性为'Array'
- 类数组是一个拥有length属性,并且他属性为非负整数的普通对象,类数组不能直接调用数组方法。
- 区别
本质:类数组是简单对象,它的原型关系与数组不同
let arrayLike = {
length: 10,
};
console.log(arrayLike instanceof Array); // false
console.log(arrayLike.__proto__.constructor === Array); // false
console.log(arrayLike.toString()); // [object Object]
console.log(arrayLike.valueOf()); // {length: 10}
let array = [];
console.log(array instanceof Array); // true
console.log(array.__proto__.constructor === Array); // true
console.log(array.toString()); // ''
console.log(array.valueOf()); // []
- 类数组转换为数组
- 转换方法
- 使用 Array.from()
- 使用 Array.prototype.slice.call()
- 使用 Array.prototype.forEach() 进行属性遍历并组成新的数组
- 转换须知
- 转换后的数组长度由 length 属性决定。索引不连续时转换结果是连续的,会自动补位
let al1 = {
length: 4,
0: 0,
1: 1,
3: 3,
4: 4,
5: 5,
};
console.log(Array.from(al1)) // [0, 1, undefined, 3]
// 2.仅考虑 0或正整数 的索引
let al2 = {
length: 4,
'-1': -1,
'0': 0,
a: 'a',
1: 1
};
console.log(Array.from(al2)); // [0, 1, undefined, undefined]
// 3.使用slice转换产生稀疏数组
let al2 = {
length: 4,
'-1': -1,
'0': 0,
a: 'a',
1: 1
};
console.log(Array.prototype.slice.call(al2)); //[0, 1, empty × 2]
// 4.使用数组方法操作类数组注意地方
let arrayLike2 = {
2: 3,
3: 4,
length: 2,
push: Array.prototype.push
}
// push 操作的是索引值为 length 的位置
arrayLike2.push(1);
console.log(arrayLike2); // {2: 1, 3: 4, length: 3, push: ƒ}
arrayLike2.push(2);
console.log(arrayLike2); // {2: 1, 3: 2, length: 4, push: ƒ}
1.18 介绍下 Set、Map、WeakSet 和 WeakMap的区别?
Set
- 成员不能重复;
- 只有键值,没有键名,有点类似数组;
- 可以遍历,方法有 add、delete、has
WeakSet
- 成员都是对象(引用);
- 成员都是弱引用,随时可以消失(不计入垃圾回收机制)。可以用来保存 DOM 节点,不容易造成内存泄露;
- 不能遍历,方法有 add、delete、has ;
Map
- 本质上是键值对的集合,类似集合;
- 可以遍历,方法很多,可以跟各种数据格式转换;
WeakMap
- 只接收对象为键名(null 除外),不接受其他类型的值作为键名;
- 键名指向的对象,不计入垃圾回收机制;
- 不能遍历,方法同 get、set、has、delete ;
1.19 简单说说 js 中有哪几种内存泄露的情况
- 意外的全局变量;
- 闭包;
- 未被清空的定时器;
- 未被销毁的事件监听;
- DOM 引用;
1.20 json和xml数据的区别?
- 数据体积方面:xml是重量级的,json是轻量级的,传递的速度更快些。
- 数据传输方面:xml在传输过程中比较占带宽,json占带宽少,易于压缩。
- 数据交互方面:json与javascript的交互更加方便,更容易解析处理,更好的进行数据交互
- 数据描述方面:json对数据的描述性比xml较差
- xml和json都用在项目交互下,xml多用于做配置文件,json用于数据交互。
1.21 JavaScript有几种方法判断变量的类型?
- 使用typeof检测当需要判断变量是否是number, string, boolean, function, undefined等类型时,可以使用typeof进行判断。
- 使用instanceof检测instanceof运算符与typeof运算符相似,用于识别正在处理的对象的类型。与typeof方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。
- 使用constructor检测constructor本来是原型对象上的属性,指向构造函数。但是根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的。
1.22 Math.min()< Math.max()
false
按常规的思路,这段代码应该输出 true,毕竟最小值小于最大值。但是却输出 false
1.23 promise和 async await 区别?
概念
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强
大,简单地说,Promise好比容器,里面存放着一些未来才会执行完毕(异步)的事件的结果,而
这些结果一旦生成是无法改变的
async await也是异步编程的一种解决方案,他遵循的是Generator 函数的语法糖,他拥有内置执
行器,不需要额外的调用直接会自动执行并输出结果,它返回的是一个Promise对象
两者的区别
- Promise的出现解决了传统callback函数导致的“地域回调”问题,但它的语法导致了它向纵向
发展行成了一个回调链,遇到复杂的业务场景,这样的语法显然也是不美观的。而async
await代码看起来会简洁些,使得异步代码看起来像同步代码,await的本质是可以提供等同
于”同步效果“的等待异步返回能力的语法糖,只有这一句代码执行完,才会执行下一句。 - async await与Promise一样,是非阻塞的。
- async await是基于Promise实现的,可以说是改良版的Promise,它不能用于普通的回调函
数。
1.24 defer和async区别?
-
defer
要等到整个页面在内存中正常渲染结束(DOM结构完全生成,以及其他脚本执行完成),才会执行。多个defer脚本会按照它们在页面出现的顺序加载。==“渲染完再执行”== -
async
一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。多个async脚本是不能保证加载顺序的。==“下载完就执行”==
1.25 同步和异步
同步
- 指在 主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务。
- 也就是调用一旦开始,必须这个调用 返回结果(划重点——)才能继续往后执行。程序的执行顺序
和任务排列顺序是一致的。
异步
- 异步任务是指不进入主线程,而进入 任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程。
- 每一个任务有一个或多个 回调函数。前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行。
- 程序的执行顺序和任务的排列顺序是不一致的,异步的。
- 我们常用的setTimeout和setInterval函数,Ajax都是异步操作。
1.26 javascript中arguments相关的问题?
arguments
在js中,我们在调用有参数的函数时,当往这个调用的有参函数传参时,js会把所传的参数全部存到一个叫arguments的对象里面。它是一个类数组数据
由来
Javascrip中每个函数都会有一个Arguments对象实例arguments,引用着函数的实参。它是寄生在js函数当中的,不能显式创建,arguments对象只有函数开始时才可用
作用
有了arguments这个对象之后,我们可以不用给函数预先设定形参了,可以动态地通过arguments为函数加入参数
1.27 null 和 undefined 的区别,如何让一个属性变为null
undefined
- 声明了一个变量,但没有赋值
- 访问对象上不存在的属性
- 函数定义了形参,但没有传递实参
- 使用 void 对表达式求值
null
- null是一个空值
- null 有属于自己的类型 Null,而不属于Object类型
- 二进制的前三位为 0 会被 typeof 判断为对象类型
1.28 简单说说 js 中有哪几种内存泄露的情况
- 意外的全局变量;
- 闭包;
- 未被清空的定时器;
- 未被销毁的事件监听;
- DOM 引用;
1.29 call appy bind的作用和区别?
作用:
都可以改变函数内部的this指向
区别点:
- call 和 apply 会调用函数,并且改变函数内部this指向。
- call 和 apply 传递的参数不一样,call 传递参数arg1,arg2...形式 apply 必须数组形式[arg]
- bind 不会调用函数,可以改变函数内部this指向
1.30 this指向(普通函数、箭头函数)
- 谁调用了函数或者方法,那么这个函数或者对象中的this就指向谁
- 匿名函数中的this:匿名函数的执行具有全局性,则匿名函数中的this指向是window,而不是调用该匿名函数的对象
箭头函数中的this
- 箭头函数中的this是在函数定义的时候就确定下来的,而不是在函数调用的时候确定的
- 箭头函数中的this指向父级作用域的执行上下文;
- 箭头函数无法使用apply、call和bind方法改变this指向,因为其this值在函数定义的时候就被确定下来