颠覆认知的『JavaScript』——14 三目运算、对象克隆、浅拷贝、深拷贝

本文介绍了JavaScript中的三目运算符,展示了如何使用它来简化条件判断。接着讨论了对象的克隆问题,包括浅拷贝和深拷贝的概念及其实现方式,并通过示例代码详细解释了它们的区别。最后,文章提供了几个关于JavaScript预编译、this指向以及如何判断闰年的笔试题目,帮助读者深入理解JavaScript的基础知识。
摘要由CSDN通过智能技术生成

一、三目运算

结构:条件 ?表达式A :表达式B,条件为真A执行,为假则表达式B执行

三目运算一般可以作为简单if语句的简化,三目运算也可以嵌套使用

var a = 5;
if (a > 0) {
  console.log('大于0');
} else {
  console.log('小于等于0');
}

a > 0 ? console.log('大于0')    //注意这里是一整个表达式不要用分号
      : console.log('小于等于0'); 

//-------------------------------------------------------------------------

// 字符串根据ASCII码按位比较
/**
 *	89 > 9 -> true 执行括号内的语句
 *	'89' > '9' -> false '8'的ASCII码小于'9'的ASCII码 执行:后面的表达式
 *	str = '内层未通过'
 */
var str = 89 > 9 ? ('89' > '9' ? '通过了'
                               : '内层未通过'
                   )
                   : '外层未通过';

console.log(str);   // '内层未通过'

也可以定义一个参数接收三目运算返回的结果,三目运算也可以算是一个return

var str = a > 0 ? '大于0'
        :'小于0'

二、对象克隆

Object.prototype.num = 1;
var person1 = {
  name: '张三',
  age: 18,
  sex: 'male',
  height: 180,
  weight: 140,
  son: {
    first: 'Jenney',
    second: 'Lucy',
    Third: 'Jone'
  }
}

// person1和person2指向同一对象
var person2 = person1; // person2指向person1的地址
// 修改person2的name属性
person2.name = '李四'; 
console.log(person1, person2);

三、浅拷贝

浅拷贝的原理就是字面量创建一个新对象,然后通过循环,把里面的值放到新的对象里。这两个不同的对象,指针地址也不一样,所以不会互相影响。

缺点:如果对象里面又有对象,还是会拿到指针地址,就跟上面的克隆一样

Object.prototype.num = 1;
var person1 = {
  name: '张三',
  age: 18,
  sex: 'male',
  height: 180,
  weight: 140,
  son: {
    first: 'Jenney',
    second: 'Lucy',
    Third: 'Jone'
  }
}
// 字面量创建对象
var person2 = {};
// 浅拷贝
for (var key in person1) {
  // 把person1的可枚举属性赋值给person2(包括原型上的属性)
  person2[key] = person1[key];
}

// 在浅拷贝过程中,原始值复制的是副本,两个变量完全独立,互不干扰
person2.name = '李四';
// 在浅拷贝过程中,引用值复制的是指针,两个变量指向同一对象
person2.son.forth = 'Ben';
console.log(person1, person2);

注意:for (var key in person1)会把原型上的方法复制过来,所以我们可以通过hasOwnProperty这个属性判断是不是原型上的

封装浅拷贝

function clone(origin, target) {
  // 没传入target时,声明一个空对象
  var target = target || {};
  for (var key in origin) {
    // 过滤掉原型上的属性
    if (origin.hasOwnProperty(key)) {
      target[key] = origin[key];
    }
  }
  return target;
}

四、深拷贝

深拷贝就是遇到对象里面有对象,通过递归一步一步拷贝

Object.prototype.num = 1;
var person1 = {
  name: '张三',
  age: 18,
  sex: 'male',
  height: 180,
  weight: 140,
  children: {
    first: {
      name: '张小一',
      age: 13
    },
    second: {
      name: '张小二',
      age: 7
    },
    third: {
      name: '张小三',
      age: 3
    }
  },
  car: ['Benz', 'Mazda']
};

