Web前端经典面试题-JavaScript

Web前端经典面试题-JavaScript
看看银行卡余额,看看工资条,看看房价,动力就来了,大二狗,加油~~
JavaScript
原型链、类、继承、作用域、闭包、js运行机制/单线程、js数据类型、js内置函数、内置对象、js去重、js逻辑判断、js内存泄漏、dom、bom、通信、ajax、错误监控、js基础
一、原型链
1.1,创建对象有几种方法?
1、字面量对象 // 默认这个对象的原型链指向object

var o1 = {
    
    name: '01'};

2、通过new Object声明一个对象

var o11 = new Object({
    
    name: '011'});

3、使用显式的构造函数创建对象

var M = function(){
    
    this.name='o2'};
var o2 = new M();
o2.__proto__=== M.prototype

o2的构造函数是M
o2这个普通函数,是M这个构造函数的实例
4、object.create()

var P = {
    
    name:'o3'};
var o3 = Object.create(P);
  • 原型、构造函数、实例、原型链

1、Object.prototype属性是整个原型链的顶端
2、原型链通过prototype原型和proto属性来查找的.
3、所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了“null”以
外)。
4、所有的引用类型(数组、对象、函数),都有一个proto属性,属性值是一个普通的对象(null除
外)。
5、所有的函数,都有prototype属性,属性值也是一个普通的对象。
6、所有的引用类型(数组、对象、函数),proto属性指向它的构造函数prototype属性值
7、实例本身的属性和方法如果没有找到,就会去找原型对象的属性和方法。如果在某一级找到
了,就会停止查找,并返回结果
1.2,instanceof的原理?
实例对象的proto属性和构造函数的prototype属性,判断是不是同一个引用
在这里插入图片描述
1、实例对象的属性引用的是构造函数的原型对象
2、instanceof用于判断引用类型属于哪个构造函数的方法

var M = function(name) {
    
    this.name = name};
var o3 = new M('o3');
console.log(o3 instanceof M); // true
console.log(o3 instanceof Object); // true,只要是原型链上的构造函数,都会被看成是
object的构造函数,都会返回true
console.log(o3.__proto__===M.prototype); // true
console.log(M.prototype.__proto__===Object.prototype); // true
console.log(o3.__proto__.constructor === M); // true,o3是M这个构造函数直接生成的
console.log(o3.__proto__.constructor === Object); // false
  • new运算符
    new运算符后面跟的是一个构造函数
var new2 = function(func) {
    
    
var o = Object.create(func.prototype);
var k = func.call(o); // call转移上下文
if (type k === 'Object') {
    
    
return k;
} else {
    
    
return o;
}
}
var o6 = new2(M);
console.log(o6 instanceof M); // true
o6 instanceof Object // true
o6.__proto__.constructor === M; // true
M.prototype.walk = function(){
    
    console.log('walk')};
o6.walk(); // 能成功

2、类
2.1,类的声明?
1、传统的构造函数,声明一个类

function Animal() {
    
    
this.name = 'name';
}

2、es6中的class声明

class Animal2{
    
    
constructor() {
    
    
this.name = name;
}
}

2.2,生成实例?/ 声明一个类,怎么生成类的实例?

/*实例化*/
console.log(new Animal(), new Animal2()); // 通过New就可以实例化一个类,如果没有参数,
Animal后面的()可以不要

3、继承
继承的本质是原型链
3.1,call、apply的共同点与区别?
1、改变了函数运行上下文
2、call()和apply()主要是能扩充函数赖以运行作用域。两者的作用方式相同,它们的区别在于接收参数
的方式不同,对于call()而言,第一个参数this与apply()相同,其他的参数必须直接传给函数,要一个一
个的列出来,而对于apply()来说,apply()可以接收一个数组或arguments对象。所以如何选择二者,
在于哪种给函数传参数的方式最简单。
3.2,用javascript实现对象的继承/ 继承的几种方式,这几种方式的优缺点?
方法1:借助构造函数实现继承(部分继承)

