前端学习笔记1

前端基础-js

2.1 let const var 相关

参考答案:

var ——ES5 变量声明方式

  1. 在变量未赋值时,变量undefined(为使用声明变量时也为undefined)
  2. 作用域——var的作用域为方法作用域;只要在方法内定义了,整个方法内的定义变量后的代码都可以使用

let——ES6变量声明方式

  1. 在变量为声明前直接使用会报错
  2. 作用域——let为块作用域——通常let比var 范围要小
  3. let禁止重复声明变量,否则会报错;var可以重复声明

const——ES6变量声明方式

  1. const为常量声明方式;声明变量时必须初始化,在后面出现的代码中不能再修改该常量的值

  2. const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动

2.2 js数据类型,区别

参考答案:

基本数据类型:

Number,String,Boolean,null,undefined,symbol,bigint(后两个为ES6新增)

引用数据类型:

object,function(proto Function.prototype)

object:普通对象,数组对象,正则对象,日期对象,Math数学函数对象。

两种数据存储方式:

基本数据类型是直接存储在栈中的简单数据段,占据空间小、大小固定,属于被频繁使用的数据。栈是存储基 本类型值和执行代码的空间。

引用数据类型是存储在堆内存中,占据空间大、大小不固定。引用数据类型在栈中存储了指针,该指针指向堆 中该实体的起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得实体。

两种数据类型的区别:

  1. 堆比栈空间大,栈比堆运行速度快。
  2. 堆内存是无序存储,可以根据引用直接获取。
  3. 基础数据类型比较稳定,而且相对来说占用的内存小。
  4. 引用数据类型大小是动态的,而且是无限的。
2.3 Object.assign的理解

参考答案:

作用:Object.assign可以实现对象的合并。

语法:Object.assign(target, ...sources)

解析

  1. Object.assign会将source里面的可枚举属性复制到target,如果和target的已有属性重名,则会覆盖。
  2. 后续的source会覆盖前面的source的同名属性。
  3. Object.assign复制的是属性值,如果属性值是一个引用类型,那么复制的其实是引用地址,就会存在引用共享的问题。
2.4 constructor的理解

参考答案:

创建的每个函数都有一个prototype(原型)对象,这个属性是一个指针,指向一个对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针。当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(继承自构造函数的prototype),指向构造函数的原型对象。注意当将构造函数的prototype设置为等于一个以对象字面量形式创建的新对象时,constructor属性不再指向该构造函数。

2.5 map 和 forEach 的区别

参考答案:

相同点:

  1. 都是循环遍历数组中的每一项
  2. 每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(索引值),arr(原数组)
  3. 匿名函数中的this都是指向window
  4. 只能遍历数组

不同点:

  1. map()会分配内存空间存储新数组并返回,forEach()不会返回数据。
  2. forEach()允许callback更改原始数组的元素。map()返回新的数组。
2.6 for of 可以遍历哪些对象

参考答案:

for…of…: 它是es6新增的一个遍历方法,但只限于迭代器(iterator), 所以普通的对象用for…of遍历
是会报错的。

可迭代的对象:包括Array, Map, Set, String, TypedArray, arguments对象等等

2.7 js静态类型检查

参考答案:

js是动态类型语言

静态类型语言 & 动态类型语言

静态类型语言:类型检查发生在编译阶段,因此除非修复错误,否则会一直编译失败

动态类型语言:只有在程序运行了一次的时候错误才会被发现,也就是在运行时,因此即使代码中包含了会 在运行时阻止脚本正常运行的错误类型,这段代码也可以通过编译

js静态类型检查的方法

Flow是Facebook开发和发布的一个开源的静态类型检查库,它允许你逐渐地向JavaScript代码中添加类型。

TypeScript是一个会编译为JavaScript的超集(尽管它看起来几乎像一种新的静态类型语言)

使用静态类型的优势

  • 可以尽早发现bug和错误
  • 减少了复杂的错误处理
  • 将数据和行为分离
  • 减少单元测试的数量
  • 提供了领域建模(domain modeling)工具
  • 帮助我们消除了一整类bug
  • 重构时更有信心

