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()的方法是不能复制函数、循环引用的对象、特殊对象(如Date、RegExp对象)等。方法一:手动递归复制所有属性
方法二:
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);