/**
* 借助构造函数实现继承
*/
function Parent1() {
    
    
this.name = 'parent';
}
Parent1.prototype.say = function() {
    
    }; // 不会被继承
function Child1() {
    
    
// 继承:子类的构造函数里执行父级构造函数
// 也可以用apply
// parent的属性都会挂载到child实例上去
// 借助构造函数实现继承的缺点:①如果parent1除了构造函数里的内容,还有自己原型链上的东西,
自己原型链上的东西不会被child1继承
// 任何一个函数都有prototype属性,但当它是构造函数的时候,才能起到作用(构造函数是有自己的
原型链的)
Parent1.call(this);
this.type = 'child1';
}
console.log(new Child1);

(1)如果父类的属性都在构造函数内,就会被子类继承。
(2)如果父类的原型对象上有方法,子类不会被继承。
方法2:借助原型链实现继承

/**
* 借助原型链实现继承
*/
function Parent2() {
    
    
this.name = 'name';
this.play = [1, 2, 3]
}
function Child2() {
    
    
this.type = 'child2';
}
Child2.prototype = new Parent2(); // prototype使这个构造函数的实例能访问到原型对象上
console.log(new Child2().__proto__);
console.log(new Child2().__proto__ === Child2.prototype); // true
var s1 = new Child2(); // 实例
var s2 = new Child2();
console.log(s1.play, s2.play);
s1.play.push(4);
console.log(s1.__proto__ === s2.__proto__); // true // 父类的原型对象

(1)原型链的基本原理:构造函数的实例能访问到它的原型对象上
(2)缺点:原型链中的原型对象,是共用的
方法3:组合方式

/**
* 组合方式
*/
function Parent3() {
    
    
this.name = 'name';
this.play = [1, 2, 3];
}
function Child3() {
    
    
Parent3.call(this);
this.type = 'child3';
}
Child3.prototype = new Parent3();
var s3 = new Child3();
var s4 = new Child3();
s3.play.push(4);
console.log(s3.play, s4.play);
// 父类的构造函数执行了2次
// 构造函数体会自动执行,子类继承父类的构造函数体的属性和方法

①组合方式优化1:

/**
* 组合继承的优化方式1:父类只执行了一次
*/
function Parent4() {
    
    
this.name = 'name';
this.play = [1, 2, 3];
}
function Child4() {
    
    
Parent4.call(this);
this.type = 'child4';
}
Child4.prototype = Parent4.prototype; // 继承父类的原型对象
var s5 = new Child4();
var s6 = new Child4();
console.log(s5 instanceof Child4, s5 instanceof Parent4); // true
console.log(s5.constructor); // Parent4 //prototype里有个constructor属性,子类和
父类的原型对象就是同一个对象, s5的constructor就是父类的constructor

②组合方式优化2(最优解决方案):

/**
* 组合继承优化2
*/
function Parent5() {
    
    
this.name = 'name';
this.play = [1, 2, 3];
}
function Child5() {
    
    
Parent5.call(this);
this.type = 'child5';
}
Child5.prototype = Object.create(Parent5.prototype); // Object.create创建的对象
就是参数
Child5.prototype.constructor = Child5;
var s7 = new Child5();
console.log(s7 instanceof Child5, s7 instanceof Parent5);
console.log(s7.constructor); // 构造函数指向Child5

优缺点:
原型链继承的缺点
1、字面量重写原型
一是字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。
2、借用构造函数(类式继承)
借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起。所以我们需要原型链+借用构造函数的模式,这种模式称为组合继承
3、组合式继承
组合式继承是比较常用的一种继承方法,其背后的思路是 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。
4、作用域
1、js没有块级作用域,有函数作用域、全局作用域。es6出现才有块级作用域。
4.1,说说你对作用域链的理解?
作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。
4.2,this?
1、作为构造函数执行

