Object对象
创建对象的两种方式
new+构造函数
let obj=new Object({name:'bob',age:'age'}) console.log(obj);
使用new操作符加构造函数可以创建一个对象
使用对象字面量{}
let obj1={name:'Tom',age:'20'}
使用{}包含可以创造一个对象,{表示一个表达式开始,}则代表这个表达式结束.
注: 在所有现代浏览器中,对象字面量最后一个属性加,不报错,但在一些老的浏览器中,会发生报错。
在上述两小节中,我们可以得出new Object在一定程度上等于{},区别是前者是用构造函数来创建对象,后者是用对象字面量来创建。{}是ES3语法,在较旧的js版本中不支持,而new Object在兼容所有js环境。
存取对象属性两种方式
点语法和中括号语法
但在特殊情况下,如属性名中有空格,那么可以通过[]来进行存取。 举例:
let obj1={age:'20'} obj1.name='Tom' obj1['My Cat']='Jack' console.log(obj1.name,obj1['My Cat']);//Tom Jack
且[]可以获取到动态属性值,而点语法只能获取到静态属性值,举例:
let obj={name:'Tom'} const nickName='name' console.log(obj.nickName,obj.name);//undefined 'Tom' console.log(obj[nickName],obj['name']);//undefined 'Tom'
nickName的值等于name,中括号如果里面不加’'则会提取nickname的值来作为属性名,而点语法则只有静态,不能进行提取。
数组
创建数组方式
Array构造函数
构造函数和Object构造函数类似,不同的是,它如果输入一个数字,且只输入该数字,则该数字就是数组长度。
let arr=new Array(20); let arr1=new Array(20,'Tom') let arr2=new Array('Jack','Tom','John') console.log(arr.length,arr1.length,arr2.length)//20 2 3
数组字面量[ ]
let arr=[]; let arr1=[1,3] let arr2 =[1,2,3,4,,,,,] console.log(arr,arr1,arr2)//[] [1,3] (8) [1, 2, 3, 4, empty × 4] console.log(arr.length,arr1.length,arr2.length);//0 2 8
和对象字面量类似,数组字面量实现和构造函数一样的效果,在上述代码的arr2中我们发现加了很多空,这些,被用作占位,打印出来是undefined(未定义的值),有占位符的数组也叫稀疏数组,为了代码整洁和增强可读性一般不建议使用。
创建数组方法(form&of)
of方法
of方法可以将一组参数转换成数组实例,举例
console.log(Array.of(1,2,3,4),Array.of(undefined,undefined)); //(4) [1, 2, 3, 4] (2) [undefined, undefined]
from方法
From方法可以把任何可迭代的结构从类数组对象,转换成数组实例。js当中大多数都是可迭代对象,这里举几个不是迭代对象的例子:
不可迭代数据类型:number、boolean、Math、symbol、null、undefined、JSON。
注:ES6中引入的迭代器协议,我们也可以通过实现Symbol.iterator方法来对一个不可迭代对象实现可迭代。那么它就可以被from方法所调用并转换成数组实例。
from方法是在获取到一个可迭代结构后,新建一个数组,并把这个结构返回一个新数组,那么这个数组的地址的新的,但值还是可迭代结构转换成数组后的引用。举例:
let str='123' let ma=new Map().set(1,2) .set(3,4) let se=new Set().add(1).add(3).add(5) console.log(str,ma,se);//123 Map(2) {1 => 2, 3 => 4} Set(3) {1, 3, 5} console.log(Array.from(str),Array.from(ma),Array.from(se)); //(3) ['1', '2', '3'] (2) [Array(2), Array(2)] [1, 3, 5]
也可以通过对arguments对象进行改变。
arguments 对象是 JavaScript 中的一个特殊对象,它在函数内部自动创建,并包含了函数被调用时传递的参数信息。
a数组复制给b数组,=和from的区别是什么?
from实现过程:
1.获取可迭代对象,2.遍历可迭代对象中的元素,可迭代对象转换成新数组 3.返回新数组
转换后的数组是被创建出来的新数组,和原数组堆地址不同,引用值相同。所以它虽然也是浅拷贝,但是它俩改变非对象索引的值,不会发生一变都变的效果。
等于=实现过程:
1.获取原始数组
2.复制引用值,引用堆地址
所以说=被复制和复制的数组都用一个引用堆地址,就会出现一变都变的情况,不管它们是不是对象索引值。
数组空位(稀疏数组)
let arr=[,]
这个就被称为稀疏数组,ES6中,打印出来为undefined。
正常来说遍历这种未定义的值数组时,会跳过,但使用ES6新增的from方法,则会返回undefined,未定义的值。
数组索引(length)
数组可以通过length属性来判断长度,同时也可以通过改变长度修改数组。
let arr=[1,2,3] console.log(arr);//(3) [1, 2, 3] arr.length=2; console.log(arr);//(3) [1, 2, 3]
如果想在数组末尾添加元素也可以通过**arr[arr.length]=‘元素值’**进行添加。
数组检测(instanceof&isArray)
常用的两种方法:instanceof、isArray()
instanceof: value instanceof Array
isArray: Array.isArray(value)
前者在遭遇多个全局执行上下文|框架时,会出现报错,因为主页面的Array构造函数和子页面的Array构造函数不同,每个框架或页面都有自己原生的Array构造函数,所以就可能出现报错问题。举例:
我有一个页面,有用到iframe子页面框架
<body> <iframe src="./angular-01.html"></iframe> <script> // 在全局作用域中定义一个值 var value = [1, 2, 3]; // 判断 value 是否为数组 if (value instanceof Array) { console.log("Value is an arrayS"); // 在主页面输出 } </script> </body>
子页面angular-01.html
<body> <script> // 在 frame1.html 的全局作用域中重新定义 Array var Array = "I'm not an array!"; // 使用与主页面相同的代码来判断 value 是否为数组 if (value instanceof Array) { console.log("Value is an array"); // 不会输出 } </script> </body>
如果有多个执行上下文或多个iframe框架,则可以使用isArray来检测数组。
迭代器方法(keys、values、entries)
这三种方法都是实现对数组迭代,区别是获得的内容不同
keys:数组索引(键)
values:数组各个属性值(值)
entries:数组索引和值(键值对)
let arr=['apple','banana','orange'] console.log(Array.from(arr.keys()));// (3) [0, 1, 2] console.log(Array.from(arr.values()));//(3) ['apple', 'banana', 'orange'] console.log(Array.from(arr.entries()));//(3) [Array(2), Array(2), Array(2)]
复制和填充方法(copyWithin&fill)
fill填充方法
语法格式:
一个参数:数组名.fill(填充数)
两个参数:数组名.fill(填充数,最小索引值)
三个参数:数组名.fill(填充数,最小索引值,最大索引值)
举例:
let oneFill = [0, 1, 2, 3, 4] let twoFill = [0, 1, 2, 3, 4] let threeFill = [0, 1, 2, 3, 4] oneFill.fill(5); console.log(oneFill); //(5) [5, 5, 5, 5, 5] twoFill.fill(6, 1) console.log(twoFill); //(5) [0, 6, 6, 6, 6] threeFill.fill(5, 2, 4) console.log(threeFill); //(5) [0, 1, 5, 5, 4]
copyWithin复制方法
浅复制自身数组索引,一共有三个参数,语法格式如下:
let arr=[0,1,2,3,4,5,6,7,8,9] arr.copyWithin(5);//复制从索引为0的值开始,复制的位置在索引为5的值//0,1,2,3,4,0,1,2,3,4 let arr1=[0,1,2,3,4,5,6,7,8,9] console.log(arr1); arr1.copyWithin(2,4)//开始复制的位置是2,起始位置索引 console.log(arr1);//0,1,4,5,6,7,8,9,8,9 let arr2=[0,1,2,3,4,5,6,7,8,9] console.log(arr2) arr2.copyWithin(2,4,8) console.log(arr2);//0,1,4,5,6,7,6,7,8,9 //被复制值,起始位置:4,结束位置:8,复制地点:2,如果没有结束位置,则一直复制到数组末尾。
转换方法(toLocalString,toString,join)
toLocalString和toString
它俩都是用于数组转换成字符串的方法。
toString() 方法返回一个表示数组元素的字符串,并使用逗号分隔每个元素。
默认情况下,toString()方法不会对数组元素进行任何格式化或本地化处理。
例如,对于数组 [1, 2, 3],调用 toString() 方法将返回字符串 “1,2,3”。
toLocaleString() 方法将数组转换为一个本地化后的字符串,根据不同的语言环境可能有不同的输出。 与 toString()
不同,toLocaleString() 对数组元素进行了本地化处理,根据语言环境应用相应的格式。
例如,在某些语言环境下,日期、时间和数字可能以特定的方式显示。 toLocaleString()
方法还接受一些可选参数,用于指定语言环境和格式选项。 例如,对于日期数组 [new Date()],调用 toLocaleString()
方法将返回日期的本地化字符串表示。
join
实现数组转字符串,还可以往每个元素中添加参数,来进行隔断,如join(‘,’)等
let arr=['red','green','yellow'] let str1=arr.join('') let str2=arr.join(',') console.log(str1+'\n'+str2); //greenyellow // red,green,yellow
栈方法(pop、push)
首先讲一下堆栈概念: 堆栈是一种后进先出(Last-In-First-Out,LIFO)的数据结构。 元素在堆栈的顶部进行插入和删除操作。
最后插入的元素始终位于堆栈的顶部,即最新的元素可被首先访问或移除。 类似于现实生活中的一叠盘子,只能从顶部放入或取出。
常见的应用场景包括函数调用、表达式求值、撤销操作等。 例如,浏览器的历史记录就可以看作是一个堆栈。.
js这两个方法类似于堆栈进行操作,pop就是释放最外层元素,push就是在最外层加一个元素。
let arr=['red','green','yellow'] arr.pop() arr.push('blue') console.log(arr); // [ // "red", // "green", // "blue" // ]
队列方法(shift、push)
队列概念·
队列是一种先进先出(First-In-First-Out,FIFO)的数据结构。
元素在队列的尾部(末尾)进行插入,而从队列的头部(开头)进行删除。 新元素被添加到队列的末尾,而最早添加的元素位于队列的开头。
类似于现实生活中排队等候的概念,先来先服务。 常见的应用场景包括任务调度、消息传递等。 例如,打印机队列就是一个典型的队列。
shift方法是在数组头部,进行释放动作,push是在数组末尾进行添加动作,这两个方法组合就变成了队列方法。
let arr=['red','green','yellow','pink'] arr.push('blue','black') arr.shift() console.log(arr); // [ // "green", // "yellow", // "pink", // "blue", // "black" // ]
unshift
除了shift方法外,还有一个unshift方法,和shift方法相反,unshift方法主要做了往数组头部添加元素的动作。
排序方法(sort、reverse)
reverse翻转数组
通俗来说,把数组反过来,12345变成54321(,省略了)
let arr=['red','green','yellow','pink'] arr.reverse() console.log(arr); // [ // "pink", // "yellow", // "green", // "red" // ]
sort排序
sort默认是升序,把数组从小到大进行排序。
let arr=[5,4,2,6,3] arr.sort() console.log(arr);//(5) [2, 3, 4, 5, 6]
也可以通过箭头函数或者普通函数来进行降序或者复杂的动作。
let arr=[5,4,2,6,3] arr.sort((a,b)=>b-a) console.log(arr);//(5) [6, 5, 4, 3, 2]
操作方法(concat、slice、splice)
concat
concat主要是用于新数组的拼接以及数组拍平操作。
拍平有一个数组属性:
Symbol.isConcatSpreadAble
,这个属性可以控制数组是否被强制拍平,默认是true。
数组拼接
let arr1=[1,2,3] let arr2=[9,8] let arr3=arr1.concat(arr2) console.log(arr3);//(5) [1, 2, 3, 9, 8] arr2=arr2.concat(1,2) console.log(arr2);//(4) [9, 8, 1, 2] arr1=arr1.concat('yes','no') console.log(arr1);//(5) [1, 2, 3, 'yes', 'no'] arr1=[4,5,6].concat(1) console.log(arr1);//(4) [4, 5, 6, 1] //拍平 let arr=[1,2,3,4] let arrs=[2,3,4] let arra=[3,4,5] arrs[Symbol.isConcatSpreadable]=false; arra[Symbol.isConcatSpreadable]=true; console.log(arr.concat(arrs));//(5) [1, 2, 3, 4, Array(3)] console.log(arr.concat(arra));//(7) [1, 2, 3, 4, 3, 4, 5]
slice
切割原数组得到新数组的一个方法,可以传正负值。
let arr=[0,1,2,3,4] console.log(arr.slice(1));//得到索引>1的新数组 //(4) [1, 2, 3, 4] console.log(arr.slice(1,2));//得到索引>=1同时<2的新数组 //[1]
传负值,一般会从结束索引反推,比如上述数组,传值-2,-1,如果负数过大,则会返回空数组。
console.log(arr.slice(-2,-1));//[2]
splice(删除、添加、替换)
删除
let arr=[0,1,2,3,4]; //删除 语法格式[删除开始位置,删除截止位置] console.log(arr.splice(0,2),arr);//(2) [0, 1] (3) [2, 3, 4]
添加
let arr=[0,1,2,3,4]; //添加 语法格式[开始位置,删除数量,添加内容....] console.log(arr.splice(0,1,'red','blue'),arr);//[0] (6) ['red', 'blue', 1, 2, 3, 4]
替换
替换和添加是一样的语法格式,只不过替换是要先删除原有索引下的内容,然后替换成新的。
let arr=[0,1,2,3,4]; //添加 语法格式[开始位置,删除数量,替换内容....] console.log(arr.splice(0,1,6),arr);//[0] (5) [6, 1, 2, 3, 4]
在上述代码中,0就被替换成6。
显式调用和隐式调用的区别
显式调用是指直接调用函数,如fun().隐式调用是指用对象下的方法,用对象进行调用,a.fun()等,属于隐式调用。
6. 显式调用要求直接使用函数名来调用函数,而隐式调用则需要通过对象的方法或属性来调用函数。
7. 显式调用可以在任何地方进行,而隐式调用必须通过对象来进行,因为函数和对象之间有关联。
8. 在隐式调用中,函数内部的 this 关键字会绑定到调用该函数的对象上,而显式调用则可以自由地指定 this 的值。
搜索和位置方法
按严格相等搜索是基于值的相等性进行比较,使用严格相等运算符(===)来查找数组中与指定值严格相等的元素,返回第一个或最后一个匹配项的索引。
按断言函数搜索是基于自定义条件进行比较,使用传入的断言函数对每个元素进行判断,返回满足条件的第一个元素或其索引。它允许根据特定的需求编写复杂的条件来搜索数组中的元素
严格相等搜索(indexOf、lastIndexOf、includes)
前两者为所有版本都可以使用,includes为ES7新出现的搜索方法。
lastIndexOf是从后往前搜索,而indexOf和includes是从前往后搜索。
includes查询Object或数组返回都是true\false,indexOf和lastIndexOf返回的都是索引位置或-1、
举例:
let arr=[0,1,2,3,4,4,3,2,1,0]; console.log(arr.indexOf(3),arr.indexOf(5));//3 -1 console.log(arr.lastIndexOf(3),arr.lastIndexOf(5));//6 -1 console.log(arr.includes(3),arr.includes(5));//true false
断言函数搜索(find、findIndex)
ES6新出现的断言函数.举例
let person=[ {'name':'Jack',age:20}, {'name':'Tom',age:21}, {'name':'John',age:10} ] console.log(person.find((item,index,array)=>item.age>18)) //{name: 'Jack', age: 20} console.log(person.findIndex((item,index,array)=>item.age<18)); //2
前者返回值,后者返回索引,都是从数组头部开始判断,每个索引都调用这个函数,只返回第一个匹配的值。
迭代方法(every、filter、forEach、map、some)
every方法与some方法
同:两个方法都返回true、false。 异:every方法需要所有值都满足条件,才会返回true。 some方法需要至少有一个值满足条件,返回true。
举例:
let person=[ {'name':'Jack',age:20}, {'name':'Tom',age:21}, {'name':'John',age:10} ] console.log(person.every((item)=>item.age>18));//false console.log(person.some((item)=>item.age>18));//true
filter、map方法
同: 新数组为返回值,原数组不发生改变。 时间复杂度:O(n)
异: filter为条件筛选后的新数组。map为把数组中元素操作后的新数组。
举例:
let person=[ {'name':'Jack',age:20}, {'name':'Tom',age:21}, {'name':'John',age:10} ] let fil=person.filter(item=>{ return item.age>18; }) let ma=person.map(item=>{ if(item.age>18){ return item.age*2; }else return item.age; }) console.log(fil,ma); // {name: 'Jack', age: 20} // {name: 'Tom', age: 21} //(3) [40, 42, 10]
forEach方法
特点:
无返回值,时间复杂度O(n),遍历数组并执行指定操作。
let person=[ {'name':'Jack',age:20}, {'name':'Tom',age:21}, {'name':'John',age:10} ] person.forEach(item=>{ item.age++; }) console.log(person);//age都加1
归并方法(reduce、reduceRight)
归并方法,用于将数组的元素聚合成单个值。
它接受一个回调函数作为参数,在每次迭代中将累加器和当前元素组合起来。
回调函数的返回值将成为下一次迭代的累加器值。最后将这个值作为返回值。
区别:reduce从第一项开始遍历,reduceRight从最后一项开始遍历
let red=[1,2,3,4,5]; console.log(red.reduce((rev,rep)=>rev-rep));//-13 //1-2-3-4-5=-13 console.log(red.reduceRight((rev,rep)=>rev-rep));//-5 //5-4-3-2-1=-5
Map、WeakMap、Set 类型
Map基本语法
通常使用 Map 数据结构来表示键值对的集合。
四大方法
get:获取map集合中的属性。
set:添加map集合中属性。
has:判断map集合是否有某个属性。
delete:删除map集合中的属性。
举例:
let a=new Map([ ['name','key'], ['age',18] ]) console.log(a.get('name'));//key a.set('animal','cat') console.log(a.get('animal'));//cat console.log(a.has('animal'));//true console.log(a.delete('animal'),a.has('animal'));//true false
Map特性、Map与Object区别
特性
键可以是任何数据类型:在Map中,键可以是任何JavaScript的数据类型,包括原始类型(如字符串、数字等)和引用类型(如对象、函数等)。这使得Map在处理复杂数据结构时非常有用。
保持插入顺序:Map会记住元素插入的顺序,并按照插入顺序进行迭代。这在需要按顺序访问元素时非常有用。
动态大小:与数组不同,Map没有固定的长度限制。它可以根据需要自动扩展以容纳更多的元素。
区别
1.Map在内存占用可以比Object多存储50%的键值对。
2.插入性能Map较Object快。(Map使用哈希表)。
3.查找速度Object较快。
4.删除性能Map较Object强。因为Object需要用到垃圾回收机制。
weakMap
因为Map即使没有被引用也不会被垃圾回收。会出现内存泄漏的问题,但weakMap解决了这个问题,它如果没被引用,则会被回收,从而预防了内存泄漏的问题。
因为是Map的子集,所有Map的API它大多都可以调用。
它出现的价值有三点:
1.预防内存泄漏。
2.保持数据的隐私性:因为外部无法直接访问weakMap内部的键值。
缺点:
1.无法迭代 2.无法获取大小长度。3.键必须是对象类型,不能是原始类型。
Set
set是一种具有无序和唯一性的集合。无序是指,它的属性没有先后顺序之分,唯一是指,它定义的值,不能再次添加,接下来简单讲解一下它的四个方法和size属性。
语法格式:
let se=new Set();
add、delete、has方法|size属性
let se=new Set([ 'val1','val2' ]) se.add('val3').add('val4').add('val2') console.log(se);//Set(4) {'val1', 'val2', 'val3', 'val4'} let boo=se.has('val1') console.log(boo,se.size);//true console.log(se.delete('val1'),se.has('val1'),se.size);//true false 3 se.clear(); console.log(se.size);//0
上述代码中,add是用来添加set元素,可以多次添加,但是不能添加已有的属性值。
add添加,delete删除,has查询,clear删除所有元素,size查询当前集合长度。
顺序和迭代
使用keys、values或者[Symbol.iterator]属性可以迭代。
举例:
let se=new Set([ 'val1','val2' ]) for(item of se.values()){ console.log(item);//val1 val2 } for(item of se[Symbol.iterator]()){ console.log(item);//val1 val2 } for(item of se.keys()){ console.log(item);//val1 val2 }
扩展操作符
[…]
let arr1 = [1, 2, 3]; let arr2 = [0, ...arr1, 4, 5]; console.log(arr2);//(6) [0, 1, 2, 3, 4, 5]
总结
林林总总写了一星期,map和set那里写的很少,只讲了基本用法。那么好,本期内容到此结束。