JavaScript学习笔记十四

88 阅读8分钟

fourteen

一:条件(三元)运算符

1.1 三元运算符初步认识

MDN:

条件(三元)运算符是 JavaScript 唯一使用三个操作数的运算符:一个条件后跟一个问号(?),如果条件为true([真值]),则执行冒号(:)前的

表达式;若条件为false([假值]),则执行最后的表达式。该运算符经常当作 [if...else] 语句的简捷形式来使用。

Tips1:

三元运算符,也叫三目运算符、条件运算符。

语法:条件表达式 ? 语句1 : 语句2;

代码范例1:改写 [if...else]

//[`if...else`]
if(80 > 10){
    console.log('大于');
}else{
    console.log('小于');
}

//三元运算改写
80 > 10 ? '大于' : '小于';
1.2 三元运算的三种写法

基操:

基础写法 ---> 日常常用;

赋值写法 ---> 日常常用;

嵌套写法 ---> 狗都不用,维护与阅读极其不方便,知道有这种写法就行。

代码范例2:展示三种写法

//基础写法
80 > 10 ? '大于' : '小于';

//赋值写法
var res = 80 > 10 ? '大于'  // 此处可认为  return '大于'
				  : '小于'; // 此处可认为  return '大于'
console.log(res); //Print Result:大于

//嵌套写法
var res = 80 > 10 ? ( 
                      80 > 50 ? '大于50'
                              : '小于'
                     )  
				  : '小于'; 
console.log(res); //Print Result:大于50

二:引用类型中的克隆

2.1 引用类型中的克隆(clone)现象

​ 通过代码范例3,可以知道,在引用类型的数据中,使用克隆(也叫拷贝、复制)时,会出现修改克隆体,会影响母体,这是因为引用类型的特性(在克

隆的上下文环境中,都是共享(引用)同一个数据地址,也叫数据指针),代码范例3中演示的是对象类型,但所有引用类型都会如此。

代码范例3:验证上述内容

var person1 = {
    name: '张三',
    age: 18,
    sex: 'male',
    height: 180,
    weight: 140
}
//下面的赋值操作,可以理解:
//1、person1 对象 赋值给了 变量 person2,也就意味着 person2 的数据类型发生改变,转变成引用类型的对象类型;
//2、因为是引用类型的数据,所以 person2 实际上得到的是 person1 引用地址(数据指针);
//3、所以,一旦 person2 中修改或新增数据时,person1 也将会发生改变。
var person2 = person1; 
person2.name = '李四';
person2.text = 'testData';
//打印验证
console.log(person1, person2);
//Print Result:打印结果太长了,直接说结果,一毛一样
2.2 对象浅拷贝

​ 在 JavaScript 中,浅拷贝(Shallow Copy)指的是创建一个新的对象,这个新对象有着原始对象属性值的一份精确副本。如果原始对象的属性是基本类

型,比如字符串、数字或布尔值,浅拷贝会复制属性值。然而,如果属性是引用类型(例如数组或对象),浅拷贝不会复制实际的对象或数组本身,而是复制

指向这些对象或数组的引用,这里的引用是属于传址,而非传值

总结:浅拷贝

在进行浅拷贝后,原始对象和副本将共享引用类型属性的引用。如果在浅拷贝副本中修改了这类型的属性,将会改变原始对象中的引用类型数据。

代码范例4:演示了一个浅拷贝的实现,并对浅拷贝副本进行了修改以展示浅拷贝的特性。

//声明一个对象字面量,其中包含了原始类型和引用类型的数据。
var person1 = {
    name: '张大', //原始类型 ---> 字符串
    age: 18, //原始类型 ---> 数字
    sex: 'male', //原始类型 ---> 字符串
    height: 180, //原始类型 ---> 数字
    weight: 140, //原始类型 ---> 数字
    children: {No1: '张一', No2: '张二', No3: '张三'}, //引用类型 ---> 对象
    car: ['Benz', 'Audi', 'Toyota'] //引用类型 ---> 数组
}

//最原始的浅拷贝方法实现
var person2 = {}; //创建一个空对象,用于存储 person1 对象的拷贝。
for(var key in person1){ //遍历 person1 对象内的属性或方法
    if(person1.hasOwnProperty(key)){ //排除 person1 对象的原型上的属性或方法
        //浅拷贝的核心部分:
        //1、这是一个赋值语句,同时也是一个表达式;
        //2、表达式的执行顺序是右到左;
        //3、person1[key] 所返回的值,是 person1 对象中的属性值而不是属性名;
        //4、同时 person2[key] ,是先创建 person2 的属性名,然后在接收 person1 的属性值;
        //5、因为 person2 是一个空对象,所以这里的 [key] 是属性名,是从遍历 person1 对象获取到的,也就是先创建属性名然后赋值操作。
        person2[key] = person1[key]; 
    }
}
person2.name = '李四'; //测试修改原始类型的值是否会修改原始对象中的对应属性的值
person2.children.No4 = '张四'; //测试修改引用类型的值是否会修改原始对象中的对应属性的值
person2.car[3] = 'Honda'; //同上
console.log(person1, person2); //打印结果太长,直接说结果,原始类型的值不会修改,而引用类型的值会被修改。
2.3 对象浅拷贝几种方法实现

