一. 数据类型概述
1. 变量
变量是储存数据的容器,声明关键字有 let var ,以及常量生成关键字 const
let age; //声明变量但不赋值,相当于创建一个名为age的容器 let age1 = 18;
变量提升情况
使用 var 关键字声明变量时,会产生变量提升,所以我们必须先声明再使用变量,或者使用 let 关键字声明。
/* 2.变量提升情况 var关键字 先声明后使用*/ console.log(num); //undefined var num = 10; /* 相当于 var num; console.log(num); num = 10 */ // 报错:ReferenceError 引用类型错误
2. 基本数据类型
String | Number | Boolean | undefined | null
3. 引用数据类型
Array | Object | Function
4. 数据类型的转换
4.1 显式转换
4.1.1 字符串 布尔类型转数字类型
方法有 Number() | parseInt() | parseFloat()
/* 一.转数字类型 Number语法 */ /* 1.字符串转数字 */ var a = "123"; var b = Number(a); console.log(typeof a, typeof b); // string number /* 2.null转数字 会转换成0*/ var a = null; var b = Number(a); console.log(typeof a, typeof b, b); //object number 0 /* 3.undefined转数字 会转换成NaN,非数字,本质还是数字类型*/ var a = undefined; var b = Number(a); console.log(typeof a, typeof b, b); // undefined number NaN /* 4.boolean转数字 true对应1 false对应0 */ /* 5.小数转换 */ var a = 123.45; var b = Number(a); console.log(typeof a, typeof b, b); // number number 123.45 /* 6.带字母字符串转换 */ var a = "123abc123"; var b = Number(a); console.log(typeof a, typeof b, b); // string number NaN /* 二.parseInt 转换方法,主要转换整数,类似于一个数字一个数字转换,遇到字母或是小数点就停止 */ var a = 123.45; var b = parseInt(a); console.log(typeof a, typeof b, b); // number number 123 会省略后面的小数 var a = "123abc123"; var b = parseInt(a); console.log(typeof a, typeof b, b); // string number 123 /* 三.parseFloat 转换方法,与parseInt类似,可以保留小数 */
4.1.2 布尔类型 数字类型转字符串
方法有 String() | toString()
/* 一. 转换为字符串类型 String()写法 任何类型皆可转换 */ let a = null; let b = String(a); console.log(typeof a, typeof b, b); // object string null /* 二. toString() 写法 具有限制,值为null和undefined时会报错可以看做是方法的调用,null和undefined是不能调用方法的*/ let a = true; let b = a.toString(); console.log(typeof a, typeof b, b); let num = 14; console.log(num.toString(16)); //进制转换 //boolean string true
4.1.3 字符串 数字类型转布尔类型
/* 一. 类型转换为布尔值 */ /* 只有0,'',undefined,null,NaN 这些值会转换成false,其余都是true */ let a = ""; let b = Boolean(a); console.log(typeof a, typeof b, b); // string boolean false
4.2 隐式转换
浏览器通过符号或数字进行数据类型的自动转换
// 二、隐式转换 (浏览器自动转换) // 1) 转字符串类型 // 任意数据类型和字符串拼接,都会变成字符串类型 // + 这个加号运算符(加法运算、字符串拼接) console.log(10 + 20);// 30 console.log(10 + "abc");// '10abc' console.log(typeof 10 );// 'number' console.log(typeof 10 + "abc");// 'numberabc' console.log(typeof (10 + "abc"));// 'string' console.log(typeof true);//'boolean' console.log(typeof (true + ""));//'string' console.log(typeof (undefined + ""));//'string' // 2) 转数字类型 // 主要数字字符串使用这个“-”可以隐式转换成数字类型 // 任何数字减去0都等于其本身 // 任何数字乘以1都等于其本身 // - 这个符号号运算符(减法运算、转数字) console.log(100 - 60);// 40 console.log(typeof "100");// 'string' console.log(typeof ("100" - 0));// 'number' console.log(typeof ("100" * 1));// 'number' // 3)两个等于号表示比较值的大小,不比较数据类型 // == // 0 == false // "" == false // 1 == true console.log(0 == false); // true console.log("" == false); // true console.log(0 == ""); // true console.log(1 == true); // true console.log(undefined == false); // false // 举例:1 > 2 < 3 这个表达式执行的结果: true // 1 > 2 表示 false 隐式转换为0 // 0 < 3 结果 true
5. 运算符
5.1 数学运算符
// + - * / % /* 倒计时转换效果 */ let time = 1000; let hour = parseInt(time / 60); let min = time % 60; console.log(hour + ":" + min); /* 字符串数学运算 */ console.log(1 + "2" * 3 + 4); //非加号的字符串数学运算都带有隐式转换,会转换成数字类型进行运算 /* 自增自减运算 ++ --*/ let num = 10; console.log(num++); //10 先输出再运算 console.log(num); //11 console.log(++num); //11 先运算再输出
5.2 赋值或逻辑运算符
/* JS的赋值运算符有 = += -= *= /=*/ /* 比较运算符有 == === != !== */ console.log(true == 1); //true console.log("" == 0); //true console.log(undefined == 0); //false /* 逻辑运算符 || && ! */ /* 逻辑或 || 一真全真,全假为假 */ /* 逻辑与 && 全真为真,一假为假 */ /* || 的运用 默认值操作*/ let data = "" || "侬好"; console.log(data); //'侬好' /* && 的运用 */ let data1 = true && 100; //&& 运算符所有的条件都会执行,有值赋值 console.log(data1);
二. 字符串
1.概念
字符串是一个 JS 内的基本数据类型,在 JS 内用单引号 ' ' 或者双引号 " " 包裹的内容就叫做 字符串。
2.创建字符串
// 1. 字面量方式创建 字符串var str1 = 'hello world'var str2 = "hello world"console.log(str1)// hello worldconsole.log(str2)// hello world
使用构造函数创建字符串,是以 new 创建对象的形式,所以字符串会被存放在堆内存,变量str1和str2存放的是地址值,str1==str2 是false,str1===str2 也是false
// 2. 构造函数创建字符串var str1 = new String('hello world')var str2 = new String("hello world")console.log(str1)// String {"hello world"}console.log(str2)// String {"hello world"}
3.字符串相关方法
/* 字符串常用方法 */ //1.字符串长度 const str = "hello"; console.log(str.length); //5 //2.字符串拼接 const str1 = "hello"; const str2 = "world"; console.log(str1 + str2); //helloworld //3.字符串截取 const str3 = "hello world"; console.log(str3.slice(0, 5)); //hello //4.字符串查找 indexOf charAt const str4 = "hello world"; console.log(str4.indexOf("h")); //0 console.log(str4.indexOf("o", 5)); //从第五个字符开始查找o //4.1 charAt const str41 = "hello"; console.log(str.charAt(1)); // 输出结果:e console.log(str[1]); // 输出结果:e console.log(str.charAt(5)); // 输出结果:'' console.log(str[5]); // 输出结果:undefined //4.2 includs let str42 = "Hello world!"; str.includes("o"); // 输出结果:true str.includes("e", 2); // 输出结果:false,ongoing第二个字符开始查找e //4.3 match 返回包含值与索引的数组,通过点语法输出 let str43 = "abcdef"; console.log(str43.match("c").input); // ["c", index: 2, input: "abcdef", groups: undefined] //5.字符串替换 const str5 = "hello world"; console.log(str5.replace("world", "javascript")); //hello javascript //6.字符串分割,生成数组 split substr const str6 = "hello world"; console.log(str6.split(" ")); //(2) ["hello", "world"] //正则匹配分割 const list = "apples,bananas;cherries"; const fruits = list.split(/[,;]/); console.log(fruits); // 输出结果:["apples", "bananas", "cherries"] //6.1 substr [] let str61 = "abcdefg"; str.substr(1, 6); // 输出结果:"bcdefg" str.substr(1); // 输出结果:"bcdefg" 相当于截取[1,str.length-1] str.substr(); // 输出结果:"abcdefg" 相当于截取[0,str.length-1] str.substr(-1); // 输出结果:"g" //6.2 substring [) let str62 = "abcdefg"; str.substring(1, 6); // 输出结果:"bcdef" [1,6) str.substring(1); // 输出结果:"bcdefg" [1,str.length-1] str.substring(); // 输出结果:"abcdefg" [0,str.length-1] str.substring(6, 1); // 输出结果 "bcdef" [1,6) str.substring(-1); // 输出结果:"abcdefg" //7.字符串拼接 let str7 = "abc"; console.log(str7.concat("efg")); //输出结果:"abcefg" console.log(str7.concat("efg", "hijk")); //输出结果:"abcefghijk" console.log(str7.concat("efg", ...str)); console.log(str + str7); //8.移除左右空格,在input输入框中有运用 let str8 = " abcdef "; str8.trim(); // 输出结果:"abcdef" //9.字符串的转换 数组转字符串join() 字符串转数组split(',') let str91 = "abcdef", str92 = 123123123; arr = [1, 2, 3]; console.log(str92.toString()); // "123123123" console.log(typeof str2.toString()); //string console.log(arr.toString()); //1,2,3 console.log(arr.toString().split(",")); //split分割逗号,['1','2','3'] /* //7.字符串转大写 const str7 = "hello world"; console.log(str7.toUpperCase()); //HELLO WORLD //8.字符串转小写 const str8 = "HELLO WORLD"; console.log(str8.toLowerCase()); //hello world */ /* 补充 */ //1.判断字符串以什么字符开头及结尾 let s1 = "Hello world!"; s1.startsWith("Hello"); // 输出结果:true s1.startsWith("Helle"); // 输出结果:false s1.startsWith("wo", 6); // 输出结果:true s1.endsWith("!"); // 输出结果:true s1.endsWith("llo"); // 输出结果:false s1.endsWith("llo", 5); // 输出结果:true
三. 数组
1.概念
一组有序的数据集合,可以同时存储不同类型的值,并且长度是动态的,可以根据需要随时添加或删除元素。
2.声明
// 1.字面量创建let arr1 = [1, 2, 3];// 2.构造函数创建let arr2 = new Array(10, 20, 30);let arr3 = new Array(7);//创建一个长度为7的空数组
3.访问元素
数组含有规律的索引,通过从0开始到长度-1的索引值来访问和修改元素
let arr = [1,2,3]console.log(arr[0]);//1arr[1]=5console.log(arr);//[1,5,3]
4.数组遍历
利用数组有规律的索引,通过for循环的方式进行数组遍历,能够按需取出数组元素
let arr = [1,2,3];for(let i = 0 ; i < arr.length ; i++){ console.log(arr[i])//1,2,3}
5.相关方法
/* 数组常用方法 */ //1.数组添加 var arr = [1, 2, 3, 4, 5]; res = arr.push(6); console.log(res); //返回添加的数值6 console.log(arr); //1.2 unshift(数据)方法向数组的开头添加一个或更多元素,并返回新的数组长度。 var arr = [1, 2, 3, 4, 5]; res = arr.unshift(0); console.log(res); //[6] console.log(arr); //[0,1,2,3,4,5] //2.数组删除 pop() 删除数组最后一个元素 var arr = [1, 2, 3, 4, 5]; res = arr.push(); console.log(res); //[5] console.log(arr); //[1,2,3,4] //2.1shift()方法,删除数组的第一项,并返回删除的项,原数组改变 var arr = [1, 2, 3, 4, 5]; res = arr.shift(); console.log(res); //[1] console.log(arr); //[2,3,4,5] //3.数组翻转 reverse()方法用于颠倒数组中元素的顺序。返回值:返回颠倒后的数组,原数组改变 var arr = [1, 2, 3, 4, 5]; res = arr.reverse(); console.log(res); //[5,4,3,2,1] console.log(arr); //[5,4,3,2,1] //3.1.数组翻转 for循环 let arr1 = []; for (let i = arr.length - 1; i >= 0; i--) { arr1.push(arr[i]); } console.log(arr1); //4.数组排序 sort()方法用于对数组的元素进行排序。返回值:返回排序后的数组,原数组改变 var arr = [1, 3, 2, 5, 4]; res = arr.sort(); console.log(res); //[1,2,3,4,5] console.log(arr); //[1,2,3,4,5] //4.1.数组排序 for循环 for (let i = 0; i < arr.length; i++) { for (let n = i + 1; n < arr.length; n++) { if (arr[n] > arr[i]) { let temp = arr[i]; arr[i] = arr[n]; arr[n] = temp; } } } console.log(arr); //[5,4,3,2,1] //5.数组截取 slice(start,end)方法可从已有的数组中返回选定的元素。返回值:返回截取后的数组,原数组不改变 var arr = [1, 2, 3, 4, 5]; res = arr.slice(1, 3); console.log(res); //[2,3] console.log(arr); //[1,2,3,4,5] //5.1.数组截取 splice(开始的索引,结束的索引,添加的元素) 截取从开始到结束的元素,并添加元素,返回被删除的元素 var arr = [10, 60, 8, 56, 48, 75]; res = arr.splice(1, 2, 100, 200); console.log(arr); //[10, 100, 200, 56, 48, 75] console.log(res); //[60, 8] //6.数组合并concat() 合并数组,返回新数组 var arr = [10, 60, 80, 50, 40, 70, 10, 40]; res = arr.concat(10, "测试", 40); console.log(arr); //[10, 60, 80, 50, 40, 70, 10, 40] console.log(res); //[10, 60, 80, 50, 40, 70, 10, 40, 10, '测试', 40] console.log([...arr, "测试"]); //拓展运算符 //7.数组转字符串 join()把数组中的元素用指定的字符串连接起来 map(item=>{}).join() js转html结构 var arr = [10, 60, 80, 50, 40, 70, 10, 40]; res = arr.join("+"); console.log(arr); //[10, 60, 80, 50, 40, 70, 10, 40] console.log(res); //10+60+80+50+40+70+10+40 //8.数组查找 indexOf(元素,起始索引位置) var arr = [10, 60, 80, 50, 40, 70, 10, 40]; res = arr.indexOf(40, 3); console.log(arr); console.log(res); /* 9.ES6新增 */ //forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。 //item: 数组中正在处理的当前元素。 //index: 可选,数组中正在处理的当前元素的索引。 //arr: 可选,forEach() 方法正在操作的数组。 var arr = [1, 2, 3, 4, 5]; console.log(arr); var res = arr.forEach(function (item, index, arr) { console.log(item, index, arr); }); //map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。 var arr = [1, 2, 3, 4, 5]; console.log(arr); //[1, 2, 3, 4, 5] var res = arr.map(function (item) { return item * 200; }); console.log(res); //[200, 400, 600, 800, 1000] //filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 //注意: filter() 不会对空数组进行检测。 //注意: filter() 不会改变原始数组。 var arr = [1, 20, 35, 44, 50]; console.log(arr); //[1, 20, 35, 44, 50] var res = arr.filter(function (item) { return item > 40; }); console.log(res); //[44, 50] //every 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。 //如果所有元素都通过检测,则返回 true;否则返回 false。 var arr = [1, 20, 35, 44, 50]; console.log(arr); //[1, 20, 35, 44, 50] var res = arr.every(function (item) { return item > 20; }); console.log(res); //false //some => //some 方法是用来检测数组中是否含有符合条件的元素 //如果有,则返回true,否则返回false //some 方法不会对空数组进行检测 //some 方法不会改变原始数组 var arr = [1, 20, 35, 44, 50]; console.log(arr); //[1, 20, 35, 44, 50] var res = arr.some(function (item) { return item > 22; }); console.log(res); //true //find()方法 //find()方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。 //find()方法不会改变原始数组。 var arr = [1, 20, 35, 44, 50]; console.log(arr); //[1, 20, 35, 44, 50] var res = arr.find(function (item) { return item > 22; }); console.log(res); //35 //reduce => //用于把数组中的所有值相加得到一个值 //result => 初始值 //item => 数组中的每一个值 //result => 每一次相加的结果 var arr = [1, 20, 35, 44, 50]; console.log(arr); //[1, 20, 35, 44, 50] var res = arr.reduce(function (result, item) { return result + item; }); console.log(res); //150
5.二维数组
一个数组内的元素还是数组形式,形如以下的数组,称为二维数组
let arr = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ];
二维数组的遍历 : 采用双重循环的方式
for (let i = 0; i < arrData.length; i++) { for (let j = 0; j < arrData[i].length; j++) { return arr[i][j] } }
二维数组的动态生成
/* 渲染一个二维数组 */function getArray(col,row) { let arr = new Array(col); for (let i = 0; i < col; i++) { arr[i] = new Array(row); for (let j = 0; j < row; j++) { a[i][j]=1 } } return arr;};
四. 对象
1.概念
对象:以键值对形式出现的数据集合 {key:value}
2.声明方式
// 1.字面量创建let ming= {name:"阿明",age:22,};// 2.构造函数创建let ming= new Object();ming.name = "阿明";ming.age = 22;
3.访问和添加删除对象属性
3.1访问对象属性
方法一 : 通过.语法访问
let ming= {name:"阿明",age:22,};console.log(ming.name);//阿明
方法二 : 通过键名方式 object[key]
let ming= {name:"阿明",age:22,};console.log(ming[age]);//22
3.2添加删除对象属性
通过.语法添加
let ming= {name:"阿明",age:22,};ming.study='H5';console.log(ming)//{name:'阿明',age:22,study:'H5'}
通过delect删除
let ming= {name:"阿明",age:22,};delete ming.age;// 或者 delete ming[age]console.log(ming)//{name:'阿明'}
4.遍历对象
对象是不能像数组一样使用普通for循环遍历,因为对象的键名多是没有规律的,但是可以通过 for in 这类方法遍历
let ming= {name:"阿明",age:22,};for(let key in ming){let value = ming[key]; console.log(key + ' ' + value); //name '阿明' //age 22}
5.相关方法
//1.Object.entries(obj):返回对象内可枚举键值对组成的数组; const obj1 = { a: "1", b: 2 }; console.log(Object.entries(obj1)); // [ ['a', '1'], ['b', 2] ] //2.Object.keys(obj):返回对象内可枚举键组成的数组; // 简单数组,数组的keys值为index索引 var arr = ["a", "b", "c"]; console.log(Object.keys(arr)); // console: ['0', '1', '2'] // 简单对象 const obj2 = { a: 1, b: 2 }; console.log(Object.keys(obj2)); // [a,b] //3.Object.values(obj):返回对象内可枚举值组成的数组; // 简单数组,数组的keys值为index索引 var arr = ["a", "b", "c"]; console.log(Object.values(arr)); // console: ['a', 'b', 'c'] // 简单对象 const obj3 = { a: 1, b: 2 }; console.log(Object.values(obj3)); // [1,2] //5、delete 操作符:用于删除对象的某个属性 let obj5 = { a: 1, b: 2 }; // delete obj;// 不能直接删除对象,这里会报错 delete obj5.a; console.log(obj5); // 输出{b: 2}; //6、hasOwnProperty():返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键); let obj6 = { a: 1, b: 2 }; console.log(obj6.hasOwnProperty("a")); // true console.log(obj6.hasOwnProperty("c")); // false //7、in 操作符:返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键); let obj7 = { a: 1, b: 2 }; console.log("a" in obj7); // true console.log("c" in obj7); // false //8、Object.assign():用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。 let obj8 = { a: 1, b: 2 }; let obj9 = { c: 3, d: 4 }; let obj10 = Object.assign(obj8, obj9); let obj11 = { ...obj8, ...obj9 }; console.log(obj10); // {a: 1, b: 2, c: 3, d: 4} console.log(obj11); //9、Object.defineProperty() :会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 /*obj: 要定义属性的对象。prop: 要定义或修改的属性的名称或 Symbol 。descriptor: 要定义或修改的属性描述符。*/ //Object.defineProperty(obj, prop, descriptor); //使用 const obj = {}; Object.defineProperty(obj, "property", { value: 1, // value值 }); //== 等价于 == Object.defineProperty(obj, "property", { value: 1, // value值 configurable: false, // 是否可删除 enumerable: false, // 是否可遍历 writable: false, // 是否可修改 }); //所以obj不可修改删除遍历操作,除非把上面的三个属性设置为true console.log(obj); // { property: 1} delete obj.property; // 删除操作,不生效 console.log(obj); // { property: 1} obj.property1 = 23; // 修改操作,不生效 console.log(obj); // { property: 1} for (let i in obj) { // 遍历操作,不生效 console.log(i); // 无打印 }
五. 函数
1. 函数概念
JS 是一门函数式的编程语言,函数是可以重复利用的代码块
2. 函数声明
函数名()
function 函数名(形式参数...){}
定义变量接收函数 不能在声明之前调用
const 函数名 = function(){}
3. 构造函数
3.1概念
构造函数是一种用于构建对象的代码块。用于构建、设计对象的函数,需要使用new来调用,普通函数作用域的this,往往指向window,因为其在全局环境下。构造函数作用域的this,指向构造函数所创建的实例,因为它是由new来调用。this 是指针变量。不同的作用域this指向是不同。
3.2 内置构造函数
String 、Number 、 Boolean 、 Array 、Object 、Date 、Function ...
构造函数的命名规范 名称首字母大写。
3.3 基本使用
采用new操作符调用的函数都是构造函数, const sayHi = new Function('')
function Student(name, age) { this.name = name; this.age = age; this.sayHi = function () { console.log("侬好"); }; } const student = new Student("咸鱼茄子煲", 19); student.sayHi(); console.log(student.age); console.log(student.name); console.log(student);
六. JS语句
/* javascript 语句 */ //1.判断语句 if else | if (else if) else | switch //2.循环语句 for循环 while循环 do while循环 /* 2.1 for循环 */ for (初始化; 终止条件; 增量) { // 循环体代码 } for (let i = 0; i < 5; i++) { console.log(i); } /* 2.2 while循环 */ while (条件) { // 循环体代码 } let i = 0; while (i < 5) { console.log(i); i++; } /* 2.3 do while 循环 */ do { // 循环体代码 } while (条件); let j = 0; do { console.log(j); j++; } while (j < 5);
七. 原型链
1.构造函数的原型对象
在js中,一个特殊的每一个对象(函数也是对象)都有属性叫做原型(prorotype),它指向另一个对象,这个对象(Object.prototype)被称为原型对象, 原型对象是用来共享属性和方法的。
// 原型 prototype :每个构造函数都有的属性,类型是object,也称原型对象,通过原型对象添加自定义方法 // 构造函数.prototype console.log(Array.prototype); //挂载很多方法 push pop // arr调用join方法,但arr实例对象没有这个方法,会找到Array构造函数,再找到其原型对象身上的join方法 let arr = [1, 2, 3]; let arrStr = arr.join(""); console.log(arrStr); /* 来个栗子 */ function App() {} App.prototype.sayHi = function (params) { console.log(this); //指向实例对象,谁调用指向谁 console.log("你好啊" + params); }; let app = new App(); app.sayHi("阿明"); console.log(app.__proto__);
2.实例对象的隐式原型
在js中,每个实例对象都有一个“ __proto__ ”属性,这个__proto__就被称为隐式原型,它与构造函数的原型对象有相互指向的关系,也就是 obj__proto__ === Object.prototype。
八. 深浅拷贝
1.概念
拷贝就是复制或是克隆。js的数据类型主要有基本数据类型和引用数据类型,其中基本数据类型存于栈内存,存储在变量的就是实际的元素;而引用数据类型存于堆内存,存储在变量的为指向堆内存的地址值,所以这两种数据类型在拷贝使用中会有不同。
/* 基本数据类型与引用数据类型的存储 */ //1.基本数据类型:存在栈内存,变量存储元素值 let width = "100px"; //2.引用数据类型:存在堆内存,变量存储地址值 let _obj = { height: "100px", }; /* 数据拷贝和地址拷贝 */ let a = [1, 2, 3]; let b; b = a; b[0] = 100; console.log(a); //[100,2,3] console.log(b); //[100,2,3] let c = [1, 2, 3]; let d = []; d[0] = c[0]; d[0] = 100; console.log(c); //[1,2,3] console.log(d); //[100]
数据拷贝主要是元素赋值操作,两个变量互不影响;但地址拷贝不同,赋值变量的是地址值,也就让两个变量都指向同一个地址的引用数据类型,当一个变量改动数据时,另一个变量也回随之改变。
2.浅拷贝
适用于元素为简单数据类型的情况
// 数组内为基本数据类型 let arr1 = [1, 2, 3]; // 数组包含引用数据类型 let arr2 = [1, 2, { x: "50px" }]; //封装浅拷贝函数 function simpleCopy(data) { //根据data判断要设置的数据类型 let newData = Array.isArray(data) === true ? [] : {}; for (const key in data) { newData[key] = data[key]; } return newData; } //数组包含基本数据类型 let newArr1 = simpleCopy(arr1); newArr1[0] = 100; console.log(arr1); console.log(newArr1); //不会影响原数组元素 //数组包含引用数据类型 //浅拷贝的是地址值,也就是arr1[2]和newArr2[2]共同指向同一个对象 let newArr2 = simpleCopy(arr2); newArr2[2].x = "100px"; console.log(arr2); console.log(newArr2); //会将原数组的数据改变
3.深拷贝
适用于元素带有引用数据类型的情况
let obj = { a: 1, b: 2, obj: { x: 100, y: 200, }, }; let arr = [1, 2, { o: 100, p: 100 }]; //封装深拷贝函数 function deepClone(data) { if (data && typeof data === "object") { //1.根据传入的数据结构创建对应的数据结构 let newObj = Array.isArray(data) ? [] : {}; //2.进行循环,如果是普通类型,调用浅拷贝 for (const key in data) { if (data.hasOwnProperty(key)) { //3.判断如果是引用数据类型 if (data[key] && typeof data[key] === "object") { //4.将内部的引用数据类型进行递归,也就是剥层,直到简单数据类型的浅拷贝 newObj[key] = deepClone(data[key]); } else { newObj[key] = data[key]; } } } return newObj; } else { return data; } } let newObj = deepClone(obj); newObj.a = 100; newObj.obj.x = 1; console.log(obj); console.log(newObj); let newArr = deepClone(arr); newArr[0] = 100; newArr[2].o = 1; console.log(arr); console.log(newArr);
前者数据的改变不会影响后者