function Foo(name) {
    
    
this.name = name;
}
var f = new Foo('zhangsan');

2、作为对象属性执行

var obj = {
    
    
name: 'A',
printName: function() {
    
    
console.log(this.name);
}
}
obj.printName();

3、作为普通函数执行

function fn() {
    
    
console.log(this);
}
fn();

4、call apply bind

function fn1(name, age) {
    
    
alert(name);
console.log(this);
}
fn1.call({
    
    x: 100}, 'zhangsan', 20);
fn1.apply({
    
    x:100}, ['zhangsan', 20])
123456
var fn2 = function (name, age) {
    
     // 必须是函数表达式,不能是函数声明,即不能是function
fn2(name, age) {
    
    }
alert(name);
console.log(this);
}.bind({
    
    y:200});
fn2('zhangsan', 20);

4.3,请说出下列的值?

var items = document.getElementsByTagName('li');
var i,x;
i = 0;
l = items.length;
for (; i < x; i++) {
    
    
items[i].addEventListener('click', function() {
    
    
console.log(i);
})
}

x
1、i是全局变量,从0增加到x-1,最后一次x++后成为c成为x。最终点击输出的就是x。
4.4,请说出下列的值?

!function() {
    
    
'use strict';
str = 'A Ha~';
console.log(window.str);
var str = 'Haha~';
console.log(str);
}();

undefined Haha~
1、 console.log(window.str) 改成 cnosole.log(this.str) , 说出this.str打印出来的值
非严格模式下:undefined
严格模式下:报错。因为严格模式下,this为undefined,所以this.str报错
5、javaScripti闭包
1、闭包是函数和声明该函数的词法环境的组合。
2、使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念
5.1,闭包的特征?
1、函数嵌套函数
2.、函数内部可以引用外部的参数和变量
3、参数和变量不会被垃圾回收机制回收
5.2,闭包应用场景?
1、作为返回值

function fn() {
    
    
var max = 10;
return function bar(x) {
    
    
if (x > max) {
    
    
console.log(x);
}
}
}
var f1 = fn();
f1(15);

2、作为参数传递

var max = 10;
function fn(x) {
    
    
if (x > max) {
    
    
console.log(x);
}
}
(function(f) {
    
    
var max = 100;
f(15);
})(fn);

5.3,实际开发中闭包的应用?
闭包实际应用中主要用于封装变量,收敛权限

function isFirstLoad() {
    
    
var _list = []; // 有_的变量说明是私有变量,函数内部使用的
return function(id) {
    
    
if (_list.indexOf(id) >=0) {
    
     // 也可用includes
return false;
} else {
    
    
_list.push(id);
return true;
}
}
}
// 使用
var firstLoad = isFirstLoad();
console.log(firstLoad(10)); // true
console.log(firstLoad(10)); // false
console.log(firstLoad(20)); // true
// 你在isFirstLoad函数外面,根本不可能修改掉_list的值

5.4,请说出下列的值?

function num(a) {
    
    
'use strict';
var n = 10;
return function (b) {
    
    
n +=10;
return (a + b + n);
}
}
var n = num(10);
console.log(n(10));
console.log(n(10));

结果:40 50
1、 40 = 10 + 10 + 20;
2、50 = 10 + 10 + 30;
5.5,请说出下列的值?

function obj() {
    
    
this.name = 'Hu';
}
obj.prototype.getName = function() {
    
    
return this.name;
}
obj.prototype.delayCall = function() {
    
    
window.setTimeout(function() {
    
    
console.log(this.getName());
}, 300);
}
var o = new obj();
o.delayCall();

报错:this.getName() is not a function
1、这个时候的this指向window
5.6,请说出下列的值?

function fun(n, o) {
    
    
console.log(o);
return {
    
    
fun: function(m) {
    
    
return fun(m, n);
}
}
}
var a = fun(0);
a.fun(1);
a.fun(2);
a.fun(3);

