1.引用类型与值类型区别
- 引用类型:复杂数据类型,object(Object、Array、Date、RegRex、function)
- 值类型:基本数据类型,五种:string number boolean undefined null。
- 1.变量只能访问栈中的空间
- 2.如果是引用类型(复杂数据类型),则将保存在堆中,而栈中存储的是这个数据的地址。
- 3.如果是值类型(基本数据类型),则数据保存在栈中(数据比较小,读取比较快捷方便)
- 4.内存主要有两部分:栈与堆
<script> /* 引用类型:array,obejct 数据存储在堆中,地址存储在栈中 值类型:string number boolean undefined null 数据存储在栈中 区别:值类型:栈中存储的是数据,变量赋值时拷贝的是数据,修改拷贝后的数据不会对原数据造成影响 引用类型:栈中存储的是地址,变量赋值时拷贝的也是地址,修改拷贝后的数据会对原数据造成影响 */ // 1.值类型:拷贝的是数据 var num1 = 10; var num2 = num1; // 将num1的数据拷贝一份保存到num2中 num2 = 100; console.log ( num1, num2 ); // 修改num2不会对num1造成影响 // 2.引用类型: 拷贝的是地址 var arr1 = [10,20,30,40,50]; var arr2 = arr1; // 将arr1的地址拷贝一份保存到num2中 arr2[0] = 100; console.log ( arr1, arr2 ); // 修改arr2会对arr1造成影响 </script>
2.共享引用
- JS中实际对象传值不是真正的引用传值(传地址),而是传递引用的副本(call by sharing):按共享传递
- 对象赋值的本质是对象引用的副本
- 保存副本的对象如果是对对象本身进行操作:那么就是引用(操作原对象)
- 保存副本的对象如果是重新赋值:那么就重新开辟存储空间
// 1.对象共享传递 var obj1 = { name: '我是本体' }; // 2.对象引用(共享) var obj2 = obj1; var obj3 = obj1; // 3.引用的改变效果:如果操作的是对象本身(属性或者方法)那么操作的是原对象obj1,如果把保存引用的变量赋值其他任何类型数据,那么都会重开内存(不影响obj1) obj2.name = '我是新本体'; // obj2操作的是obj1本身的对象,所以修改是共用的(不开辟新空间) console.log(obj1); // {name: "我是新本体"} obj3 = 1; // obj3独立开辟内存空间保存1,与obj1和obj2不再有关联 console.log(obj1); // {name: "我是新本体"} // 共享引用:共享引用是JS中复杂数据类型的本质传递方式而已
3.基本包装类型
- 本身是基本数据类型,但是在执行代码的过程中,可以调用相关的属性和方法
- JS中有三种基本包装类型
- Number
- String
- Boolean
/* // 问题:为什么num是一个基本数据类型,可以像对象一样调用方法呢? // 基本数据类型 var num = 10; console.log ( typeof num ); num.toString () ; /* 本质相当于执行了以下代码(JS解释器检测到num调用来toString()方法,所以快速处理了) (1) var num = new Number(10); // 创建对象 (2) num.toString(); // 调用对象方法 (3) num = null; // 删除对象 */ // 对象类型 var num1 = new Number(10); /* 由于num1本身就是对象类型,所以这里可以直接调用,无需转换 */ num1.toString(); console.log ( num1 ); console.log ( typeof num1 ); // object var str = '111'; str.toString(); /* (1)var str = new String('111'); (2)str.toString(); (3)str = null; */ var bol = true; bol.toString(); /* (1) var bol = new Boolean(true); (2) bol.toString(); (3) bol = null(); */ /* 基本包装类型和引用类型(new Number()/String()/Boolear()的区别 1.new产生的对象是长期占用内存,直到脚本结束 2.基本包装类型属于后台瞬发,用完就销毁了对象:对象 = null 所以:String/Number/Boolean,我们在开发中都是使用基本包装类型 */
4.数组去重
数组去重:将数组中重复的元素去掉
- JS数组没有删除具体元素的删除(只能删掉值,删不掉元素的索引),可以使用另外一个结构来进行存储
- 新数组
- 新对象
- JS数组虽然本质可以删除第一个和最后一个元素,可以利用这一特性,交换当前重复的元素到最后,然后进行删除(pop() 或者length--)
<script> var arr = [20, 66, 88, 25, 66, 90, 88, 50]; // [20,25,66,88,90,50] //1.排序法 // // 1.1 对数组排序 // arr.sort(function(a,b){ // return a-b; // }); // console.log(arr); // // 1.2 声明空数组存储去重后的数组 // var newArr = []; // //1.3 遍历arr,检查arr[i]与arr[i+1]是否相等 // for(var i = 0;i<arr.length;i++){ // if(arr[i] != arr[i+1]){ // newArr[newArr.length] = arr[i]; // }; // }; // console.log(newArr); // 2.假设成立法 // // 2.1 声明空数组存储去重后的数组 // var newArr = []; // // 2.2 遍历arr,检查arr[i]在不在newArr中 // for (var i = 0; i < arr.length; i++) { // // 假设成立法 : 某种操作结果只有两种清空。布尔类型存储两种情况。 // // 1.声明 // var single = true; // 假设不在 // // 2.遍历newArr检查 只要与arr[i]相等 // for (var j = 0;j<newArr.length;j++) { // if (arr[i] == newArr[j]) { // single = false; // break; // 只要发现重复元素,后面没有必要比较 // }; // }; // // 3. 根据结果实现需求 // if (single) { // newArr[newArr.length] = arr[i]; // }; // }; // console.log(newArr); // 3.indexOf // // 2.1 声明空数组存储去重后的数组 // var newArr = []; // // 2.2 遍历arr,检查arr[i]在不在newArr中 // for (var i = 0; i < arr.length; i++) { // if(newArr.indexOf(arr[i]) == -1){ // 不在 // newArr.push(arr[i]); // } // }; // console.log(newArr); // 4.对象法 var arr = [20, 66, 88, 25, 66, 90, 88, 50]; /* 核心思路:利用对象的属性名不能重复 对象的取值赋值特点 取值 : 存在,取值。 不存在,取undefined 赋值 : 存在,修改。 不存在,动态添加 1.声明空对象 : 检查数组元素是否重复 (元素作为属性名,检查对象有没有这个属性) 2.声明空数组 :存储去重后的数组 3.遍历arr,检查arr[i]是否重复 */ var obj = {}; var newArr = []; for (var i = 0;i<arr.length;i++) { // 检查对象有没有 arr[i] 这个属性? if (obj[arr[i]] == undefined) { // 未重复 newArr.push(arr[i]); obj[arr[i]] = 1; // 这里赋值目的是为了下一次取值,不是undefined } }; console.log(newArr); // 5.重复元素自我交换删除法 /* 核心思路:判定元素在数组中查到的位置是否是自身(元素是一定能找到的) * 如果是自身:说明当前元素还没有重复 * 如果不是自身:说明当前元素在前面已经存在过:交换最后一个元素,然后把最后一个删除 步骤: 1.遍历数组的每一个元素 2.判定当前遍历的元素在当前数组中存在的位置,判定位置是否是当当前自己的位置 2.1.是自己位置,说明前面没有重复,忽略 2.2.不是自己位置,说明前面已经存在: 2.2.1交换最后一个元素过来 2.2.2然后删除 2.2.3最后一个元素有可能已经与前面重复了,为了不跳过当前新交换的元素,重新从当前元素开始检索 */ arr = [1,1,2,3,5,0,1]; for (var i = 0; i < arr.length; i++) { / /判定当前元素在数组中找出的位置 if (arr.indexOf(arr[i]) != i) { // 说明不是自己:前面已经存在过 // 交换最后一个元素过来(因为最后一个可以删除 var temp = arr[i]; arr[i] = arr[arr.length - 1]; arr[arr.length - 1] = temp; // 删除最后一个元素:两种方式都可以 // arr.pop(); arr.length--; // 最后一个元素有可能已经与前面重复了,所以为了保证安全,被交换过来的元素还要重新经受考验 i--; } } // 注意:以上方式会改变数组中原来元素的顺序位置 </script>