三目运算
「三目运算符」也称为「三元运算符」。
三目运算符可以使我们简单判断语句,比如用if判断语句:
var a = 5;if (a > 0) {console.log("大于0");} else {console.log("小于等于0");}
利用三目运算可以简化成:
var a = 5;a > 0 ? console.log("大于0") : console.log("小于等于0");
三目运算还具有return的功能:
var a = 5;var str = a > 0 ? "大于0" : "小于等于0";console.log(str); // "大于0"
三目运算还能嵌套使用:
var a = 5;var str1 = a > 0? (a > 3 ? "大于3" : "小于3"): "小于等于0";console.log(str1); // "大于3"
面试题:
// 请问 str 打印什么?var str = 89 > 9? ("89" > "9" ? "通过了" : "内层未通过"): "外层未通过";console.log(str)// 解析:// 先判断 89 > 9 肯定是 true// 然后来到 ("89" > "9" ? "通过了" : "内层未通过")// 这里需要注意的是 “89” 和 “9” 不会进行隐式类型,而是使用 ASCII 表的顺序进行比较// 所以答案是 "内层未通过"
对象克隆
我们都知道「原始类型」和「引用类型」的区别是:原型类型的数据保存在栈内存当中,而引用类型的数据是在栈内存当中保存了堆内存的地址。
所以当我们复制一个对象的时候,其实复制了一个堆内存的地址。
var person1 = {name: "zhangsan",age: 18,height: 180,wetght: 140,};var person2 = person1;person2.name = "lisi";console.log(person2);// {name: 'lisi', age: 18, height: 180, wetght: 140}console.log(person1);// {name: 'lisi', age: 18, height: 180, wetght: 140}
以上代码person2在复制person1对象后更改了name属性为lisi,打印person1和person2发现它们两的name属性都被更改了,这就是因为指向的是同一个堆内存地址,所以相互影响。
浅拷贝
既然我们知道了原因,那我们可以利用循环的方式,将**person1**的每一个属性循环的复制给**person2**来实现浅拷贝。
var person1 = {name: "zhangsan",age: 18,height: 180,wetght: 140,};var person2 = {};for (var key in person1) {person2[key] = person1[key];}// 赋值后互不影响,完成克隆person2.name = "lisi";console.log(person1); // {name: 'zhangsan', age: 18, height: 180, wetght: 140}console.log(person2); // {name: 'lisi', age: 18, height: 180, wetght: 140}
这样的浅拷贝还不是最完美的,因为for...in...会把person1上原型的属性也复制过来:
// 浅拷贝的问题,没有处理对象内部的引用数据Object.prototype.num = 1;// 对象字面量其实也是 new Object() 构造出来的!!!var person1 = {name: "zhangsan",age: 18,height: 180,wetght: 140,children: {first: "Jenney",second: "Lucy",},};var person2 = {};// for in 的问题会把 person1 的原型也拷贝进去for (var key in person1) {person2[key] = person1[key];}person2.name = "lisi";person2.children.third = "Jone";console.log(person1);console.log(person2);

接着我们来优化一下浅拷贝:
function clone(origin, target) {for (var key in origin) {// 解决克隆 person1 原型属性的问题if (origin.hasOwnProperty(key)) {target[key] = origin[key];}}}Object.prototype.num = 1;var person1 = {name: "zhangsan",age: 18,height: 180,wetght: 140,children: {first: "Jenney",second: "Lucy",},};var person2 = {};clone(person1, person2);person2.name = "lisi";person2.children.third = "Jone";console.log(person1);console.log(person2);

这样就完成了浅拷贝,但是我们能发现虽然更改name属性后,person1和person2相互不影响了,但是在给person2.children新增属性的时候,person1也发生了变化,这是因为我们虽然解决了第一层的引用关系,但是第二层的引用关系我们没有进行处理。
深拷贝
那么如何处理第二层甚至第三层、第四层的引用关系呢?我们可以利用递归的方式去判断处理,如果是引用值我们就进行递归,如果是原始值我们就直接赋值。
// 循环的时候判断引用值,利用递归function deepclone(origin, target) {var target = target || {};var toStr = Object.prototype.toString;var arrType = "[object Array]";for (var key in origin) {// 判断是否是 origin 的属性if (origin.hasOwnProperty(key)) {// 判断是否是引用类型,因为 typeof null 会返回 object,所以需要判断 !== nullif (typeof origin[key] === "object" && origin[key] !== null) {// 利用 Object.prototype.toString() 方法能更准确的判断 object 或者 arraytoStr.call(origin[key]) === arrType? target[key] = []: target[key] = {}// 进行递归deepclone(origin[key], target[key]);} else {// 原始值直接赋值target[key] = origin[key];}}}// 返回 target 对象return target;}Object.prototype.num = 1;var person1 = {name: "张三",age: 40,height: 180,wetght: 140,car: ["Benz", "Mazda"],children: {first: {name: "张小一",age: 13,},second: {name: "张小二",age: 10,},},};var person2 = deepclone(person1);person2.children.third = {name: "张小三",age: 8,};console.log(person1);console.log(person2);

利用递归的方式完美的实现了深拷贝!
另外还有一种方式可以利用JSON的方法进行深克隆。
var person1 = {name: "张三",age: 40,height: 180,wetght: 140,car: ["Benz", "Mazda"],children: {first: {name: "张小一",age: 13,},second: {name: "张小二",age: 10,},},};var str = JSON.stringify(person1);var person2 = JSON.parse(str);console.log(person1);console.log(person2);

