文章加密

;

2019年6月28日 星期五

問題:讓後端直接傳回錯誤訊息,結果無法進入if else判斷,測試typeof預想微字串,卻直接輸出了錯誤訊息。

function confirm() {
DMS.ajaxPost("../model/c_lend_return_manage.php","func=change&"+$('#form').serialize(),function(ret){
console.log(typeof ret) //银行名称格式不能含有特殊符号
if(ret==1){
DMS.success("提交成功");
}else if(ret==0){
DMS.alert('没有修改');
}else if(ret==2){
DMS.error("银行名称格式不能含有特殊符号");
}else if(ret==3){
DMS.error("银行账户名称格式不能含有特殊符号");
}else if(ret==4){
DMS.error("银行账号格式不能含有特殊符号");
}else if(ret==5){
DMS.error("开户分支格式不能含有特殊符号");
}else{
DMS.error('提交失败');
}
})
}


讓後端直接傳回錯誤訊息,結果無法進入if else判斷,測試typeof預想微字串,卻直接輸出了錯誤訊息。甚至if(ret=="银行名称格式不能含有特殊符号")也進不去
沒有找到答案

2019年6月25日 星期二

UTF8-BOM文件格式造成網頁中空行

https://www.twblogs.net/a/5b8776a92b71775d1cd74e71

<script type="text/javascript">
$(function(){

// 下面这段导致vue出不来,但能把空白移除
    if(document.body){
        document.body.innerHTML=document.body.innerHTML.replace(/\ufeff/g,'');
}

})
</script>

node_module裡的iview寫入console.log結果運行沒看見console.log,不曉得為啥?

node_module裡的iview寫入console.log結果運行沒看見console.log,不曉得為啥?

mixins在iview裡有寫,然後this.$on註冊事件不懂為啥不用method註冊就好

2019年6月22日 星期六

let list = [...this.list]; //為什麼這裡要解構賦值? Oberver,Watcher和Dep

https://segmentfault.com/a/1190000009054946

filteredAndOrderedList () {
let list = [...this.list]; //為什麼這裡要解構賦值?

// 按品牌过滤
if (this.filterBrand !== '') {
list = list.filter(item => item.brand === this.filterBrand);
}
// 按颜色过滤
if (this.filterColor !== '') {
list = list.filter(item => item.color === this.filterColor);
}
// 排序
if (this.order !== '') {
if (this.order === 'sales') {
list = list.sort((a, b) => b.sales - a.sales);
} else if (this.order === 'cost-desc') {
list = list.sort((a, b) => b.cost - a.cost);
} else if (this.order === 'cost-asc') {
list = list.sort((a, b) => a.cost - b.cost);
}
}
return list;
}

JavaScript property access: dot notation vs. brackets?


The two most common ways to access properties in JavaScript are with a dot and with square brackets. Both value.x and value[x] access a property on value—but not necessarily the same property. The difference is in how x is interpreted. When using a dot, the part after the dot must be a valid variable name, and it directly names the property. When using square brackets, the expression between the brackets is evaluated to get the property name. Whereas value.x fetches the property of value named “x”, value[x] tries to evaluate the expression x and uses the result as the property name.
So if you know that the property you are interested in is called “length”, you say value.length. If you want to extract the property named by the value held in the variable i, you say value[i]. And because property names can be any string, if you want to access a property named “2” or “John Doe”, you must use square brackets: value[2] or value["John Doe"]. This is the case even though you know the precise name of the property in advance, because neither “2” nor “John Doe”is a valid variable name and so cannot be accessed through dot notation.

2019年6月19日 星期三

vue computed下有时不加this指定data,不知道为啥?

vue computed下有时不加this指定data,不知道为啥?

<div @click="pressButton">ppp</div>

new Vue({
el:'#paytype',
data:{
getData:{},
bankKey:{},
bankValue:{}
},
computed:{
banks:function(){
return bankKey.map((item,index) =>{
return {
key:item,
value:bankValue[index]
}
})
}
},
created:function(){
axios.post('../model/c_lend_return_manage.php','func=getdata')
.then(function (response) {
this.getData=response;
this.bankKey=Object.keys(response.data.banks[0]);
this.bankValue=Object.values(response.data.banks[0]);
})
.catch(function (error) {
console.log(error);
});
},
methods:{
pressButton:function(){
console.log('1',this.banks)
},
bankData:function(key){
switch(key){
case 'bank_num':
return '银行账号';
case 'bank_name':
return '银行账户名';
case 'bank_zhi':
return '开户支行';
default:
return '银行名称';
}
}
}

})



