1、如何将一个多维数组变成一维数组?
方法一:转字符串法
let tempArr = [1,[2,3],[4,5,[6,7]]];
let result_str1 = tempArr.join(',').split(',');
console.log(result_str1); // ["1", "2", "3", "4", "5", "6", "7"]
该方法的缺点是如果数组中的各个项是number,将不可避免的转为字符串。
改进
使用了map进行再次遍历。 这种情况只适用于数组中各个项都是number类型或string类型的情况
function unid(arr){
let result_str1 = arr.join(',').split(',');
let result_number = result_str1.map(item=>{
return Number(item);
});
return result_number;
}
console.log(unid(tempArr)); // [1, 2, 3, 4, 5, 6, 7]
方法二:使用数组的concat方法,以及apply
数组的concat方法
let tempArr2 = ['3',4],
tempArr3 = ['3',4,[5,6]];
console.log([1,2].concat(tempArr2)); // [1, 2, "3", 4]
console.log([1,2,].concat(tempArr3)); // [1, 2, "3", 4, [5,6]]
所以使用concat方法只能把二维数组转为一维数组
let tempArr4 = [[1,2],'3','4',[5,6],[7]];
console.log([].concat.apply([],tempArr4)); // [1, 2, "3", "4", 5, 6, 7]
方法三:使用递归
```
使用递归来实现多维数组转为一维数组
let result = [],
tempArr5 = ['1',2,[3,4,[5,6]],7];
function unid1(arr){
for(let item of arr){
if(Object.prototype.toString.call(item).slice(8, -1)==='Array'){
unid1(item);
}else{
result.push(item);
}
}
return result;
}
console.log(unid1(tempArr5)); // ["1", 2, 3, 4, 5, 6, 7]
2、去除数组中重复的方法?
1、使用filter函数来过滤多余的数组项
var arr1 = [1, 2, 4, 5, 6, 7, 1, 2, 3, 4, 4, 3, 2];
function demo(arr){
let arr1 = arr.filter(function (item,index,self){
return index == self.indexOf(item);
})
console.log(arr1)
return arr1;
}
demo(arr);
2、使用for循环来循环出多余的数组项
arr = ['Ron', 'Pal', 'Fred', 'Rongo', 'Ron',123,'Fred'];
function demo(arr) {
let demo1 = [];
arr.forEach(function (i) {
if(!demo1[i]) {
demo1[i] = true;
}
});
console.log(Object.keys(demo1))
return Object.keys(demo1);
}
console.log(demo(arr));
3、Js中的循环方式有哪些?
1、for循环,通常遍历数组;
2、for...in循环,对数组或者对象的属性进行循环操作;
3、while循环,通常用来循环数组;
4、do while循环,它在循环开始前先执行一次操作,然后才进行判断,true就继续执行,false就结束循环;
5、forEach循环,用于调用数组的每个元素,并将元素传递给回调函数。对于空数组不会执行回调函数;
6、map方法,返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值;
7、for...of循环。
4、Js中的变量存储?
引用类型保存在堆中,如:object、array、function;
基础类型保存在栈中,如:undefined、null、boolean、number、string
5、Js中的判断是否为数组的方法有哪些?
1、Array.isArray()返回布尔值true或false;
2、instanceof运算符 返回布尔值 true或false;
3、通过constructor判断;arr.constructor === Array 若为true则为数组类型
4、通过Object.prototype.toString.call()判断
6、js原型和js原型链?
在js中我们是使用构造函数来新建一个对象的,每一个构造函数的内部都有一个prototype属性值,
这个属性值是一个对象,这个对象包含了可以由构造函数的所有实例共享的属性和方法。
当我们使用构造函数新建一个对象后,在这个对象的内部包含一个指针,
这个指针指向构造函数的prototype属性对应的值,在ES6中这个指针被称为对象的原型,
一般来说我们是不能够获取到这个值的,但是现在浏览器中都实现了_proto_属性让我们来访问这个属性,
但是我们最好不要使用这个属性,因为他不是规范中规定的。
ES6中新增了一个Object.getPrototypeOf() 方法,我们可以通过这个方法来获取对象的原型。
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象上找这个属性,
这个原型对象上又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。
原型链的尽头一般来说都是Object.prototype,所以这就是我们新建对象为什么能够实用toString()等方法的原因。
特点:
JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。
当我们修改原型时,与之相关的对象也会继承这一改变。
7、什么是浅拷贝和深拷贝?
浅拷贝
就是两个变量都是指向一个地址,改变了一个变量,那另一个变量也随之改变。
这就是浅拷贝带来的副作用,两个变量会相互影响到,因为它们指向同一个地址。
NewArray = Array
深拷贝
就是互相独立,指向的是不同的地址,一个变量改变了,另一个变量不会被影响到。
newArray = _.map(array, (a) => { return a })闭包函数
8、什么是闭包函数?
定义: 当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,
如果返回的这个函数在外部被执行,就产生了闭包。
表现形式:使函数外部能够调用函数内部定义的变量。
为什么要使用闭包?
使用闭包主要是为了设计私有的方法和变量。
闭包的优点是可以避免全局变量的污染,
缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
在js中,函数即闭包,只有函数才会产生作用域的概念
闭包函数的三个特性?
函数嵌套函数
函数内部可以引用外部的参数和变量
参数和变量不会被垃圾回收机制回收
9、cookie、sessionStorage、localStorage的区别?
sessionStorage 和 localStorage 是HTML5 storage API 提供的,
可以把数据保存在本地,避免了数据在浏览器和服务器之间不必要的通信。
sessionStorage,localStorage, cookie 都是在浏览器存储的数据。
不同之处:
1:cookie数据始终在同源http中携带,即使不需要,也会在浏览器和服务器间来回传递。Storage只存在本地;
2:cookie数据有路径概念,可以限制cookie只能在某路径下;
3:cookie:4k;Storage:5M;
4:sessionStorage:仅在当前浏览器关闭前有效;localStorage:始终有效;cookie:在过期前有效;
5:sessionStorage:在打开的不同浏览器窗口不共享,即使是同一页面,
localStorage:在同源页面共享;cookie:同源页面共享;
10、JavaScript实现继承的方式有哪几种?
1、原型链的继承
核心: 将父类的实例作为子类的原型
特点:
1. 纯粹的继承关系,实例是子类的实例,也是父类的实例
2. 父类新增原型方法/原型属性,子类都能访问到
3. 简单,易于实现
缺点:
1. 可以在Cat构造函数中,为Cat实例增加实例属性。如果要新增原型属性和方法,则必须放在`new Animal()`这样的语句之后执行。
2. 无法实现多继承
3. 来自原型对象的所有属性被所有实例共享
4. 创建子类实例时,无法向父类构造函数传参
2、构造继承
核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
特点:
1. 解决了1中,子类实例共享父类引用属性的问题
2. 创建子类实例时,可以向父类传递参数
3. 可以实现多继承(call多个父类对象)
缺点:
1. 实例并不是父类的实例,只是子类的实例
2. 只能继承父类的实例属性和方法,不能继承原型属性/方法
3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
3、组合继承
核心: 通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
4、实例继承
核心: 为父类实例添加新特性,作为子类实例返回
特点:
1. 不限制调用方式,不管是`new 子类()`还是`子类()`,返回的对象具有相同的效果
缺点:
1. 实例是父类的实例,不是子类的实例
2. 不支持多继承
5、Class 继承
在 ES6 中,我们可以使用 `class` 去实现继承,并且实现起来很简单
核心: 使用 `extends` 表明继承自哪个父类,并且在子类构造函数中必须调用 `super`
11、在jQuery中怎么阻止事件冒泡?*
1.event.stopPropagation();
在事件处理过程中,阻止了事件冒泡,但是不会阻止默认行为(比如a标签的跳转,不会组织链接的跳转)
2、return false;
在事件处理过程中,既阻止事件冒泡,也阻止事件的默认行为
3.event.preventDefault();
在事件处理过程中,阻止了事件的默认行为,但是不会阻止事件的冒泡
12、在JavaScript中怎么向数组中添加或者删除数据?*
push()向数组的最后一项添加
pop()删除数组的最后一项
unshift()向数组的第一项添加
shift()删除数组的第一项
13、什么是DOM和BOM?
DOM指的是文档对象模型,它指的是把文档当做一个对象来对待,这个对象主要定义了处理网页内容的方法和接口。
BOM指的是浏览器对象模型,它指的是把浏览器当做一个对象来对待,这个对象主要定义了与浏览器进行交互的方法和接口。
BOM的核心是window,而window对象具有双重角色,它及时通过js访问浏览器窗口的一个接口,又是一个Global(全局)对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者方法存在。window对象都含有location对象、navigator对象、screen对象等子对象,并且DOM的最根本对象document也是BOM的window对象的子对象
BOM的最根本对象是window。DOM最根本对象是document(实际上是window.document)。
14、js中有什么数据类型?
js中有六种数据类型,包括五种基本数据类型(Number,String,Boolean,Undefined,Null)
复杂数据类型(Object)。
15、关于js中的递归和正则匹配?
递归求和
function sum(n) {
if (n === 1) return 1
return sum(n - 1) + n
}
console.log(sum(100))
斐波拉契数列
递归的写法
function fib(n) {
if (n === 1 || n === 2) return n - 1
return fib(n - 1) + fib(n - 2)
}
console.log(fib(10)) // 34
非递归的写法
function demo(n){
let a = 0;
let b = 1;
let c = a + b;
for (let i = 3; i<n ; i++){
a = b;
b = c;
c = a + b;
}
return c
}
console.log(demo(10))
16、关于自由落体运动和匀速圆周运动?
(基本不会考到/个别的公司的面试问题)
17、js中事件执行的顺序
- 1、事件捕获
- 2、事件处理
- 3、事件冒泡
- 4、阻止事件冒泡