三目运算

「三目运算符」也称为「三元运算符」。
三目运算符可以使我们简单判断语句,比如用if判断语句:

  1. var a = 5;
  2. if (a > 0) {
  3. console.log("大于0");
  4. } else {
  5. console.log("小于等于0");
  6. }

利用三目运算可以简化成:

  1. var a = 5;
  2. a > 0 ? console.log("大于0") : console.log("小于等于0");

三目运算还具有return的功能:

  1. var a = 5;
  2. var str = a > 0 ? "大于0" : "小于等于0";
  3. console.log(str); // "大于0"

三目运算还能嵌套使用:

  1. var a = 5;
  2. var str1 = a > 0
  3. ? (a > 3 ? "大于3" : "小于3")
  4. : "小于等于0";
  5. console.log(str1); // "大于3"

面试题:

  1. // 请问 str 打印什么?
  2. var str = 89 > 9
  3. ? ("89" > "9" ? "通过了" : "内层未通过")
  4. : "外层未通过";
  5. console.log(str)
  6. // 解析:
  7. // 先判断 89 > 9 肯定是 true
  8. // 然后来到 ("89" > "9" ? "通过了" : "内层未通过")
  9. // 这里需要注意的是 “89” 和 “9” 不会进行隐式类型,而是使用 ASCII 表的顺序进行比较
  10. // 所以答案是 "内层未通过"

对象克隆

我们都知道「原始类型」和「引用类型」的区别是:原型类型的数据保存在栈内存当中,而引用类型的数据是在栈内存当中保存了堆内存的地址。
所以当我们复制一个对象的时候,其实复制了一个堆内存的地址。

  1. var person1 = {
  2. name: "zhangsan",
  3. age: 18,
  4. height: 180,
  5. wetght: 140,
  6. };
  7. var person2 = person1;
  8. person2.name = "lisi";
  9. console.log(person2);
  10. // {name: 'lisi', age: 18, height: 180, wetght: 140}
  11. console.log(person1);
  12. // {name: 'lisi', age: 18, height: 180, wetght: 140}

以上代码person2在复制person1对象后更改了name属性为lisi,打印person1person2发现它们两的name属性都被更改了,这就是因为指向的是同一个堆内存地址,所以相互影响。

浅拷贝

既然我们知道了原因,那我们可以利用循环的方式,将**person1**的每一个属性循环的复制给**person2**来实现浅拷贝。

  1. var person1 = {
  2. name: "zhangsan",
  3. age: 18,
  4. height: 180,
  5. wetght: 140,
  6. };
  7. var person2 = {};
  8. for (var key in person1) {
  9. person2[key] = person1[key];
  10. }
  11. // 赋值后互不影响,完成克隆
  12. person2.name = "lisi";
  13. console.log(person1); // {name: 'zhangsan', age: 18, height: 180, wetght: 140}
  14. console.log(person2); // {name: 'lisi', age: 18, height: 180, wetght: 140}

这样的浅拷贝还不是最完美的,因为for...in...会把person1上原型的属性也复制过来:

  1. // 浅拷贝的问题,没有处理对象内部的引用数据
  2. Object.prototype.num = 1;
  3. // 对象字面量其实也是 new Object() 构造出来的!!!
  4. var person1 = {
  5. name: "zhangsan",
  6. age: 18,
  7. height: 180,
  8. wetght: 140,
  9. children: {
  10. first: "Jenney",
  11. second: "Lucy",
  12. },
  13. };
  14. var person2 = {};
  15. // for in 的问题会把 person1 的原型也拷贝进去
  16. for (var key in person1) {
  17. person2[key] = person1[key];
  18. }
  19. person2.name = "lisi";
  20. person2.children.third = "Jone";
  21. console.log(person1);
  22. console.log(person2);

image.png

接着我们来优化一下浅拷贝:

  1. function clone(origin, target) {
  2. for (var key in origin) {
  3. // 解决克隆 person1 原型属性的问题
  4. if (origin.hasOwnProperty(key)) {
  5. target[key] = origin[key];
  6. }
  7. }
  8. }
  9. Object.prototype.num = 1;
  10. var person1 = {
  11. name: "zhangsan",
  12. age: 18,
  13. height: 180,
  14. wetght: 140,
  15. children: {
  16. first: "Jenney",
  17. second: "Lucy",
  18. },
  19. };
  20. var person2 = {};
  21. clone(person1, person2);
  22. person2.name = "lisi";
  23. person2.children.third = "Jone";
  24. console.log(person1);
  25. console.log(person2);

image.png

这样就完成了浅拷贝,但是我们能发现虽然更改name属性后,person1person2相互不影响了,但是在给person2.children新增属性的时候,person1也发生了变化,这是因为我们虽然解决了第一层的引用关系,但是第二层的引用关系我们没有进行处理。

深拷贝

那么如何处理第二层甚至第三层、第四层的引用关系呢?我们可以利用递归的方式去判断处理,如果是引用值我们就进行递归,如果是原始值我们就直接赋值。

  1. // 循环的时候判断引用值,利用递归
  2. function deepclone(origin, target) {
  3. var target = target || {};
  4. var toStr = Object.prototype.toString;
  5. var arrType = "[object Array]";
  6. for (var key in origin) {
  7. // 判断是否是 origin 的属性
  8. if (origin.hasOwnProperty(key)) {
  9. // 判断是否是引用类型,因为 typeof null 会返回 object,所以需要判断 !== null
  10. if (typeof origin[key] === "object" && origin[key] !== null) {
  11. // 利用 Object.prototype.toString() 方法能更准确的判断 object 或者 array
  12. toStr.call(origin[key]) === arrType
  13. ? target[key] = []
  14. : target[key] = {}
  15. // 进行递归
  16. deepclone(origin[key], target[key]);
  17. } else {
  18. // 原始值直接赋值
  19. target[key] = origin[key];
  20. }
  21. }
  22. }
  23. // 返回 target 对象
  24. return target;
  25. }
  26. Object.prototype.num = 1;
  27. var person1 = {
  28. name: "张三",
  29. age: 40,
  30. height: 180,
  31. wetght: 140,
  32. car: ["Benz", "Mazda"],
  33. children: {
  34. first: {
  35. name: "张小一",
  36. age: 13,
  37. },
  38. second: {
  39. name: "张小二",
  40. age: 10,
  41. },
  42. },
  43. };
  44. var person2 = deepclone(person1);
  45. person2.children.third = {
  46. name: "张小三",
  47. age: 8,
  48. };
  49. console.log(person1);
  50. console.log(person2);

image.png

利用递归的方式完美的实现了深拷贝!

另外还有一种方式可以利用JSON的方法进行深克隆。

  1. var person1 = {
  2. name: "张三",
  3. age: 40,
  4. height: 180,
  5. wetght: 140,
  6. car: ["Benz", "Mazda"],
  7. children: {
  8. first: {
  9. name: "张小一",
  10. age: 13,
  11. },
  12. second: {
  13. name: "张小二",
  14. age: 10,
  15. },
  16. },
  17. };
  18. var str = JSON.stringify(person1);
  19. var person2 = JSON.parse(str);
  20. console.log(person1);
  21. console.log(person2);

image.png