JS学习
一、面向对象的实例
<script>
let user={
name:"Emily",
grade:[
{name:"js",score:99},
{name:"css",score:76},
],
average(){
let total=this.grade.reduce((t,l)=>t+l.score,0);
return `${this.name}的平均成绩是:${total/this.grade.length}`;
},
}
console.log(user.average());
</script>
输出:
Emily的平均成绩是:87.5
二、属性的基本操作
1、两种获取属性的方法对比:
<script>
let user={
name:"Emily",
age:18,
};
console.log(user.name);
console.log(user["age"]);
</script>
在有些情况下只能使用第二种方法:
属性名有空格时:
<script>
let user={
name:"Emily",
age:18,
"my weight":80
};
console.log(user["my weight"]);//正确
//console.log(user.my weight);//红线
</script>
遍历属性时:
<script>
let user={
name:"Emily",
age:18,
"my weight":80
};
for(const key in user){
console.log(key,user[key]);//正确
//console.log(key,user.key);//"user.key"undefined
}
</script>
2、动态添加/删除属性
<script>
let user={
name:"Emily",
age:18,
"my weight":80
};
user.sex="女";//添加变量
user.get=function(){//添加方法
return `${this.name}的性别是${this.sex}`;
}
console.log(user.get());
delete user.get;//删除方法
console.log(user.get());
</script>
输出:
Emily的性别是女
Uncaught TypeError: user.get is not a function
at test1.html:20
三、对象的引用传址
函数的参数传递对比:
基本数据类型,传值
在函数内部改变参数的值不会改变外部的值:
<script>
let user=1;
function show(a){
a+=100;
console.log(a);
}
show(user);
console.log(user);
</script>
输出:
101
1
对象类型,传址
在函数内部改变参数的值会引起外部的值的改变:
<script>
let user={
age:100,
};
function show(a){
a.age=18;
console.log(a);
}
show(user);
console.log(user);
</script>
输出:
{age: 18}
{age: 18}
四、使用展开语法完成参数合并
1、展开语法在数组中的使用:
<script>
let arr=[1,2,3];
let a=[...arr,5,6,7];
console.log(a);
</script>
输出:
(6) [1, 2, 3, 5, 6, 7]
2、展开语法在对象中的使用:
<script>
let user={name:"Emily",age:18};
let a={...user,sex:"女"};
console.log(a);
</script>
输出:
{name: "Emily", age: 18, sex: "女"}
3、多个展开语法的使用:
<script>
function upload(params){
let config={
type:"*.png",
size:1000
};
config={...config,...params};
//config=Object.assign(config,params);//使用Object.assign更方便
console.log(config);
}
upload({size:99,type:"*,gif"});
</script>
输出:
type: "*,gif", size: 99}
当params中有config中的key时,会将config中的键值覆盖;没有的话会在config中添加。
如果将params和config的顺序反过来,config会将params中的键值覆盖。
五、解构赋值
1、对象的解构赋值(定义)
<script>
let user={name:"Emily",age:18};
let {name:a,age:b}=user;
console.log(a,b);
</script>
输出:
Emily 18
如果将name,age分别用同名参数保存:
let {name:name,age:age}=user;
简写为:
let {name,age}=user;
2、对象的解构赋值(返回值)
<script>
function show(){
return {name:"Emily",age:18};
}
let {name,age}=show();
console.log(name,age);
</script>
输出同上。
3、对象的解构赋值(传参)
<script>
function user({name,age}){
console.log(name,age);
}
user({name:"Emily",age:18});
</script>
输出同上。
4、Math也是一个数据,接收它的部分key:
<script>
let {random}=Math;
console.log(random());//产生随机数
</script>
效果同下:
<script>
console.log(Math.random());//产生随机数
</script>
5、严格模式下的解构
必须使用声明语句来进行解构赋值
六、对象与原型链属性检测
1、数组检测
使用hasOwnProperty只能检测当前对象有无该属性;
但是使用in还会追溯到父级:
<script>
"use strict";
let arr=[1,2,3];
console.log(arr.hasOwnProperty("length"));
console.log(arr.hasOwnProperty("concat"));
console.log("length" in arr);
console.log("concat" in arr);
</script>
输出:
true
false
true
true
2、对象检测
a->b->c
<script>
"use strict";
let a={name:"Emily"};
let b={age:18};
let c={sex:"女"};
Object.setPrototypeOf(b,c);//把c设为b的原型
Object.setPrototypeOf(a,b);//把b设为a的原型
console.log(a.hasOwnProperty("sex"));
console.log("sex" in a);
</script>
输出:
false
true
in会一直检测到原型链顶端。
七、数组转对象
<script>
"use strict";
let lessons=[
{title:"数据结构",teacher:"王老师"},
{title:"算法设计",teacher:"李老师"},
{title:"操作系统原理",teacher:"杨老师"},
{title:"计算机网络",teacher:"周老师"},
];
let res=lessons.reduce((obj,cur,index)=>{
obj[`${cur.teacher}-${index+1}`]=cur;
return obj;
},{});
console.log(lessons);
console.log(JSON.stringify(res,null,2));
</script>
输出:
[
{
"title": "数据结构",
"teacher": "王老师"
},
{
"title": "算法设计",
"teacher": "李老师"
},
{
"title": "操作系统原理",
"teacher": "杨老师"
},
{
"title": "计算机网络",
"teacher": "周老师"
}
]
{
"王老师-1": {
"title": "数据结构",
"teacher": "王老师"
},
"李老师-2": {
"title": "算法设计",
"teacher": "李老师"
},
"杨老师-3": {
"title": "操作系统原理",
"teacher": "杨老师"
},
"周老师-4": {
"title": "计算机网络",
"teacher": "周老师"
}
}
八、遍历操作与DOM绘制
<script>
"use strict";
let lessons=[
{title:"数据结构",teacher:"王老师"},
{title:"算法设计",teacher:"李老师"},
{title:"操作系统原理",teacher:"杨老师"},
{title:"计算机网络",teacher:"周老师"},
];
let ul=document.createElement("ul");
for(const lesson of lessons){
let li=document.createElement("li");
li.innerHTML=`课程:${lesson.title},老师:${lesson.teacher}`;
ul.appendChild(li);
}
document.body.appendChild(ul);
</script>
九、对象的浅拷贝
只拷贝一层,如果第一层有数组或者对象,址引用
1、循环遍历
<script>
"use strict";
let lessons={title:"数据结构",teacher:{name:"王老师",sex:"男"}};
let obj={};
for(const key in lessons){
obj[key]=lessons[key];
}
obj.teacher.name="杨老师";
obj.category="软件工程";
console.log(JSON.stringify(lessons,null,2));
console.log(JSON.stringify(obj,null,2));
</script>
输出:
"title": "数据结构",
"teacher": {
"name": "杨老师",
"sex": "男"
}
}
test1.html:15 {
"title": "数据结构",
"teacher": {
"name": "杨老师",
"sex": "男"
},
"category": "软件工程"
}
修改obj的teacher的属性影响到了lessons的teacher。
2、Object.assign,这种方式更简单
<script>
"use strict";
let lessons={title:"数据结构",teacher:{name:"王老师",sex:"男"}};
let obj=Object.assign({},lessons);
obj.teacher.name="杨老师";
obj.category="软件工程";
console.log(JSON.stringify(lessons,null,2));
console.log(JSON.stringify(obj,null,2));
</script>
输出同上。
3、展开语法,这种方式也不错
<script>
"use strict";
let lessons={title:"数据结构",teacher:{name:"王老师",sex:"男"}};
let obj={...lessons};
obj.teacher.name="杨老师";
obj.category="软件工程";
console.log(JSON.stringify(lessons,null,2));
console.log(JSON.stringify(obj,null,2));
</script>
输出同上。
十、深拷贝
多层递归拷贝,每层的数组或者对象都重新开辟空间值引用
<script>
"use strict";
let lessons={title:"数据结构",teacher:{name:"王老师",sex:"男"}};
function copy(obj){
let res=obj instanceof Array?[]:{};
for(const [key,value] of Object.entries(obj)){
res[key]=typeof value=="object"?copy(value):value;
}
return res;
}
let obj=copy(lessons);
obj.teacher.name="杨老师";
obj.category="软件工程";
console.log(JSON.stringify(lessons,null,2));
console.log(JSON.stringify(obj,null,2));
</script>
输出:
{
"title": "数据结构",
"teacher": {
"name": "王老师",
"sex": "男"
}
}
{
"title": "数据结构",
"teacher": {
"name": "杨老师",
"sex": "男"
},
"category": "软件工程"
}
修改obj的teacher的属性不会影响到lessons的teacher。