1、for...of\for...in\forEach\map区别
for..of:必须具有iterator接口、可中断
for..in:遍历自身和继承的可枚举属性,不能获取属性值,只有键值,可中断
forEach:只能遍历数组,没有返回值(在自身做修改),不可中断
map:只能遍历数组,返回新的数组,不可中断。
2、判断是不是数组
1、Array.isArray(arr):返回true
2、arr instanceOf Array:返回true
3、Object.prototype.toString.call(arr):返回[object Array]
4、arr.constructor === Array:返回true(因为constructor可修改,所以不准确)
3、== 和 ===
首先看类型是否相同,相同的话,比较值。类型不同进行类型先转换。转换规则有以下几条:
1、看是否为null或者undefined,是的话就相等
2、string和number比较,将string转换为数字再比较
3、任意一边有boolean,将两边转换为number再比较
4、如果遇到对象和数字、字符串比较,将对象转换成基本类型在比较
4、讲讲new
栗子:var a = new b() 1、创建一个空对象,赋值给a(a = {})
2、a的隐式原型(proto) = b的显示原型(prototype)
3、调用b.call(a),b的this指向a,然后返回。
5、说说防抖和节流
节流就是单位时间内只能运行一次,防抖就是一定时间内多次触发只执行最后一次。
举个栗子:英雄联盟或者王者荣耀这种游戏来说,节流就像技能,一段时间只能放一次,防抖就像回城,例如王者荣耀多次点击回城,只计算最后一次点击的。
6、说说浮点数的事(字节19年12月笔试问的双精度是怎么存储的)
当天回来看了js中number存储的方式,我自己理解是这样的:因为计算机中都是由0和1整的二进制数字表示的,所以十进制的小数转换成二进制是采用对阶运算求和,例如8是2的3次方,0.5(1/2)就是2的-1次方,0.75(3/4)是2的-1加2的-2,可是0.2呢?就是1/5,通过对阶运算求和只能无限接近,不能相等,所以就扫噶斯乃啦。
7、闭包
闭包就是函数嵌套函数,并在内部返回,使得在函数外部可以访问到函数内部变量,因为闭包始终保存着对变量的引用,所以不会被垃圾回收机制(不用了就回收,还在用就保留)回收,当然内存内漏(他不是说内存溜出去了,而是有一部分内存被占用,不可使用,导致可用内存变少了,就似乎好像是内存跑了一样,其实不然)就是这样造成的。
实际应用:单例模式就是闭包,在内部创建函数并返回,为了互不影响,使用立即执行函数处理闭包,代码如下
let AModule = (function () {
let n = 10;
let query = function () {
//...
};
let fn = function () {
//...
//调取开发者B编写的QUERY方法
BModule.query();
};
return {
query: query,
init: function () {
query();
fn();
}
}
})();
// 开发者B
let BModule = (function () {
let n = 20;
let query = function () {
//...
};
let sum = function () {
//...
//调取开发者A编写的QUERY方法
AModule.query();
};
return {
query: query,
init: function () {
query();
sum();
}
}
})();
作者:Fe_从零到壹
链接:https://juejin.cn/post/6844903933731667982
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
8、ES6的Set和Map
注:字节跳动面试题,es6没学好,所以回答的不好。
今天总结一下
1、Set是一个数据结构,本身是一个构造函数,它返回的并不是数组,是一个集合的数据结构
Set去重:
newAarr = [...new Set(arr)]
//因为返回的是集合,所以要使用扩展运算'...'将Set返回的集合变成数组
//
Set内部判断是否相同的方法类似于"==="(精确相等运算符),类似于是因为它解决了NaN不等于自身的问题。
四个操作方法:
- add(添加)
- delete(删除某一个,返回布尔值,表示是否删除成功)
- has(判断是否存在,返回布尔值)
- clear(清空所有,无返回值)
注意:遍历出来的顺序就是插入顺序
2、Map是一个字典的数据结构
- 先了解一下JS对象的数据结构,JS对象本质上是键值对的集合(hash结构),但是只能用字符串作为键。Map数据结构解除了这种限制,提供了“值——值”对应的结构,是更完善的hasd结构。
- 操作方法:has(key)、delete(key)、set(key,value)、get(key)、size
- 遍历出来的顺序就是插入顺序,返回的也不是数组,可以使用扩展运算符转换为数组“...”
WeakMap
- 只接受对象作为键(null)除外
- weakmap
- 无法获取键名,无法清空(没有clear方法)
9、Boolean
说到布尔值,就会想到判断问题,那是如何判断布尔值的呢?总结一下布尔值要注意的点
- 只有true和false是布尔值,是区分大小写的
- 任何对象(包括空对象和Objext的子类型(array、data、math、function、regexp等))都是ture,注意null为false(null并非对象,红宝书说null只是空对象的一个指针)
- 任何非空字符串是true
- 任何非零数值为true,0和NaN是false
- null和undefined为false
- if语句自动转换Boolean值,进行判断
- 操作符“!”,!操作符会将后面任意值转换为布尔值,再取反。
10、Number
- 数值最值得注意的就是浮点数不准确的问题了,浮点数存储方式IEEE 754 64位格式存储不准确是因为计算中的数字都是由一个一个二进制数相加求出来的,例如9时2的3次方加2的0次方,例如0.75等于2的-1次方加2的-2次方,这下知道0.3为什么不准确了吧,不信你试试通过二进制数能不能加出来0.3这个数值。
- 数值转换问题,不是数值那就是NaN,布尔值相应转换为1和0
- parseInt方法,逐步解析,遇到非数值就会停下来并返回,例如22.5就会返回22,因为小数点不是数值
- parseFloat相对于parseInt区别是,可以识别第一个小数点,第二次出现就不能识别了。
11、 js中的位操作符
与(“并且”的意思,都为1才为1)、或(“或者”的意思,有1就为1)、非(按位取反),异或(“异”及“不同”则为1)
12、Array
操作方法:
类1
- splice(直接修改数组,返回删除的项)
- slice(返回新数组)
- concat(返回新数组)
类2
- 构建栈(push(尾部插入(后进)),pop(尾部删除(后进先出)))
- 构建队列(push(尾部插入(后进),shift(头部删除(先进先出)))
类3
- every(数组中的每一项运行给定函数,全部返回true,则every返回true)
- some(数组中的每一项运行给定函数,某一项返回true,则some返回true)
- filter(数组中的每一项运行给定函数,返回结果为true的项)返回新数组
- forEach(数组中的每一项运行给定函数)直接修改数组
注意:forEach有两个参数,第二个参数为this指向(可选)
- map(数组中的每一项运行给定函数,返回每项调用函数后返回结果组成的数组)返回新数组
- reduce
注意:
1、两个参数1是每项执行的函数2是作为归并基础的初始值(可选)
2、第一个参数传入的函数接收四个参数,1是前一个值,2是当前值,3是索引,4是新的数组对象)
13、对象的创建
A、工厂模式
在函数内部创建对象,在此对象上添加属性,直接调用(红宝书)示例如下
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
var person1 = createPerson("Nicholas", 29, "Software Engineer");//直接调用
B、构造函数模式
向函数内的this对象上面添加属性,new构造调用,(红宝书)示例如下
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");//new调用(改变this指向)
14、JS继承
1、原型链继承
想必大家已经了解了原型链继承方式了,因为今天是深挖到底系列,所以我直接说我(在红宝书中)挖到了什么
还是先说一下原型继承哈哈:原型链继承是A的原型指向B,使A成为B的一个实例,这样A就可以访问原型链上所有属性,实现继承
- 栗如A继承了B,不能在A的原型上使用对象字面量添加方法,因为这样的话会使B的实例变成此字面量对象,而非原来B本身的实例,会切断AB的原型链关系。
- 问题2就是当原型中拥有引用类型属性时,在继承该原型的实例中修改此属性值,那么继承该原型的所有实例都会共享修改后的属性。
2、寄生组合继承
- 创建prototype等于object.create(B.prototype) ;直接创建对象省去了new的一次构造函数使用。
- prototype.constructor = A;
- A.prototype = prototype;
15、函数声明和函数表达式
- 函数声明是function开头
- 函数表达式是由名称的
- 函数声明后面不可以带(),把函数声明放到括号内就成了函数表达式,后面可以加括号,即常说的立即执行函数,模仿的块级作用域。
- 函数表达式后面可以带()
16、闭包
-
先了解一下私有变量,js中任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量。 私有变量包括函数的参数、局部变量和在函数内部定义的其他函数。
-
闭包是指有权访问另一个函数作用域中的变量的函数。创建形式是函数返回函数
先写这么多,先准备面试,回来再补(2019/12/31)