结果:
undefined 0 0 0 0
undefined 0 1 2
undefined 0
1
1
6、js运行机制/ 单线程/ 异步
(2)javascript是单线程的,主线程拥有一个执行栈以及一个任务队列,主线程会依次执行代码,当遇
到异步函数时候,会先将该函数入栈,所有主线程函数运行完毕后再将异步函数出栈,直到所有的异步
函数执行完毕即可。
(3)Macrotask(宏任务)和Microtask(微任务)
都属于上述的异步任务中的一种,他们分别有如下API:
macrotask: setTimeout, setInterval, setImmediate, I/O, UI rendering
microtasks: process.nextTick, Promise, MutationObserver
(4)promise中的then方法的函数会被推入到microtasks队列中,而setTimeout函数会被推入到
macrotasks任务队列中,在每一次事件循环中,macrotask只会提取一个执行,而microtask会一直提取,直到microsoft队列为空为止。
6.1,如何理解js的单线程?
只有一个线程,同一时间只能做一件事情。
6.2,js为什么是单线程的?
避免dom渲染的冲突
1、浏览器需要渲染dom
2、js可以修改dom结构
3、js执行的时候,浏览器dom渲染会暂停
4、两段js也不能同时执行(都修改dom就冲突了)
5、webworder支持多线程,但是不能访问dom
6.3,同步和异步的区别是什么?分别举一个同步和异步的例子?
1、同步会阻塞代码执行,而异步不会。
2、alert是同步,setTimeout是异步。
同步:指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一
直等待下去,直到收到返回信息才继续执行下去;
异步:指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。

6.4,何时需要异步?
1、在可能发生等待的情况,等待也是占线程的一种
2、等待过程中不能像alert一样阻塞程序进行
3、因此,“等待的情况”都需要异步
6.5,什么是任务队列?
任务队列(task queue)主要分两种:
1、宏任务(macrotask):在新标准中叫task
(1)主要包括:script(整体代码),setTimeout,setInterval,setImmediate,I/O,ui rendering
2、微任务(microtask):在新标准中叫jobs
(1)主要包括:process.nextTick, Promise,MutationObserver(html5新特性)
扩展:
1、同步任务:在主线程上,排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
2、异步任务:不进入主线程,而进入“任务队列”(task queue)的任务,只有“任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
6.6,请说出下列值?

setTimeout(() => {
    
    
console.log('1')
new Promise((resolve) => {
    
    
resolve()
}).then(() => {
    
    
console.log('2')
})
}, 0);
setTimeout(() => {
    
    
console.log('3')
}, 0);
new Promise((resolve) => {
    
    
resolve()
}).then(() => {
    
    
console.log('4')
new Promise((resolve) => {
    
    
resolve()
}).then(() => {
    
    
console.log('5')
})
setTimeout(() => {
    
    
console.log('6')
}, 0);
})
new Promise((resolve) => {
    
    
resolve()
}).then(() => {
    
    
console.log('7')
})

结果:

4751236

6.7,栈和队列的区别?
1、栈的插入和删除操作都是在一端进行的,而队列的操作却是在两端进行的。
2、队列先进先出,栈先进后出。
3、栈只允许在表尾一端进行插入和删除,而队列只允许在表尾一端进行插入,在表头一端进行删除
6.8,栈和堆的区别?
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。
2、堆(数据结构):堆可以被看成是一棵树,如:堆排序;
栈(数据结构):一种先进后出的数据结构。

  • event loop
    6.9,什么是event loop?
    事件循环。
    1、js实现异步的具体解决方案:event-loop
    2、运行栈:执行同步任务的
    3、浏览器js引擎遇到了setTimeout,识别了这是一个异步任务,不会将其放入运行栈,而是把它拿
    走,拿走了之后也没有立马放到异步任务队列中,按延迟时间放入到任务队列中。同步任务没有正在执行的东西,就会读异步任务,把任务放到运行栈中,执行完了又去读异步任务,把任务放到运行栈中,如此循环。
    6.10,event-loop流程?
    1、同步代码,直接执行
    2、异步先放在任务队列中
    3、待同步函数执行完毕,轮询执行任务队列的函数
  • 任务队列
    6.11,哪些语句会放入异步任务队列中?
    1、定时任务:setTimeout、setInterval
    2、网络请求:ajax请求、动态 <img 加载