这里要加this

<div id="app">
  <p>原始訊息:${ message }</p>
  <p>反轉訊息:${ reversedMessage }</p>
</div>
var vm = new Vue({
  el: '#app',
  delimiters: ['${', '}'],
  data: {
    message: 'Hello World!'
  },
  computed: {
    reversedMessage: function() {
      return this.message.split('').reverse().join('');
    }
  }
});

2019年6月17日 星期一

js面試考題

https://juejin.im/post/5d0644976fb9a07ed064b0ca

new 建構子的部分全忘了!

沒了解過undefined, referenceError, typeerror出現的時機及其對應的原因

4. 下面代码的输出是什么?

+true;
!"Lydia";
  • A: 1 and false
  • B: false and NaN
  • C: false and false









答案 答案: A
一元加号会尝试将boolean类型转换为数字类型。 true被转换为1false被转换为0
字符串'Lydia'是一个真值。 我们实际上要问的是“这个真值是假的吗?”。 这会返回false


6. 下面代码的输出是什么?

let c = { greeting: "Hey!" };
let d;

d = c;
c.greeting = "Hello";
console.log(d.greeting);
  • A: Hello
  • B: undefined
  • C: ReferenceError
  • D: TypeError








答案 答案: A
JavaScript中,当设置它们彼此相等时,所有对象都通过引用进行交互。
首先,变量c为对象保存一个值。 之后,我们将d指定为c与对象相同的引用。
更改一个对象时,可以更改所有对象。

第六題其實是by value和by reference那個~

7. 下面代码的输出是什么?

let a = 3;
let b = new Number(3);
let c = 3;

console.log(a == b);
console.log(a === b);
console.log(b === c);
  • A: true false true
  • B: false false true
  • C: true false false
  • D: false true true








答案 答案: C
new Number()是一个内置的函数构造函数。 虽然它看起来像一个数字,但它并不是一个真正的数字:它有一堆额外的功能,是一个对象。
当我们使用==运算符时,它只检查它是否具有相同的值。 他们都有3的值,所以它返回true
译者注:==会引发隐式类型转换,右侧的对象类型会自动拆箱为Number类型。
然而,当我们使用===操作符时,类型和值都需要相等,new Number()不是一个数字,是一个对象类型。两者都返回 false



8. 下面代码的输出是什么?

class Chameleon {
  static colorChange(newColor) {
    this.newColor = newColor;
  }

  constructor({ newColor = "green" } = {}) {
    this.newColor = newColor;
  }
}

const freddie = new Chameleon({ newColor: "purple" });
freddie.colorChange("orange");
  • A: orange
  • B: purple
  • C: green
  • D: TypeError








答案 答案: D
colorChange方法是静态的。 静态方法仅在创建它们的构造函数中存在,并且不能传递给任何子级。 由于freddie是一个子级对象,函数不会传递,所以在freddie实例上不存在freddie方法:抛出TypeError



9. 下面代码的输出是什么?

let greeting;
greetign = {}; // Typo!
console.log(greetign);
  • A: {}
  • B: ReferenceError: greetign is not defined
  • C: undefined








答案 答案: A
控制台会输出空对象,因为我们刚刚在全局对象上创建了一个空对象! 当我们错误地将greeting输入为greetign时,JS解释器实际上在浏览器中将其视为global.greetign = {}(或window.greetign = {})。
为了避免这种情况,我们可以使用“use strict”。 这可以确保在将变量赋值之前必须声明变量。

10. 当我们这样做时会发生什么?

function bark() {
  console.log("Woof!");
}

bark.animal = "dog";
  • A: Nothing, this is totally fine!
  • B: SyntaxError. You cannot add properties to a function this way.
  • C: undefined
  • D: ReferenceError







答案 答案: A
这在JavaScript中是可能的,因为函数也是对象!(原始类型之外的所有东西都是对象)
函数是一种特殊类型的对象。您自己编写的代码并不是实际的函数。 该函数是具有属性的对象,此属性是可调用的。

11. 下面代码的输出是什么?

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

const member = new Person("Lydia", "Hallie");
Person.getFullName = () => this.firstName + this.lastName;

console.log(member.getFullName());
  • A: TypeError
  • B: SyntaxError
  • C: Lydia Hallie
  • D: undefined undefined