这里只简单说下在浅拷贝下的应用,对象扩展运算符 {...} 与 Object.assign 方法。

对象扩展运算符 {...} :

  • var [targetObject] = {...[originObject]}
  • 具体看代码范例。

Object.assign 方法:

  • var [targetObject] = Object.assign({}, [originObject])
  • 具体看代码范例。

代码范例5:浅拷贝简单方法实现

//方法1:原始的浅拷贝方法实现,在代码范例4中以实现,就不在这里复述;

//方法2:针对方法1 函数化;
function shallowCopy(origin, target){
    // 如果调用时没有提供 target 参数,则将 target 初始化为一个空对象。
    // 这是为了确保即使没有提供目标对象,函数也能正常运行。
    var target = target || {};
    for(var key in origin){
        if(origin.hasOwnProperty(key)){
            target[key] = origin[key];
        }
    }
    return target;
}

//方法3:使用对象扩展运算符 {...} --- ES6
var person1 = {name: '张大', age: 18, sex: 'male', height: 180, weight: 140,
    children: { No1: '张一', No2: '张二', No3: '张三' },
    car: ['Benz', 'Audi', 'Toyota']
}
//是的,没有看错,就是 {...object}
var person2 = {...person1};
console.log(person2);

//方法4:使用Object.assign方法 --- ES6
var person1 = {name: '张大', age: 18, sex: 'male', height: 180, weight: 140,
    children: { No1: '张一', No2: '张二', No3: '张三' },
    car: ['Benz', 'Audi', 'Toyota']
}
var person2 = Object.assign({}, person1);
console.log(person2);
2.4 深拷贝

​ 在 JavaScript 中,深拷贝(Deep Copy)指的是创建一个对象的副本,同时递归地复制其内部的所有属性,包括引用类型的属性。深拷贝是完全复制一

个对象,包括对象内部的所有层级。这样,原始对象和副本在引用类型的数据上是完全独立的。对副本中的引用类型数据的修改不会影响到原始对象。

总结:深拷贝

深拷贝会把对象里所有的数据重新复制到新的内存空间,是最彻底的拷贝。

2.5 深拷贝几种方法实现

​ 在JavaScript中,实现深拷贝可以通过多种方式,包括手动递归复制所有属性、使用 JSON.stringify() 配合 JSON.parse() 方法(只适用于可序列化

的数据)。使用 JSON.stringify() 配合 JSON.parse() 的方法是不能复制函数、循环引用的对象、特殊对象(如 DateRegExp 对象)等。

方法一:手动递归复制所有属性

方法二: JSON.stringify() 配合 JSON.parse() 实现深拷贝**(不常用,也不推荐)**

代码范例6:验证上述内容

//方法一:手动递归复制所有属性
var person1 = {
    name: '张大',
    age: 18,
    sex: 'male',
    height: 180,
    weight: 140,
    children: { No1: '张一', No2: '张二', No3: '张三' },
    car: ['Benz', 'Audi', 'Toyota'],
    say: function(){
        console.log('牛X');
    }
}

var person2 = deepCopy(person1)
person2.say = function(){
    console.log('me too!');
}
person1.say();
person2.say();
console.log(person1, person2);
//手动递归复制所有属性
//两个形参,origin 为原始对象,target 为目标对象,target 形参可选填
function deepCopy(origin, target) {
    //target 参数如果没有提供,则函数内部会创建一个新的空对象。
    var target = target || {},
        //获取 Object 原型上的 toString 方法,用于后续类型判断。
        toStr = Object.prototype.toString,
        //定义一个字符串,用于识别数组类型。
        arrType = '[object Array]';
    //遍历原始对象 origin 的所有属性。
    for (var key in origin) {
        //确保只处理 origin 自身的属性,而非原型链上的属性。
        if (origin.hasOwnProperty(key)) {
            //如果属性值是对象(包括数组)且不为 null。
            if (typeof (origin[key]) === 'object' && origin[key] !== null) {
                //如果属性值是数组类型
                if (toStr.call(origin[key]) === arrType) {
                    //为目标对象的对应属性创建一个新数组。
                    target[key] = [];
                } else {
                    //否则,为目标对象的对应属性创建一个新对象。
                    target[key] = {};
                }
                // 递归调用 deepCopy 来复制对象或数组内部的元素。
                deepCopy(origin[key], target[key]);
            } else {
                // 对于非对象类型,直接复制值(浅拷贝)。
                target[key] = origin[key];
            }
        }
    }
    //返回复制后的目标对象。
    return target;
}
//方法二:JSON.stringify() 配合 JSON.parse() 实现深拷贝
var person1 = {
    name: '张大',
    age: 18,
    sex: 'male',
    height: 180,
    weight: 140,
    children: { No1: '张一', No2: '张二', No3: '张三' },
    car: ['Benz', 'Audi', 'Toyota'],
    say: function(){
        console.log('牛X');
    }
}
//转换 person1 对象为 JSON格式,字符串形式
var str = JSON.stringify(person1);
//然后在把字符串转换为对象,但是不能复制函数等特殊的对象类型
var person2 = JSON.parse(str);
//测试
person2.car[3] = 'Honda';
//打印测试,深拷贝没有问题,但特殊的对象类型,确实不能赋值过来。
console.log(str);
console.log(person1);
console.log(person2);