console.log('start');
var img = document.createElement('img');
img.onload = function() {
    
    
console.log('loaded');
}
img.src = 'https://ss0.baidu.com/60NW/a.jpg';
console.log('end');
// 打印出来的是start, end, loaded

3、事件绑定:dom事件
4、ES6中的promise.then中的函数
Promise 构造函数是同步执行的,promise.then 中的函数是异步执行的。
6.12,何时被放入任务队列?
1、类似onclick等,由浏览器内核的DOM binding模块处理,事件触发时,回调函数添加到任务队列
中;
2、setTimeout等,由浏览器内核的Timer模块处理,时间到达时,回调函数添加到任务队列中;
3、Ajax,由浏览器内核的Network模块处理,网络请求返回后,添加到任务队列中。
ajax加载完成,即ajax什么时候success,就什么时候把ajax中的函数放入到异步队列中
7、js数据类型
1、值类型/ 基本数据类型:undefined、string、number、boolean
引用类型:对象、数组、函数
2、复杂数据类型Object包括3种引用类型。
3、基本数据类型存储在栈中,复杂数据类型存储在堆中。
4、值类型:不会因为赋值而相互干扰。
5、false: 0、NaN、’’、null、undefined

var obj = {
    
    };
if (obj.a == null) {
    
    } // 判断a这个属性是否存在
function(a, b){
    
    if (a == null) {
    
    }} // 判断a这个参数是否存在

7.1、js使用typeof能得到的哪些类型?
typeof只能区分值类型

typeof undefined // undefined
typeof null // object
typeof console.log // function
typeof NaN // number

7.2,如何准确判断一个变量是数组类型?

instanceof Array

7.3、js变量按照存储方式区分为哪些类型,并描述其特点?
1、存储在栈中:值类型。
2、存储在堆中:引用类型
引用类型的”数据“存储在堆中,
引用类型”指向堆中的数据的指针“存储在栈中。
7.4,null和undefined的区别?
1、null是一个表示”无”的对象,是只有一个值的特殊类型,转为数值时为0;
undefined是一个表示”无”的原始值,表示一个空对象引用,转为数值时为NaN。
2、当声明的变量还未被初始化时,变量的默认值为undefined。
3、null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。
undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义。
4、null 和 undefined 的值相等,但类型不等
7.5,undefined的典型用法?
1、变量被声明了,但没有赋值时,就等于undefined。
2、调用函数时,应该提供的参数没有提供,该参数等于undefined。
3、对象没有赋值的属性,该属性的值为undefined。
4、函数没有返回值时,默认返回undefined。
7.6,null的典型用法?
1、作为函数的参数,表示该函数的参数不是对象。
2、作为对象原型链的终点。
7.7**,chrome60+浏览器中,a===b的是哪项?**
答案:B

// A
var a = b = 1;
b = 2;
// B
var a = {
    
    name: 'jack', age: 27};
var b = a;
b.name = 'may';
// C
var a = [1, 3, 5];
var b = [...a];
// D
var a = [1, 2, 3];
var b = a.push(4); // b = 4;