答案 答案: A
您不能像使用常规对象那样向构造函数添加属性。 如果要一次向所有对象添加功能,则必须使用原型。 所以在这种情况下应该这样写:
Person.prototype.getFullName = function () {
  return `${this.firstName} ${this.lastName}`;
}
这样会使member.getFullName()是可用的,为什么样做是对的? 假设我们将此方法添加到构造函数本身。 也许不是每个Person实例都需要这种方法。这会浪费大量内存空间,因为它们仍然具有该属性,这占用了每个实例的内存空间。 相反,如果我们只将它添加到原型中,我们只需将它放在内存中的一个位置,但它们都可以访问它!

12. 下面代码的输出是什么?

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

const lydia = new Person("Lydia", "Hallie");
const sarah = Person("Sarah", "Smith");

console.log(lydia);
console.log(sarah);
  • A: Person {firstName: "Lydia", lastName: "Hallie"} and undefined
  • B: Person {firstName: "Lydia", lastName: "Hallie"} and Person {firstName: "Sarah", lastName: "Smith"}
  • C: Person {firstName: "Lydia", lastName: "Hallie"} and {}
  • D:Person {firstName: "Lydia", lastName: "Hallie"} and ReferenceError






答案 答案: A
对于sarah,我们没有使用new关键字。 使用new时,它指的是我们创建的新空对象。 但是,如果你不添加new它指的是全局对象!
我们指定了this.firstName等于'Sarahthis.lastName等于Smith。 我们实际做的是定义global.firstName ='Sarah'global.lastName ='Smithsarah本身的返回值是undefined



12. 事件传播的三个阶段是什么??

  • A: 目标 > 捕获 > 冒泡
  • B: 冒泡 > 目标 > 捕获
  • C: 目标 > 冒泡 > 捕获
  • D: 捕获 > 目标 > 冒泡






答案 答案: D
在捕获阶段,事件通过父元素向下传递到目标元素。 然后它到达目标元素,冒泡开始。

13. 所有对象都有原型.

  • A: 对
  • B: 错误






答案 答案: B
基础对象外,所有对象都有原型。 基础对象可以访问某些方法和属性,例如.toString。 这就是您可以使用内置JavaScript方法的原因! 所有这些方法都可以在原型上找到。 虽然JavaScript无法直接在您的对象上找到它,但它会沿着原型链向下寻找并在那里找到它,这使您可以访问它。
译者注:基础对象指原型链终点的对象。基础对象的原型是null

15. 下面代码的输出是什么?

let number = 0;
console.log(number++);
console.log(++number);
console.log(number);
  • A: 1 1 2
  • B: 1 2 2
  • C: 0 2 2
  • D: 0 1 2