function deepClone(origin, target) {
  // 没传入target时,声明一个空对象
  var target = target || {},
  //	保存对象原型上toString方法
  toStr = Object.prototype.toString,
  //	保存对象原型上数组调用toString方法的返回值
  arrType = '[object Array]';
	// 枚举源对象上的可枚举属性(包括原型上的可枚举属性)
  for (var key in origin) {
    // 过滤掉原型上的属性,只拷贝自身可枚举属性
    if (origin.hasOwnProperty(key)) {
      // 当属性是引用值,且不为null时,条件为真
      if ((typeof(origin[key]) === 'object') && origin[key] !== null) {
        // 当前引用值调用对象原型toString方法判断是否是数组
        if(toStr.call(origin[key]) === arrType) {
          // 声明一个空数组,进行递归
          target[key] = [];
        } else {
          // 声明一个空对象,进行递归
          target[key] = {};
        }
        // 要克隆的属性是引用值,需要递归
        deepClone(origin[key], target[key])
      } else {
        // 原始值直接复制
        target[key] = origin[key];
      }
    }
  }
  // 返回深拷贝结果
  return target;
}
// 将深拷贝结果赋值给person2
var person2 = deepClone(person1);
// 修改对象的原始值
person2.name = '李四';
// 修改对象的引用值
person2.car = ['BMW'];
console.log(person1, person2);

封装深拷贝

function deepClone(origin, target) {
  var target = target || {},
  toStr = Object.prototype.toString,
  arrType = '[object Array]';

  for (var key in origin) {
    if (origin.hasOwnProperty(key)) {
      if ((typeof(origin[key]) === 'object') && origin[key] !== null) {
        if(toStr.call(origin[key]) === arrType) {
          target[key] = [];
        } else {
          target[key] = {};
        }
        deepClone(origin[key], target[key])
      } else {
        target[key] = origin[key];
      }
    }
  }
  return target;
}

json实现深拷贝

var a=JSON.stringify(obj);
var b=JSaON.parse(a);

五、笔试题

1.预编译问题

//预编译

/**
 * AO = {
 * foo: undefined -> 2
 * }
 */
function test() {
  console.log(foo); // undefined
  var foo = 2;
  console.log(foo); // 2
  console.log(a); // ReferenceError
}

test();
/**
 * AO = {
 * test: undefined -> function test() {console.log(1)}
 * }
 */
function a() {
  var test;
  test();
  function test() {
    console.log(1); // 执行
  }
}
a();

2、this指向


var name = '222';
var a = {
  name: '111',
  say: function () {
    console.log(this.name);
  }
}

var fun = a.say;
fun(); // '222'  
/* 
 * 相当于
 * fun = function () {
 *  console.log(this.name);
 *  }
 * 这个时候的this就是指向全局window的
 */
a.say(); // '111'  谁调用this指向谁,a调用,所以就是111
var b = {
  name: '333',
  say: function (fun) {
    fun();
  }
}
b.say(a.say); // '222'
b.say = a.say;
b.say(); // '333'

function test() {
  var marty = {
    name: 'marty',
    printName: function () {
      console.log(this.name);
    }
  }

  var test1 = {
    name: 'test1'
  }
  var test2 = {
    name: 'test2'
  }
  var test3 = {
    name: 'test3'
  }

  test3.printName = marty.printName;
  marty.printName.call(test1); // 'test1'   //call apply改变this的指向
  marty.printName.apply(test2); // 'test2'
  marty.printName(); // 'marty'
  test3.printName(); // 'test3'
}

test();

var bar = {
  a: '1'
}

function test() {
  bar.a = 'a';
  Object.prototype.b = 'b';
  return function inner() {
    console.log(bar.a);
    console.log(bar.b);
  }
}
test()(); // 'a' 'b'

//只要函数执行, Object.prototype.b = 'b';执行了,原型上就会挂上个

var bar = {
  a: '1'
}

function test() {
  bar.a = 'a';
  Object.prototype.b = 'b';
//   return function inner() {
//     console.log(bar.a);
//     console.log(bar.b);
//   }
}
// test(); // 'a' 'b'
console.log(bar.b);
//这样还是会打印出'b'

六、作业

请用window.prompt接收用户输入的年份,判断是否是闰年?(请用三目运算来做)
 

var year = parseInt(window.prompt('请输入一个年份'));
function isLeapYear(year) {
  return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ? '是闰年' 
                                                                 : '不是闰年'
}

console.log(isLeapYear(year));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值