javaScirpt学习第八章-第一部分
javaScirpt学习第八章-第一部分
- 数组剩下的两个几个章节
- 内置对象部分
数组
1、可变参数
我们在操作函数里面,实际形参里面会有一个argument的参数
arguments
- arguments是函数中又一个隐含参数
arguments是一个类数组对象(伪数组)
和数组相似,可以通过索引来读取元素,也可以通过for循环变量,但是它不是一个数组对象,不能调用数组的方法
- arguments用来存储函数的实参,
无论用户是否定义形参,实参都会存储到arguments对象中
可以通过该对象直接访问实参可变参数,在定义函数时可以将参数指定为可变参数
- 可变参数可以接收任意数量实参,并将他们统一存储到一个数组中返回
数的作用和arguments基本是一致,但是也具有一些不同点:
- 可变参数的名字可以自己指定
- 可变参数就是一个数组,可以直接使用数组的方法
- 可变参数可以配合其他参数一起使用
arguments使用
// 1.argumentsfunction fn() {console.log(arguments)console.log(Array.isArray(arguments))//虽然取不出来,但是可以遍历,不传就是空for(let v of arguments) { console.log(v)}}// 传了参数,代表的就是数字长度fn(1,20,30);
定义一个求和的函数(任意长度)
// 利用该属性,我们可以定义一个函数,可以求任意个数值的和function sum() {// 通过arguments,可以不受参数数量的限制更加灵活的创建函数let result = 0;for(let num of arguments) {result += num;}return result;}let result = sum(1,2,3,4,5)console.log(result)
… 可变参数
/ 利用可变参数,默认为一个数组,那么可以直接用数组内置方法function sum2(...nums) {return nums.reduce((a,b) => a + b);}result = sum2(0)console.log(result)// 3 当可变参数和普通参数一起使用时,需要将可变参数写到最后function fn3(a,b,...args) {for(let v of args) {console.log(v)}}// 会将前面两个参数占位,其他的都丢到可变参数中fn3(1,'你好','唐曾','八戒',true,2222)
2、内置函数
我们在函数上面可以继续 . 的方法
- call()
- apply()
根据函数调用方式的不同,this的值也不同
- 以函数形式调用,this是window
- 以方法形式调用,this是调用方法的对象
- 构造函数中,this是新建的对象
- 箭头函数没有自己的this,由外层作用域决定
- 通过call和apply调用的函数,它们的第一个参数就是函数的this
this 的指向
function fn() {console.log('函数执行了~',this)}const obj = {name:'孙悟空',fn};fn();obj.fn();// this为obj自身
call() 和 apply() 使用
调用函数除了通过 函数() 这种形式外,还可以通过其他的方式来调用函数
比如,我们可以通过调用函数的call()和apply()来个方法来调用函数
函数.call()
函数.apply()
- call 和 apply除了可以调用函数,还可以用来指定函数中的this
l和apply的第一个参数,将会成为函数的this- 通过call方法调用函数,函数的实参直接在第一个参数后一个一个的列出来
pply方法调用函数,函数的实参需要通过一个数组传递
- 通过call方法调用函数,函数的实参直接在第一个参数后一个一个的列出来
方式1
使用 call() 和apply()方式,这两种如何不传入任何参数的话,基本上是一样的效果
fn.call(obj);
fn.apply(console);
方式2
我们可以改变this的指向问题
// 定义一个可以传参的函数function fn2(a,b) {console.log('a=',a,'b=',b,this)}// 区别一个是传可变参数字符串,一个是传数组 console.log('=================>')fn2.call(obj,'hello',true)fn2.apply(obj,['hello', true])
3. bind()
bind() 是函数的方法,可以用来创建一个新的函数
bind可以为新函数绑定this
bind可以为新函数绑定参数
箭头函数没有自身的this,它的this由外层作用域决定,
也无法通过call apply 和 bind修改它的this
箭头函数中没有arguments
<script>function fn(a,b,c) {console.log("fn执行了~~~~", this)console.log(a, b, c)}const obj = {name:'赵思露'};// 有点类似于高阶函数,里面再套了一层const newFn = fn.bind(obj,10,20,30);newFn();// 箭头函数const arrowFn = () => {console.log(this)}const newArrowFn = arrowFn.bind(obj);// window newArrowFn();// 对象class MyClass {fn = () => {console.log(this)}}const customeClass = new MyClass();// myClass 稳定customeClass.fn.call(window)</script>
内建对象
- 解构赋值
- 对象解构
- 对象序列化
- 深复制
1、 解构赋值
解构赋值,为js的一种简单赋值简写方式
-
公共参数
const arr = [‘赵丽颖’,‘赵露思’,‘周杰伦’];
传统赋值操作
// 传统赋值
let a,b,c;
a = arr[0]
b = arr[1]
c = arr[2]
console.log(a,b,c)
解构赋值
// 1.解构赋值
;[a,b,c] = arr;
console.log(a, b, c)
声明变量的同时直接赋值解构
let [a1,a2,a3,a4] = [‘张三’,‘李四’,‘王五’,‘赵六’];
console.log(a1,a2,a3,a4);
场景1
变量多,右边值少,那么按索引,没有的就是undefined
let [index1, index2, index3, index4] = [1,2,3];
console.log(index1, index2, index3, index4);// 1 2 3 undefined
场景2
变量少,右边值多,那么按索引,右边多余的就被舍弃
;[index1, index2, index3, index4] = [1, 2, 3,4,5,6];
console.log(index1, index2, index3, index4);// 1 2 3 4
场景3
用 …来接收剩下的所有元素
let [n1,n2,…n3] = [10,20,30,40,50,60];
console.log(n1,n2,n3);//(4) [30, 40, 50, 60]
场景4
函数里面返回的数组
function fn() {
return [‘白骨精’,‘红孩儿’,‘法海’]
}
let [name1,name2,name3] = fn();
console.log(name1, name2, name3);
交换两个变量的值
通过解构赋值来快速交换两个变量的值
// 通过解构赋值来快速交换两个变量的值
let b1 = 10;
let b2 = 20;
// 传统的交换,需要用一个临时的变量接收,然后在进行转换
// let temp = b1;
// b1 = b2;
// b2 = temp;
// console.log(‘交换变量’,b1,b2);
// 简写方式交换变量
;[b1,b2] = [b2,b1];
console.log(‘交换变量’, b1, b2);// 交换变量 20 10
改变原数组,交换位置
const arr2 = [‘孙悟空’,‘追八戒’];
;[arr2[0], arr2[1]] = [arr2[1], arr2[0]];
console.log(arr2)
数组中存储的数据类型
数组中可以存储任意类型的数据,也可以存数组,如果一个数组中的元素还是数组,则这个数组我们就称为是二维数组
const arr3 = [[‘孙悟空’,188,‘男’],[‘赵丽颖’,36,‘女’]];
//传统遍历 需要两次
// for(let person of arr3) {
// for(let v of person) {
// console.log(v)
// }
// }
let [[name,age,gender],obj] = arr3;
console.log(name,age,gender)
console.log(obj)
2、对象解构
通用的方式,我们可以对一个对象进行解构操作
const obj = {name:‘孙悟空’ , age: 18, gender: ‘男’}
小试牛刀
<script>const obj = {name:'孙悟空' , age: 18, gender: '男'}let {name,age,gender} = obj;console.log(name,age,gender)// 解构没有的返回的是undefined let {address} = obj;console.log(address)//undefined// 小技巧1,解构的同时,并且重新赋值变量名称let {name:a,age:b,gender:c} = obj;console.log(a,b,c)// 小技巧2 解构同时并且将不存在的变量赋值默认值let {name:nama1,age:age1,gender:gender1,address:address1 = '水帘洞'} = obj;console.log(nama1,age1,gender1,address1)// 解析对象里面的对象 const obj1 = {nickNm:'张三',age:15,sex:'男',friends: {name: '张小三',address: '北京朝阳'},hobby: ['打球','唱歌']}// 复杂对象解构let { nickNm ,sex ,friends:{name:n1,address:a1},hobby:[i1,i2]} = obj1;console.log(nickNm,sex, n1, a1, i1,i2)</script>
3、对象序列化
对象的序列化
-
JS中的对象使用时都是存在于计算机的内存中的
序列化指将对象转换为一个可以存储的格式- 在JS中对象的序列化通常是将一个对象转换为字符串(JSON字符串)
3. 序列化的用途(对象转换为字符串有什么用): - 对象转换为字符串后,可以将字符串在不同的语言之间进行传递
甚至人可以直接对字符串进行读写操作,使得JS对象可以不同的语言之间传递
4. 用途
- 作为数据交换的格式
- 用来编写配置文字
-
如何进行序列化:
-
在JS中有一个工具类 JSON (JavaScript Object Notation) JS对象表示法
-
JS对象序列化后会转换为一个字符串,这个字符串我们称其为JSON字符串
-
也可以手动的编写JSON字符串,在很多程序的配置文件就是使用JSON编写的
-
编写JSON的注意事项:
- JSON字符串有两种类型:
JSON对象 {}
JSON数组 [] - JSON字符串的属性名必须使用双引号引起来
- JSON中可以使用的属性值(元素)
- 数字(Number)
- 字符串(String) 必须使用双引号
- 布尔值(Boolean)
- 空值(Null)
- 对象(Object {})
- 数组(Array [])
- JSON的格式和JS对象的格式基本上一致的,
注意:JSON字符串如果属性是最后一个,则不要再加,
- JSON字符串有两种类型:
-
- 在JS中对象的序列化通常是将一个对象转换为字符串(JSON字符串)
小试牛刀
<script>const obj = {name: '孙悟空',age: 18}// 将obj 转为json字符串const str = JSON.stringify(obj);console.log(str)// 字符串json转为对象const obj2 = JSON.parse(str)console.log(obj2)</script>
4、深复制
我们使用structuredClone和json 进行深复制
小试牛刀
<script>const obj = {name: "孙悟空",friend: {name: "猪八戒",},}// 浅复制const obj2 = Object.assign({},obj); console.log(obj2)//给里面的friend 赋值后再看// obj.friend.name = '李四'console.log(obj2)// 进行深复制const obj3 = structuredClone(obj);console.log(obj3)// 用json 完成深复制const str = JSON.stringify(obj);const obj4 = JSON.parse(str)console.log(obj4)</script>