答案 答案: C
后缀一元运算符++
  1. 返回值(返回0
  2. 增加值(数字现在是1
前缀一元运算符++
  1. 增加值(数字现在是2
  2. 返回值(返回2
所以返回0 2 2

16. 下面代码的输出是什么?

function getPersonInfo(one, two, three) {
  console.log(one);
  console.log(two);
  console.log(three);
}

const person = "Lydia";
const age = 21;

getPersonInfo`${person} is ${age} years old`;
  • A: Lydia 21 ["", "is", "years old"]
  • B: ["", "is", "years old"] Lydia 21
  • C: Lydia ["", "is", "years old"] 21






答案 答案: B
如果使用标记的模板字符串,则第一个参数的值始终是字符串值的数组。 其余参数获取传递到模板字符串中的表达式的值!

17. 下面代码的输出是什么?

function checkAge(data) {
  if (data === { age: 18 }) {
    console.log("You are an adult!");
  } else if (data == { age: 18 }) {
    console.log("You are still an adult.");
  } else {
    console.log(`Hmm.. You don't have an age I guess`);
  }
}

checkAge({ age: 18 });
  • A: You are an adult!
  • B: You are still an adult.
  • C: Hmm.. You don't have an age I guess






答案 答案: C
在比较相等性,原始类型通过它们的值进行比较,而对象通过它们的引用进行比较。JavaScript检查对象是否具有对内存中相同位置的引用。
我们作为参数传递的对象和我们用于检查相等性的对象在内存中位于不同位置,所以它们的引用是不同的。
这就是为什么{ age: 18 } === { age: 18 }{ age: 18 } == { age: 18 } 返回 false的原因。

20. 下面代码的输出是什么?

function getAge() {
  "use strict";
  age = 21;
  console.log(age);
}

getAge();
  • A: 21
  • B: undefined
  • C: ReferenceError
  • D: TypeError






答案 答案: C
使用“use strict”,可以确保不会意外地声明全局变量。 我们从未声明变量age,因为我们使用``use strict',它会引发一个ReferenceError。 如果我们不使用“use strict”,它就会起作用,因为属性age`会被添加到全局对象中。

21. 下面代码的输出是什么?

const sum = eval("10*10+5");
  • A: 105
  • B: "105"
  • C: TypeError
  • D: "10*10+5"






答案 答案: A
eval会为字符串传递的代码求值。 如果它是一个表达式,就像在这种情况下一样,它会计算表达式。 表达式为10 * 10 + 5计算得到105

22. cool_secret可以访问多长时间?

sessionStorage.setItem("cool_secret", 123);
  • A:永远,数据不会丢失。
  • B:用户关闭选项卡时。
  • C:当用户关闭整个浏览器时,不仅是选项卡。
  • D:用户关闭计算机时。






答案 答案: B
关闭选项卡后,将删除存储在sessionStorage中的数据。
如果使用localStorage,数据将永远存在,除非例如调用localStorage.clear()


25. 下面代码的输出是什么?

const obj = { a: "one", b: "two", a: "three" };
console.log(obj);
  • A: { a: "one", b: "two" }
  • B: { b: "two", a: "three" }
  • C: { a: "three", b: "two" }
  • D: SyntaxError





答案 答案: C
如果对象有两个具有相同名称的键,则将替前面的键。它仍将处于第一个位置,但具有最后指定的值。



29. 下面代码的输出是什么?

const a = {};
const b = { key: "b" };
const c = { key: "c" };

a[b] = 123;
a[c] = 456;

console.log(a[b]);
  • A: 123
  • B: 456
  • C: undefined
  • D: ReferenceError




答案 答案: B
对象键自动转换为字符串。我们试图将一个对象设置为对象a的键,其值为123
但是,当对象自动转换为字符串化时,它变成了[Object object]。 所以我们在这里说的是a["Object object"] = 123。 然后,我们可以尝试再次做同样的事情。 c对象同样会发生隐式类型转换。那么,a["Object object"] = 456
然后,我们打印a[b],它实际上是a["Object object"]。 我们将其设置为456,因此返回456

30. 下面代码的输出是什么?

const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"));
const baz = () => console.log("Third");

bar();
foo();
baz();
  • A: First Second Third
  • B: First Third Second
  • C: Second First Third
  • D: Second Third First




答案 答案: B
我们有一个setTimeout函数并首先调用它。 然而却最后打印了它。
这是因为在浏览器中,我们不只有运行时引擎,我们还有一个叫做WebAPI的东西。WebAPI为我们提供了setTimeout函数,例如DOM
callback推送到WebAPI后,setTimeout函数本身(但不是回调!)从堆栈中弹出。


33. 下面代码的输出是什么?

const person = { name: "Lydia" };

function sayHi(age) {
  console.log(`${this.name} is ${age}`);
}

sayHi.call(person, 21);
sayHi.bind(person, 21);
复制代码
  • A: undefined is 21 Lydia is 21
  • B: function function
  • C: Lydia is 21 Lydia is 21
  • D: Lydia is 21 function


答案 答案: D
使用两者,我们可以传递我们想要this关键字引用的对象。 但是,.call方法会立即执行!
.bind方法会返回函数的拷贝值,但带有绑定的上下文! 它不会立即执行。

34. 下面代码的输出是什么?

function sayHi() {
  return (() => 0)();
}

typeof sayHi();
复制代码
  • A: "object"
  • B: "number"
  • C: "function"
  • D: "undefined"


答案 答案: B
sayHi函数返回立即调用的函数(IIFE, Immediately Invoked Functions Expressions, 立刻處發函式)的返回值。 该函数返回0,类型为数字
仅供参考:只有7种内置类型:nullundefinedbooleannumberstringobjectsymbolfunction不是一个类型,因为函数是对象,它的类型是object
相關閱讀 https://ithelp.ithome.com.tw/articles/10193313


35. 下面这些值哪些是假值?

0;
new Number(0);
("");
(" ");
new Boolean(false);
undefined;
  • A: 0, '', undefined
  • B: 0, new Number(0), '', new Boolean(false), undefined
  • C: 0, '', new Boolean(false), undefined
  • D: 所有都是假值
答案 答案: A
JavaScript中只有6个假值:
  • undefined
  • null
  • NaN
  • 0
  • '' (empty string)
  • false
函数构造函数,如new Numbernew Boolean都是真值。


37. 下面代码的输出是什么?

const numbers = [1, 2, 3];
numbers[10] = 11;
console.log(numbers);
  • A: [1, 2, 3, 7 x null, 11]
  • B: [1, 2, 3, 11]
  • C: [1, 2, 3, 7 x empty, 11]
  • D: SyntaxError
答案 答案: C
当你为数组中的元素设置一个超过数组长度的值时,JavaScript会创建一个名为“空插槽”的东西。 这些位置的值实际上是undefined,但你会看到类似的东西:
[1, 2, 3, 7 x empty, 11]
这取决于你运行它的位置(每个浏览器有可能不同)。



38. 下面代码的输出是什么?

(() => {
  let x, y;
  try {
    throw new Error();
  } catch (x) {
    (x = 1), (y = 2);
    console.log(x);
  }
  console.log(x);
  console.log(y);
})();
  • A: 1 undefined 2
  • B: undefined undefined undefined
  • C: 1 1 2
  • D: 1 undefined undefined
答案 答案: A
catch块接收参数x。当我们传递参数时,这与变量的x不同。这个变量x是属于catch作用域的。
之后,我们将这个块级作用域的变量设置为1,并设置变量y的值。 现在,我们打印块级作用域的变量x,它等于1
catch块之外,x仍然是undefined,而y2。 当我们想在catch块之外的console.log(x)时,它返回undefined,而y返回2
相關連結:
throw : https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/throw




2019年6月16日 星期日

陣列去重/排重 1.for迴圈的變數以var設定則會把最後的值往下帶!而不是終結在for回圈裡!要終結再for迴圈要用let或const 2.对一个已经排好序的数组去重,这种方法效率肯定高于使用 indexOf! 3.以function做判斷式,結果為true 4.把数组的值存成 Object 的 key 值 5. ES6,Array.from()函数的用法

本篇以陣列去重為主題,目的是形成unique的function
https://github.com/mqyqingfeng/Blog/issues/27

1. for迴圈的變數以var設定則會把最後的值往下帶!而不是終結在for回圈裡!要終結再for迴圈要用let或const

var array = [1, 1, '1', '1'];

function unique(array) {
    // res用来存储结果
    var res = [];
    for (var i = 0, arrayLen = array.length; i < arrayLen; i++) {
        for (var j = 0, resLen = res.length; j < resLen; j++ ) {
            if (array[i] === res[j]) {
                break;  //如果不break,會再執行下一圈,最後一層j === resLen,接著
往下帶,就把重複的值也寫入res[]
            }
        }
        // 如果array[i]是唯一的,那么执行完循环,j等于resLen
        if (j === resLen) {
            res.push(array[i])
        }
    }

console.log(i) //結果為4!!!
   return res;
}

console.log(unique(array)); // [1, "1"]


2. 对一个已经排好序的数组去重,这种方法效率肯定高于使用 indexOf!



var array = [1, 1, '1'];

function unique(array) {
var res = [];
var sortedArray = array.concat().sort(); //.concat()在這裡沒啥作用
var seen;
for (var i = 0, len = sortedArray.length; i < len; i++) {
// 如果是第一个元素或者相邻的元素不相同
if (!i || seen !== sortedArray[i]) {
res.push(sortedArray[i])
seen = sortedArray[i];
}
}
return res;
}

console.log(unique(array));





比如使用 indexOf 的方法:(或是用es6的includes,他會回傳true或false,並且可判對NaN, 空值)
var array = [1, 2, 1, 1, '1'];

function unique(array) {
    var res = array.filter(function(item, index, array){
        return array.indexOf(item) === index;
    })
    return res;
}

console.log(unique(array));
排序去重的方法:
var array = [1, 2, 1, 1, '1'];

function unique(array) {
    return array.concat().sort().filter(function(item, index, array){
        return !index || item !== array[index - 1]
    })
}

console.log(unique(array));



3. 以function做判斷式,結果為true


var array3 = [1, 1, 'a', 'A', 2, 2];

// 第二版
// iteratee 英文释义:迭代 重复
function unique(array, isSorted, iteratee) {
    var res = [];
    var seen = [];

    for (var i = 0, len = array.length; i < len; i++) {
        var value = array[i];
        var computed = iteratee ? iteratee(value, i, array) : value;  //這行寫得有點多餘,不曉得為什
麼要做判斷,因為interatee結果必為true。又interatee只接收一個參數,所以寫入的第二第三個參數其實沒用,可改
寫為 var computed =  iteratee(value); 結果相同!(後來想想,大概是為了通用做鋪墊)

        if (isSorted) {
            if (!i || seen !== computed) {
                res.push(value)
            }
            seen = computed;
        }
        else if (iteratee) {
            if (seen.indexOf(computed) === -1) {
                seen.push(computed);
                res.push(value);
            }
        }
        else if (res.indexOf(value) === -1) {
            res.push(value);
        }        
    }
    return res;
}

console.log(unique(array3, false, function(item){
    return typeof item == 'string' ? item.toLowerCase() : item
})); // [1, "a", 2]


4.把数组的值存成 Object 的 key 值

var array = [1, 2, 1, 1, '1'];

function unique(array) {
    var obj = {};
    return array.filter(function(item, index, array){
        return obj.hasOwnProperty(item) ? false : (obj[item] = true)
    })
}

console.log(unique(array)); // [1, 2]
但是这种方法会判断 1 和 '1' 为同一个值,这是因为对象的键值只能是字符串,可以改用  return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true) 區分型態

但如果array的value帶入的是object,如 var array = [{value: 1}, {value: 1}, {value: 2}]; ,則需改為 return obj.hasOwnProperty(typeof item + JSON.stringify(item)) ? false : (obj[typeof item + JSON.stringify(item)] = true)



5. ES6,Array.from()函数的用法
ES6为Array增加了from函数用来将其他对象转换成数组。
当然,其他对象也是有要求,也不是所有的,可以将两种对象转换成数组。
1.部署了Iterator接口的对象,比如:Set,Map,Array。
2.类数组对象,什么叫类数组对象,就是一个对象必须有length属性,没有length,转出来的就是空数组。
var array = [1, 2, 1, 1, '1'];

function unique(array) {
   return Array.from(new Set(array));
}

console.log(unique(array)); // [1, 2, "1"]
甚至可以再简化下:
function unique(array) {
    return [...new Set(array)];
}
还可以再简化下:
var unique = (a) => [...new Set(a)]
此外,如果用 Map 的话:
function unique (arr) {
    const seen = new Map()
    return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
}

最後,總結與特殊类型比较


去重的方法就到此结束了,然而要去重的元素类型可能是多种多样,除了例子中简单的 1 和 '1' 之外,其实还有 null、undefined、NaN、对象等,那么对于这些元素,之前的这些方法的去重结果又是怎样呢?
在此之前,先让我们先看几个例子:
var str1 = '1';
var str2 = new String('1');

console.log(str1 == str2); // true
console.log(str1 === str2); // false

console.log(null == null); // true
console.log(null === null); // true

console.log(undefined == undefined); // true
console.log(undefined === undefined); // true

console.log(NaN == NaN); // false
console.log(NaN === NaN); // false

console.log(/a/ == /a/); // false
console.log(/a/ === /a/); // false

console.log({} == {}); // false
console.log({} === {}); // false
那么,对于这样一个数组
var array = [1, 1, '1', '1', null, null, undefined, undefined, new String('1'), new String('1'), /a/, /a/, NaN, NaN];
以上各种方法去重的结果到底是什么样的呢?
我特地整理了一个列表,我们重点关注下对象和 NaN 的去重情况
方法结果说明
for循环[1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN]对象和 NaN 不去重
indexOf[1, "1", null, undefined, String, String, /a/, /a/, NaN, NaN]对象和 NaN 不去重
sort[/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined]对象和 NaN 不去重 数字 1 也不去重
filter + indexOf[1, "1", null, undefined, String, String, /a/, /a/]对象不去重 NaN 会被忽略掉
filter + sort[/a/, /a/, "1", 1, String, 1, String, NaN, NaN, null, undefined]对象和 NaN 不去重 数字 1 不去重
优化后的键值对方法[1, "1", null, undefined, String, /a/, NaN]全部去重
Set[1, "1", null, undefined, String, String, /a/, /a/, NaN]对象不去重 NaN 去重
想了解为什么会出现以上的结果,看两个 demo 便能明白:
// demo1
var arr = [1, 2, NaN];
arr.indexOf(NaN); // -1
indexOf 底层还是使用 === 进行判断,因为 NaN === NaN的结果为 false,所以使用 indexOf 查找不到 NaN 元素
// demo2
function unique(array) {
   return Array.from(new Set(array));
}
console.log(unique([NaN, NaN])) // [NaN]
Set 认为尽管 NaN === NaN 为 false,但是这两个元素是重复的。