一、"=="与"==="

1."=="

相等运算符==用于检查两个操作数是否相等,并返回Boolean结果。

所用算法(抽象相等比较算法)概括:

  • 如果两个操作数所属数据类型不同,则会在比较前将他们转换为相同类型的数据。
  • Number vs String:尝试将字符串转换为数字值。
  • Boolean vs 其他类型:将布尔值转换为1或0。
  • Object vs Number&String:尝试使用valueOf()toString()方法将对象转换为原始值。
  • 如果两个操作数所属数据类型相同,则按如下规则进行比较:
  • String:仅当两个操作数具有相同顺序的相同字符时才返回true
  • Number:仅当两个操作数具有相同的值时才返回true。+0并被-0视为相同的值。如果任一操作数为NaN,则返回false
  • Boolean:仅当操作数为两个true或两个false时才返回true
  • Object:仅当两个操作数有相同的引用时才返回true。例如:
const object1 = {"key": "value"} 
const object2 = {"key": "value"}; 

object1 == object2 // false 
object2 == object2 // true

2."==="

全等运算符 (===) 会检查它的两个操作数是否相等,并且返回一个布尔值结果。与相等运算符不同,全等运算符并不自动进行类型转换,所以总是认为不同类型的操作数是不同的。

所用算法(全等比较算法)概括:

  • 如果两个操作数的类型不同,则返回false
  • 如果两个操作数都是对象的引用,则当他们指向同一个对象时才返回true
  • 如果两个操作数都为null,或都为undefined,则返回true
  • 如果两个操作数有任意一个为NaN,则返回false
  • 以上条件均满足时,比较两个操作数的值。

3."=="与"==="的主要区别:

全等运算符(===)与相等运算符(==)最显著的区别是,如果操作数的类型不同,== 运算符会在比较之前尝试将它们转换为相同的类型。

二、浅比较与深比较

ECMAScript的数据类型分为两类:基本类型值和引用类型值。进行赋值操作时,解析器必须清楚该值为哪个类型的数据。

基本数据类型是按值访问的,所以可以直接操作保存在变量中的值。

引用数据类型的值是保存在内存中的对象。在JavaScript中,不允许直接操作对象的内存空间。例如复制对象时,实际上是复制的对象的引用。但是为对象添加属性时,操作的时实际的对象。

1.浅比较

浅比较,即检查引用是否相等。在JavaScript中,===作浅比较,即检查两个操作数是否为同一个对象的引用。例如:

let obj01 = { key : value};
let obj02 = { key : value};

console.log(obj01 === obj02)  //false

2.深比较

深比较,即检查两个对象的所有属性是否相等,但不关心两个对象是否为同一个对象的引用。深比较需要以递归的方式遍历两个对象的所有属性,操作比较耗时。

三、浅拷贝与深拷贝

  • 浅拷贝:复制对象的所有变量都含有与原来的对象相同的值,改变任何一个对象,其他对象的值都会被改变
  • 深拷贝:不仅将原对象的各个属性复制过来,而且对原对象所包含的各个属性中的对象也依次采用深拷贝的方式递归的复制到新对象上;深拷贝时,一个对象的改变不会影响另一个对象

实现深拷贝的方式:

目标对象是数组【arr1 = [4,5,2]】

1. for... in

let arr2 = []
for (let index in arr1) {
  arr2[index] = arr1[index]
}

2. let arr2 = arr1.slice(0)

3. let arr2 = Array.from(arr1)

4. let arr2 = arr1.concat()

5. 扩展运算符 let [...arr2] = arr1

目标对象是普通对象

1. let arr2 = JSON.parse(JSON.stringify(arr1))

解决了传址和值互相影响的问题,但由于返回了新对象,会丢失function函数和undefined变量

2. 使用lodash的cloneDeep方法  let arr2 = lodash.cloneDeep(arr1)

3. 自定义方法

export default function deepCopy (obj) {
  if (typeof obj !== 'object') {
    // 对基本类型进行判断
    return obj
  } else if (Object.prototype.toString.call(obj) === '[object Null]') {
    // typeof null = object, 需要单独判断
    return obj
  } else {
    // 实现对数组及对象的深拷贝
    let result = Array.isArray(obj) ? [] : {}
    // for in 遍历对象和原型链上的属性和方法
    for (let key in obj) {
      // 判断是否是对象的自身内容,如果是才去做深拷贝
      // hasOwnPropertys()方法返回一个布尔值,判断对象是否包含特定的自身非继承属性
      if (obj.hasOwnProperty(key)) {
        // 判断是否是对象
        if (obj[key] && typeof obj[key] === 'object') {
          result[key] = deepCopy(obj[key])
        } else {
          result[key] = obj[key]
        }
      }
    }

    return result
  }
}