1、===,绝对等于(值和类型均相等)。
2、C选项:数组是复合数据结构,b是对a的复制,修改b不会对a产生影响。a、b的类型相同,但是值不同。
8、js中的内置函数/内置对象
8.1,js中有哪些内置函数/ 数据封装类对象?内置函数:
Number、String、Boolean
Array、Object、Function
Date、RegExp、Error
8.2,js中有哪些内置对象?
内置对象:
Math,Json
8.3,js变量按照存储方式区分为哪些类型,并描述其特点?
1、值类型和引用类型。
2、值类型存储的是值 ,赋值之后原变量的值不改变 。
3、 引用类型存储的是地址 ,赋值之后是把原变量的引用地址赋值给新变量 ,新变量改变原来的会跟
着改变。
8.4,字符串方法/ String对象方法?
String对象方法:
concat() includes indexOf() lastIndexOf() slice() toString() valueOf()
charAt() charCodeAt() endsWith fromCahrCode() match() repeat() replace()
search() split startsWith() substr() substring() toLowerCase() toUpperCase()
trim() toLocaleLowerCase `toLocaleUpperCase()
字符串属性:
constructor length prototype
8.5,数组方法/ Array对象方法?
Array对象方法:

concat() includes indexOf() lastIndexOf() slice() toString() valueOf()
copyWithin() entries() every() fill() filter() find() findIndex() forEach()
from() isArray() join() keys() map() pop() push() reduce() reduceRaight()
reverse() shift() some() sort() splice() ushift()

在这里插入图片描述数组属性:

constructor length prototype

8.6,数组API?
1、forEach 遍历所有元素

var arr = [1, 2, 3];
arr.forEach(function(item, index) {
    
    
// 遍历数组的所有元素
console.log(index, item);
});

2、every 判断所有元素是否都符合条件

var arr = [1, 2, 3];
var arr1 = arr.every(function(item, index) {
    
    
if (item < 4) {
    
    
return true;
}
})
console.log(arr1); // true

3、some 判断是否有至少一项元素符合条件

var arr = [1, 2, 3];
var result = arr.some(function(item, index) {
    
    
if (item < 2) {
    
    
return true;
}
})
console.log(result); // true

4、sort 排序

var arr = [1, 5, 2, 7, 3, 4];
var arr2 = arr.sort(function(a, b) {
    
    
// 从小到大
return a-b;
// 从大到小
return b-a;
})
console.log(arr2); // 1,2,3,4,5,7

5、map 对元素重新组装,生成新数组

var arr = [1, 5, 2, 7, 3, 4];
var arr2 = arr.map(function(item, index) {
    
    
return '<b>' + item + '</br>';
})
console.log(arr2);

6、filter 过滤符合条件的元素

var arr = [1, 2, 3, 4];
var arr2 = arr.filter(function(item, index) {
    
    
if (item>2) {
    
    
return true;
}
})
console.log(arr2); // [3, 4]

8.7,对象API?
1、for in

var obj = {
    
    x:100, y:200, z:300};
var key;
for(key in obj) {
    
    
if (obj.hasOwnProperty(key)) {
    
    
console.log(key);
}
}

9,数组去重
9.1,数组怎么去重?(方法)
1、使用数组方法indexOf来判断

function sele(arr){
    
    
var temp = [];
for( var i = 0 ; i < arr.length ; i++ ){
    
    
if( temp.indexOf( arr[ i ] ) == -1 ){
    
    
temp.push( arr[ i ] );
}
}
return temp;
}
var arr = ['aa', 'bb', 'cc', '', 1, 0, '1', 1, 'bb', null, undefined, null];
console.log(sele(arr));

2个缺点,一是效率问题,因为加上indexOf相当于是2重循环,二是indexOf的兼容性问题:IE8–不兼容。
2、使用数组方法indexOf第二种方法 IE8–不兼容

function sele( arr ) {
    
    
var temp = [];
for( var i = 0 ; i < arr.length ; i++ ){
    
    
if( arr.indexOf( arr[ i ] ) == i ){
    
    
temp.push( arr[ i ] );
}
}
return temp;
}

比方法(1)效率还要差
3、循环

function sele( arr ) {
    
    
var temp = [];
for( var i = 0 ; i < arr.length ; i++ ){
    
    
for( var j = i + 1 ; j < arr.length ; j++ ){
    
    
if( arr[ i ] === arr[ j ] ){
    
    
j = ++i;
}
}
temp.push( arr[ i ] );
}
return temp;
}
function unique3(array)
{
    
    
var result = [];
var hash = {
    
    };
for(var i=0; i<array.length; i++)
{
    
    
var key = (typeof array[i]) + array[i];
if(!hash[key])
{
    
    
result.push(array[i]);
hash[key] = true;
以上方法中之所以给key添加了类型前缀,是因为要区分’1’和15、使用es6中includes方法
6、es6的set
9.2,对上述数组去重方法速度比较?(性能)
console.time, console.timeEnd
9.3,一句话数组去重?
}
}
return result;
}
var arr = ['aa', 'bb', 'cc', '', 1, 0, '1', 1, 'bb', null, undefined, null];
console.log(unique3(arr));

以上方法中之所以给key添加了类型前缀,是因为要区分’1’和1。
5、使用es6中includes方法

function sele( arr ) {
    
    
var temp = [];
arr.forEach( ( v ) => {
    
    
temp.includes( v ) || temp.push( v );
} )
return temp;
}

6、es6的set

function unique(array){
    
    return Array.from(new Set(array));}
// 或者写成(建议写法)
const unique = arr => [...new Set(arr)]
// 也可以是
const unique = arr => {
    
    return [...new Set(arr)]}
var arr = ['aa', , '', 1, 0, '1', 1, , null, undefined, null];
console.log(unique(arr));

9.2,对上述数组去重方法速度比较?(性能)

console.time, console.timeEnd
var testArray = [];
for(var i=0; i<500000; i++)
{
    
    
testArray.push(parseInt(Math.random()*100));
}
function test(fn, name)
{
    
    
console.time(name);
fn(testArray);
console.timeEnd(name);
}
test(unique1, '第1种实现');
test(unique2, '第2种实现');
test(unique3, '第3种实现');
test(unique4, '第4种实现');

9.3,一句话数组去重?
new Set():Set本身是一个构造函数,用来生成Set数据结构

const unique = arr => [...new Set(arr)]
var arr = ['aa', , '', 1, 0, '1', 1, , null, undefined, null];
console.log(unique(arr));

9.4,保留数组中非重复元素?
indexOf 是查某个指定的字符串在字符串首次出现的位置(索引值从左往右0、1、2…) (也就是从前往后查)
lastIndexOf 是从右向左查某个指定的字符串在字符串中最后一次出现的位置(索引值从左往右0、1、2…)(也就是从后往前查)

let arr = [11, 23, 26, 23, 11, 9]
const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) ===
arr.lastIndexOf(i))
console.log(filterNonUnique(arr)); // [ 26, 9 ]

9.5,保留数组中重复元素?

let arr = [11, 23, 26, 23, 11, 9]
const filterUnique = arr => arr.filter(i => arr.indexOf(i) !==
arr.lastIndexOf(i))
console.log(filterUnique(arr)); // [ 11, 23, 23, 11 ]

10、js逻辑判断
一、 || 判断
1、只要‘||’前面为false,无论’||‘后面是true还是false, 结果都返回’||‘后面的值。
2、只要’||‘前面是true,无论’||‘后面是true还是false,结果都返回’||‘前面的值。
二、&& 判断
1、只要‘&&’前面是false,无论’&&‘后面是true还是false,结果都返回’&&‘前面的值。
2、只要’&&‘前面是true,无论’&&‘后面是true还是false,结果都返回’&&‘后面的值。
三、优先级顺序中,逻辑’&&‘的优先级高于逻辑’||’。

猜你喜欢

转载自blog.csdn.net/m0_46374969/article/details/112860255