使用静态类型的劣势

  • 代码冗长
  • 需要花时间去掌握类型
2.8 indexof

参考答案:

语法:str.indexOf(searchValue [, fromIndex])

参数:searchValue:要被查找的字符串值。

如果没有提供确切地提供字符串,[searchValue 会被强制设置为 "undefined"], 然后在当前字符串中查 找这个值。

举个例子:'undefined'.indexOf() 将会返回0,因为 undefined 在位置0处被找到,但是 'undefine'.indexOf() 将会返回 -1 ,因为字符串 'undefined' 未被找到

fromIndex:可选

数字表示开始查找的位置。可以是任意整数,默认值为 0

如果 fromIndex 的值小于 0,或者大于 str.length ,那么查找分别从 0str.length 开始。(译者 注: fromIndex 的值小于 0,等同于为空情况; fromIndex 的值大于或等于 str.length ,那么结果 会直接返回 -1 。)

举个例子,'hello world'.indexOf('o', -5) 返回 4 ,因为它是从位置0处开始查找,然后 o 在位置 4处被找到。另一方面,'hello world'.indexOf('o', 11) (或 fromIndex 填入任何大于11的值) 将会返回 -1 ,因为开始查找的位置11处,已经是这个字符串的结尾了。

返回值:

查找的字符串 searchValue第一次出现的索引,如果没有找到,则返回 -1

若被查找的字符串 searchValue 是一个空字符串,则返回fromIndex。如果 fromIndex 值为空,或者 fromIndex 值小于被查找的字符串的长度,返回值和以下的 fromIndex 值一样。

如果 fromIndex 值大于等于字符串的长度,将会直接返回字符串的长度(str.length

特点:

  1. 严格区分大小写

  2. 在使用indexOf检索数组时,用‘===’去匹配,意味着会检查数据类型

2.9 iframe有什么优点、缺点

参考答案:

优点:

  1. iframe能够原封不动的把嵌入的网页展现出来。
  2. 如果有多个网页引用iframe,那么你只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷。
  3. 网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用。
  4. 如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决。

缺点:

  1. iframe会阻塞主页面的onload事件;
  2. iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载。会产生很多页面,不容易管理。
  3. iframe框架结构有时会让人感到迷惑,如果框架个数多的话,可能会出现上下、左右滚动条,会分散访问者的注意力,用户体验度差。
  4. 代码复杂,无法被一些搜索引擎索引到,这一点很关键,现在的搜索引擎爬虫还不能很好的处理iframe中的内容,所以使用iframe会不利于搜索引擎优化(SEO)。
  5. 很多的移动设备无法完全显示框架,设备兼容性差。
  6. iframe框架页面会增加服务器的http请求,对于大型网站是不可取的。
2.10 webComponents

参考答案:

Web Components 总的来说是提供一整套完善的封装机制来把 Web 组件化这个东西标准化,每个框架实现 的组件都统一标准地进行输入输出,这样可以更好推动组件的复用

包含四个部分

  1. Custom Elements

  2. HTML Imports

  3. HTML Templates

  4. Shadow DOM

Custom Elements

提供一种方式让开发者可以自定义 HTML 元素,包括特定的组成,样式和行为。支持 Web Components 标准的浏览器会提供一系列 API 给开发者用于创建自定义的元素,或者扩展现有元素。

HTML Imports

一种在 HTMLs 中引用以及复用其他的 HTML 文档的方式。这个 Import 很漂亮,可以简单理解为我们常见 的模板中的 include 之类的作用

HTML Templates

模板

Shadow DOM

提供一种更好地组织页面元素的方式,来为日趋复杂的页面应用提供强大支持,避免代码间的相互影响

2.12 变量提升

参考答案:

JavaScript是单线程语言,所以执行肯定是按顺序执行。但是并不是逐行的分析和执行,而是一段一段地分析执行,会先进行编译阶段然后才是执行阶段。在编译阶段阶段,代码真正执行前的几毫秒,会检测到所有的变量和函数声明,所有这些函数和变量声明都被添加到名为Lexical Environment的JavaScript数据结构内的内存中。所以这些变量和函数能在它们真正被声明之前使用。

2.13 作用域

参考答案:

**概念:**作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。

ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6 的到来,为我们提供了‘块级作用域’,可通过新增命令 let 和 const 来体现。

扩展:

var ——ES5 变量声明方式

  1. 在变量未赋值时,变量undefined(为使用声明变量时也为undefined)
  2. 作用域——var的作用域为方法作用域;只要在方法内定义了,整个方法内的定义变量后的代码都可以使用

let——ES6变量声明方式

  1. 在变量为声明前直接使用会报错
  2. 作用域——let为块作用域——通常let比var 范围要小
  3. let禁止重复声明变量,否则会报错;var可以重复声明

const——ES6变量声明方式

const为常量声明方式;声明变量时必须初始化,在后面出现的代码中不能再修改该常量的值

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动

2.14 HashMap 和 Array 有什么区别?

参考答案:

  1. 查找效率
    HashMap因为其根据hashcode的值直接算出index,所以其查找效率是随着数组长度增大而增加的。
    ArrayMap使用的是二分法查找,所以当数组长度每增加一倍时,就需要多进行一次判断,效率下降
  2. 扩容数量
    HashMap初始值16个长度,每次扩容的时候,直接申请双倍的数组空间。
    ArrayMap每次扩容的时候,如果size长度大于8时申请size*1.5个长度,大于4小于8时申请8个,小于4时申 请4个。这样比较ArrayMap其实是申请了更少的内存空间,但是扩容的频率会更高。因此,如果数据量比较大的时候,还是使用HashMap更合适,因为其扩容的次数要比ArrayMap少很多。
  3. 扩容效率
    HashMap每次扩容的时候重新计算每个数组成员的位置,然后放到新的位置。
    ArrayMap则是直接使用System.arraycopy,所以效率上肯定是ArrayMap更占优势。
  4. 内存消耗
    以ArrayMap采用了一种独特的方式,能够重复的利用因为数据扩容而遗留下来的数组空间,方便下一个ArrayMap的使用。而HashMap没有这种设计。 由于ArrayMap之缓存了长度是4和8的时候,所以如果频繁的使用到Map,而且数据量都比较小的时候,ArrayMap无疑是相当的是节省内存的。

总结
综上所述,数据量比较小,并且需要频繁的使用Map存储数据的时候,推荐使用ArrayMap。 而数据量比较大的 时候,则推荐使用HashMap。

2.15 HashMap和Object

参考答案:

ObjectsMaps 类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此(并且也没有其他内建的替代方式了)过去我们一直都把对象当成 Maps 使用。不过 MapsObjects 有一些重要的区别,在下列情况里使用 Map 会是更好的选择:

MapObject
意外的键Map 默认情况不包含任何键。只包含显式插入的键。一个 Object 有一个原型, 原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。注意: 虽然 ES5 开始可以用 Object.create(null) 来创建一个没有原型的对象,但是这种用法不太常见。
键的类型一个 Map的键可以是任意值,包括函数、对象或任意基本类型。一个Object 的键必须是一个 String 或是Symbol
键的顺序Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。一个 Object 的键是无序的注意:自ECMAScript 2015规范以来,对象确实保留了字符串和Symbol键的创建顺序; 因此,在只有字符串键的对象上进行迭代将按插入顺序产生键。
SizeMap 的键值对个数可以轻易地通过size 属性获取Object 的键值对个数只能手动计算
迭代Mapiterable 的,所以可以直接被迭代。迭代一个Object需要以某种方式获取它的键然后才能迭代。
性能在频繁增删键值对的场景下表现更好。在频繁添加和删除键值对的场景下未作出优化。
2.16 javascript中arguments相关的问题

参考答案:

arguments

在js中,我们在调用有参数的函数时,当往这个调用的有参函数传参时,js会把所传的参数全部存到一个叫arguments的对象里面。它是一个类数组数据

由来

Javascrip中每个函数都会有一个Arguments对象实例arguments,引用着函数的实参。它是寄生在js函数当中的,不能显式创建,arguments对象只有函数开始时才可用

作用

有了arguments这个对象之后,我们可以不用给函数预先设定形参了,可以动态地通过arguments为函数加入参数

2.17 instanceOf 原理,手动实现 function isInstanceOf (child, Parent)

参考答案

instanceof主要作用就是判断一个实例是否属于某种类型

let person = ``function``(){` `}``let no = ``new` `person()``no ``instanceof` `person``//true

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,告诉我们左边变量并非是右边变量的实例。

同时还要了解js的原型继承原理

图片说明

我们知道每个 JavaScript 对象均有一个隐式的 proto 原型属性,而显式的原型属性是 prototype,只有 Object.prototype.proto 属性在未修改的情况下为 null 值

手动实现

function` `instance_of(L, R) {``//L 表示左表达式,R 表示右表达式``  ``var` `O = R.prototype;``  ``L = L.__proto__;``  ``while` `(``true``) {``    ``if` `(L === ``null``)``    ``return` `false``;``    ``if` `(O === L) ``// 这里重点:当 O 严格等于 L 时,返回true``    ``return` `true``;``    ``L = L.__proto__;``  ``}``}``// 开始测试``var` `a = []``var` `b = {}` `function` `Foo(){}``var` `c = ``new` `Foo()``function` `child(){}``function` `father(){}``child.prototype = ``new` `father()``var` `d = ``new` `child()` `console.log(instance_of(a, Array)) ``// true``console.log(instance_of(b, Object)) ``// true``console.log(instance_of(b, Array)) ``// false``console.log(instance_of(a, Object)) ``// true``console.log(instance_of(c, Foo)) ``// true``console.log(instance_of(d, child)) ``// true``console.log(instance_of(d, father)) ``// true
2.18 数组去重

参考答案:

1. 利用ES6 Set去重(ES6中最常用)

function` `unique (arr) {`` ``return` `Array.from(``new` `Set(arr))``}``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``console.log(unique(arr))`` ``//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]

不考虑兼容性,这种去重的方法代码最少。这种方法还无法去掉“{}”空对象,后面的高阶方***添加去掉重复“{}”的方法。

2. 利用for嵌套for,然后splice去重(ES5中最常用)

function` `unique(arr){      ``    ``for``(``var` `i=0; i<arr.length; i++){``      ``for``(``var` `j=i+1; j<arr.length; j++){``        ``if``(arr[i]==arr[j]){     ``//第一个等同于第二个,splice方法删除第二个``          ``arr.splice(j,1);``          ``j--;``        ``}``      ``}``    ``}``return` `arr;``}``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``  ``console.log(unique(arr))``  ``//[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}]   //NaN和{}没有去重,两个null直接消失了

双层循环,外层循环元素,内层循环时比较值。值相同时,则删去这个值。

3. 利用indexOf去重

function` `unique(arr) {``  ``if` `(!Array.isArray(arr)) {``    ``console.log(``'type error!'``)``    ``return``  ``}``  ``var` `array = [];``  ``for` `(``var` `i = 0; i < arr.length; i++) {``    ``if` `(array .indexOf(arr[i]) === -1) {``      ``array .push(arr[i])``    ``}``  ``}``  ``return` `array;``}``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``console.log(unique(arr))``  ``// [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…}, {…}] //NaN、{}没有去重

新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。

4. 利用sort()

function` `unique(arr) {``  ``if` `(!Array.isArray(arr)) {``    ``console.log(``'type error!'``)``    ``return``;``  ``}``  ``arr = arr.sort()``  ``var` `arrry= [arr[0]];``  ``for` `(``var` `i = 1; i < arr.length; i++) {``    ``if` `(arr[i] !== arr[i-1]) {``      ``arrry.push(arr[i]);``    ``}``  ``}``  ``return` `arrry;``}``   ``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``    ``console.log(unique(arr))``// [0, 1, 15, "NaN", NaN, NaN, {…}, {…}, "a", false, null, true, "true", undefined]   //NaN、{}没有去重

利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。

5. 利用对象的属性不能相同的特点进行去重(这种数组去重的方法有问题,不建议用,有待改进)

function` `unique(arr) {``  ``if` `(!Array.isArray(arr)) {``    ``console.log(``'type error!'``)``    ``return``  ``}``  ``var` `arrry= [];``   ``var` `obj = {};``  ``for` `(``var` `i = 0; i < arr.length; i++) {``    ``if` `(!obj[arr[i]]) {``      ``arrry.push(arr[i])``      ``obj[arr[i]] = 1``    ``} ``else` `{``      ``obj[arr[i]]++``    ``}``  ``}``  ``return` `arrry;``}``  ``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``    ``console.log(unique(arr))``//[1, "true", 15, false, undefined, null, NaN, 0, "a", {…}]  //两个true直接去掉了,NaN和{}去重

6. 利用includes

function` `unique(arr) {``  ``if` `(!Array.isArray(arr)) {``    ``console.log(``'type error!'``)``    ``return``  ``}``  ``var` `array =[];``  ``for``(``var` `i = 0; i < arr.length; i++) {``      ``if``( !array.includes( arr[i]) ) {``//includes 检测数组是否有某个值``          ``array.push(arr[i]);``       ``}``  ``}``  ``return` `array``}``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``  ``console.log(unique(arr))``  ``//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]   //{}没有去重

7. 利用hasOwnProperty

function` `unique(arr) {``  ``var` `obj = {};``  ``return` `arr.filter(``function``(item, index, arr){``    ``return` `obj.hasOwnProperty(``typeof` `item + item) ? ``false` `: (obj[``typeof` `item + item] = ``true``)``  ``})``}``  ``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``    ``console.log(unique(arr))``//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}]  //所有的都去重了

利用hasOwnProperty 判断是否存在对象属性

8. 利用filter

function` `unique(arr) {`` ``return` `arr.filter(``function``(item, index, arr) {``  ``//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素``  ``return` `arr.indexOf(item, 0) === index;`` ``});``}``  ``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``    ``console.log(unique(arr))``//[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]

9. 利用递归去重

function` `unique(arr) {``    ``var` `array= arr;``    ``var` `len = array.length;` `  ``array.sort(``function``(a,b){  ``//排序后更加方便去重``    ``return` `a - b;``  ``})` `  ``function` `loop(index){``    ``if``(index >= 1){``      ``if``(array[index] === array[index-1]){``        ``array.splice(index,1);``      ``}``      ``loop(index - 1);  ``//递归loop,然后数组去重``    ``}``  ``}``  ``loop(len-1);``  ``return` `array;``}`` ``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``console.log(unique(arr))``//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]

10. 利用Map数据结构去重

function` `arrayNonRepeatfy(arr) {`` ``let map = ``new` `Map();`` ``let array = ``new` `Array(); ``// 数组用于返回结果`` ``for` `(let i = 0; i < arr.length; i++) {``  ``if``(map .has(arr[i])) { ``// 如果有该key值``   ``map .set(arr[i], ``true``);``  ``} ``else` `{``   ``map .set(arr[i], ``false``);  ``// 如果没有该key值``   ``array .push(arr[i]);``  ``}`` ``}`` ``return` `array ;``}`` ``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``  ``console.log(unique(arr))``//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]

创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。

11. 利用reduce+includes

function` `unique(arr){``  ``return` `arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);``}``var` `arr = [1,1,``'true'``,``'true'``,``true``,``true``,15,15,``false``,``false``, undefined,undefined, ``null``,``null``, NaN, NaN,``'NaN'``, 0, 0, ``'a'``, ``'a'``,{},{}];``console.log(unique(arr));``// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]

12. […new Set(arr)]

复制代码

[...``new` `Set(arr)]``//代码就是这么少----(其实,严格来说并不算是一种,相对于第一种方法来说只是简化了代码)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值