十一、对象进阶
1.this
(1).构造函数里面的this,用于给类定义成员(属性和方法)
(2).方法里面的this,指向方法的调用者
(3).箭头函数中没有this,如果在箭头函数中使用了this,会向外层寻找this的指向
(4).如果所有的外层都没有this,最终会指向window对象
注意:用于var定义的成员(变量和方法)都会成为window对象的成员
解决this指向问题:
方式一:备份this
方式二:使用箭头函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>this1</title>
</head>
<body>
<script>
// 注意:构造函数不能使用箭头函数定义
function Person(name,age){
// 在构造函数中,this关键字,用于给类添加成员
this.name = name
this.age = age
this.sayHi = function(){
console.log(`大家好!我叫${this.name},今年${this.age}岁`);
}
}
// 创建对象,该对象会拥有,类型中定义的所有成员。
let p1 = new Person('张三',20)
console.log(p1);
p1.sayHi()
let p2 = new Person('李四',24)
console.log(p2);
p2.sayHi()
console.log('-----------------------------------------');
let obj1 = {
//对象的两个属性
name:'李白',
age:20,
//对象的方法
sayHi:function(){
// 在方法中,this指向方法的调用者,谁在调用该方法,this就指向谁
// 如果一个方法,不是由对象调用执行的,而是直接执行的,那么该方法里面的this就执行window对象
console.log(`Hi!我是${this.name},今年${this.age}岁`);
},
sayHello:()=>{
// 在箭头函数中没有this,如果在箭头函数中使用了this,它会向上一层函数中去找this
// 如果上一层函数也是箭头函数,或者没有上一层函数了,这个时候this就指向window对象。
console.log(`Hello!我是${this.name},今年${this.age}岁`);
}
}
obj1.sayHi()
let obj2 = {
name:'杜甫',
age:22,
}
//可以将obj1的函数传给obj2,其实是obj2的sayHi方法,指向obj1的方法
obj2.sayHi = obj1.sayHi
obj2.sayHi()
//将obj1身上的函数,传给了一个sayHi变量
let sayHi = obj1.sayHi
window.name = '小明' //设置window对象的name属性
window.age = 22 //设置window对象的age属性
sayHi()
console.log('-------------------------');
obj1.sayHello()
obj2.sayHello = obj1.sayHello
obj2.sayHello()
let sayHello = obj1.sayHello
sayHello()
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>this2</title>
</head>
<body>
<script>
// var 定义的成员,会自动添加为window对象的成员
var address = '北京'
var showAddress = function(){
console.log(`地点在${this.address}`);
}
console.log(window);
showAddress()
window.showAddress()
console.log('---------------------------------------');
// 定义一个对象
let obj1 = {
name:'张三',
age:25,
//自我介绍方法
sayHi(){
console.log(`Hi!我叫${this.name},今年${this.age}岁`);
},
//显示我的朋友信息
showMyFriend(){
// 备份this
// let that = this
return {
name:'李四',
age:22,
//自我介绍的方法
sayHi(){
console.log(`Hi!我叫${this.name},今年${this.age}岁`);
},
//介绍朋友
showMf:()=>{
// console.log(`Hi!我的朋友叫${that.name},今年${that.age}岁`);
console.log(`Hi!我的朋友叫${this.name},今年${this.age}岁`);
}
}
}
}
obj1.sayHi()
let obj2 = obj1.showMyFriend()
obj2.sayHi() //调用自我介绍的方法
obj2.showMf() //调用介绍朋友的方法
</script>
</body>
</html>
2.call apply bind
使用call apply bind更改方法里面this的指向
1.使用call()改变方法里面,this的指向。call()方法的第一个参数必须是指定的对象,方法的原有参数,挨个放在后面
2.使用apply(),也可以改变方法里面this的指向。第一个参是指定的对象,方法的原有参数,统一放到第二个数组参数中。
3.使用bind(),也可以改变方法里面this的指向,用法给call()一样。call()是直接运行方法,bind()是返回新的方法,然后再重新调用。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>call apply bind</title>
</head>
<body>
<script>
// call apply bind 更改方法里面this的指向
let obj1 = {
name:'张三',
age:30,
sayHi(a,b){
console.log(`Hi!我叫${this.name},今年${this.age}岁。${a}-${b}`);
}
}
let obj2 = {
name:'李四',
age:32
}
// 使用call()改变方法里面,this的指向
// call()方法的第一个参数必须是指定的对象,方法的原有参数,挨个放在后面
obj1.sayHi.call(obj2,200,100)
let obj3 = {
name:'王五',
age:35
}
// 使用apply(),也可以改变方法里面this的指向,第一个参是指定的对象,方法的原有参数,统一放到第二个数组参数中
obj1.sayHi.apply(obj3,[200,100])
let obj4 = {
name:'小明',
age:40
}
// 使用bind(),也可以改变方法里面this的指向,用法给call()一样
// call()是直接运行方法,bind()是返回新的方法,然后再重新调用。
obj1.sayHi.bind(obj4,200,100)()
</script>
</body>
</html>
3.将一个对象转为字符串
获取对象的属性值,有两种方式:
1.对象名.属性名
2.对象名["属性名"]
//定义一个手机对象
let phone = {
name: "小米10",
color: '红色',
size: '1000*200*500',
price: '2999'
}
//转成下面的字符串
//"name=小米10&color=红色&size=1000*200*500&price=2999"
for in 循环,可以循环出对象里面的所有的key,(key就是属性名)
在ES6中新增了获取对象所有key的方法 -> ECMAScript2015 其实就是最新版本的javascript标准
Object.keys(指定的对象),该方法可以获取指定对象的所有key,返回值是一个数组
Object.values(指定的对象),该方法可以获取指定对象的所有的value,返回值是一个数组
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>将一个对象转为字符串</title>
</head>
<body>
<script>
//定义一个对象
let obj1 = {}
//给对象添加属性有两种方式:
obj1.name = '张三'
console.log(obj1);
obj1['age'] = 20
console.log(obj1);
console.log('----------------------------------');
//定义一个手机对象
let phone = {
name: "小米10",
color: '红色',
size: '1000*200*500',
price: '2999'
}
//转成下面的字符串
//"name=小米10&color=红色&size=1000*200*500&price=2999"
// for in 循环,可以遍历出对象的所有key(key就是属性名称)
//方式一:
let arr = [] // 定义一个空数组
for(let key in phone){
//获取对象的属性值,可以通过['属性名']
arr.push(key+'='+phone[key])
}
let str = arr.join('&')
console.log(str);
//方式二:
// Object.keys方法,用于返回对象的所有属性名,返回值是一个数组
let keys = Object.keys(phone)
// Object.values,用于返回对象的所有属性值,返回值是一个数组
// let values = Object.values(phone)
let arr2 = keys.map(function(k){
return [k,phone[k]].join('=')
})
let str2 = arr2.join('&')
console.log(str2);
//方法二:简化写法
let str3 = Object.keys(phone).map(k=>[k,phone[k]].join('=')).join('&')
console.log(str3);
</script>
</body>
</html>
4.将字符串转为对象
//定义一个字符串
let str = "name=小米10&color=红色&size=1000*200*500&price=2999"
//转成一个对象
{
name: "小米10",
color: '红色',
size: '1000*200*500',
price: '2999'
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>将字符串转为对象</title>
</head>
<body>
<script src="./js/bing.js"></script>
<script>
//定义一个字符串
let str = "name=小米10&color=红色&size=1000*200*500&price=2999"
//转成一个对象
/* {
name: "小米10",
color: '红色',
size: '1000*200*500',
price: '2999'
} */
let obj = {} //定义一个空对象
str.split('&').forEach(r=>{
let arr = r.split('=')
// arr=>['name','小米10']
// obj['name'] = '小米10'
obj[arr[0]] = arr[1]
})
console.log(obj);
console.log('----------------------------------');
let obj2 = {
name:'小明',
age:20,
sex:'男',
job:'教师'
}
console.log($b.objectToStr(obj2));
console.log($b.objectToStr(obj2,'@'));
console.log($b.objectToStr(obj2,'哈哈'));
let str2 = 'name=小明&age=20&sex=男&job=教师'
console.log($b.strToObject(str2));
console.log($b.strToObject(str2,'&'));
let str3 = 'name=小李@age=21@sex=男@job=厨师'
console.log($b.strToObject(str3,'@'));
</script>
</body>
</html>
5.封装js库
1.isLeepYear 判断是否闰年
2.strReverse 字符串翻转
3.getMiniDate 短日期
4.getChineseDate 中国式日期
5.getPageData 分页方法
6.getStrByObj 对象转字符串
7.getObjByStr 字符串转对象
// 定义一个对象,用于保存所有的工具方法
// 这样做的目的是,防止方法被后引入的库覆盖。
let $b = {
// 判断是否是闰年的方法
isLeapYear:(year) => (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0,
// 对个位数字补零的方法
repair0:(val) => (val < 10 ? "0" + val : val),
// 返回一个日期的短日期格式方法
miniDate:function (date, type){
let year = date.getFullYear(); //年
let month = date.getMonth() + 1; //月
let day = date.getDate(); //日
let hour = date.getHours(); //时
let minute = date.getMinutes(); //分
let second = date.getSeconds(); //秒
let week = date.getDay(); //周几
//定义一个返回值,默认拼接:年,月,日
let ret = [this.repair0(year), this.repair0(month), this.repair0(day)].join("-");
if (type == "1") {
ret += " " + [this.repair0(hour), this.repair0(minute), this.repair0(second)].join(":");
} else if (type == "2") {
ret +=
" " +
[this.repair0(hour), this.repair0(minute), this.repair0(second)].join(":") +
" 星期" +
"日一二三四五六"[week];
}
return ret;
},
// 对字符串反转的方法
reverseStr:(str) => str.split("").reverse().join(""),
// 定义一个分页方法,参数是:数组,页码,每页数量
pageData:function(arr,pageIndex,pageSize){
let start = (pageIndex-1)*pageSize //算出起始下标
let end = start+pageSize //算出结束下标
//根据起始下标和结束下标,从原始数组中截取对应的数据并返回
return {
//定义返回的数据
data:arr.slice(start,end),
//总数量
count:arr.length,
//总页数
totalPage:Math.ceil(arr.length/pageSize),
//当前页
pageIndex:pageIndex,
//每页数量
pageSize:pageSize
}
},
//将对象转为字符串
objectToStr:(obj,split='&') => Object.keys(obj).map(k=>[k,obj[k]].join('=')).join(split),
//将字符串转为对象
strToObject:(str,split='&')=>{
let obj = {} //定义一个空对象
str.split(split).forEach(r=>{
let arr = r.split('=')
obj[arr[0]] = arr[1]
})
return obj
}
}
6.练习题:
1.统计字符串中每个字符串出现的次数
let str = "fasdfsadfsegsageqwgersfdhrhdfsergterwhefweteqheq"
//转成下面格式的对象
{
a:5,
b:7,
c:9,
...
}
2.找出出现次数最多的字符
//定义一个对象接收结果
let max = {
name:'',
count:0
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>统计字符串中每个字符串出现的次数</title>
</head>
<body>
<script>
//字符串
let str = "fasdfsadfsegsageqwgersfdhrhdfsergterwhefweteqheq"
//对象
let obj = {}
// 循环字符串中的所有的字符串
for(let i=0;i<str.length;i++){
//根据字符的名称,查找对象中,有没有对应的属性
if(obj[str[i]]){
//如果有,对应的属性值加1
obj[str[i]]++
}else{
//如果没有,添加这个属性,属性值赋为1
obj[str[i]] = 1
}
}
console.log(obj);
console.log('-----------------------');
//定义一个出现次数最多的字符对象
let max = {
name:'',
count:0
}
Object.keys(obj).forEach(k=>{
//判断是否有别的字符串大于max
if(obj[k]>max.count){
max.name = k
max.count = obj[k]
}
})
console.log(max);
</script>
</body>
</html>
7.使用对象数组保存学生信息,实现对学生的增删改查
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生管理系统</title>
</head>
<body>
<script>
// 定义一个学生管理对象
let studentManager = {
//定义一个学生数组
students:[
{
no:'1001',
name:'张三',
age:22,
sex:'男'
},
{
no:'1002',
name:'李四',
age:24,
sex:'女'
},
{
no:'1003',
name:'王五',
age:26,
sex:'男'
}
],
//显示所有学生信息的方法
show:function(){
let str = "学号 姓名 年龄 性别\n"
// 循环出所有的学生信息,并拼接到str中
this.students.forEach(s=>{
str+=`${s.no} ${s.name} ${s.age} ${s.sex}\n`
})
alert(str)
},
//添加学生信息的方法
add:function(){
//输入学生的基本信息
let no = prompt('请输入学号:')
//判断学号是否重复
let index = this.students.findIndex(r=>r.no===no)
while(index!==-1){
no = prompt('学号重复!请重新输入学号:')
index = this.students.findIndex(r=>r.no===no)
}
let name = prompt('请输入姓名:')
let age = parseInt(prompt('请输入年龄:'))
let sex = prompt('请输入性别:')
// 创建学生对象
let stu = {
no:no,
name:name,
age:age,
sex:sex
}
// 将学生对象添加到数组中(学号不能重复)
this.students.push(stu)
alert('添加成功!')
},
//修改学生信息的方法
update:function(){
//输入学生的基本信息
let no = prompt('请输入学号:')
//根据学号,到数组中查找并返回指定的学生对象
let stu = this.students.find(r=>r.no===no)
//根据学号判断,有没有找到该学生,找到了修改该学生的其他信息,没有找到提示学号不存在
while(!stu){
no = prompt('您输入的学号不存在,请重新输入:')
stu = this.students.find(r=>r.no===no)
}
stu.name = prompt('请重新输入该学生的姓名:')
stu.age = parseInt(prompt('请重新输入该学生的年龄:'))
stu.sex = prompt('请重新输入该学生的性别:')
alert('修改成功!')
},
//删除学生信息的方法
delete:function(){
//输入学生的基本信息
let no = prompt('请输入学号:')
//查找该学生在数组中的位置
let index = this.students.findIndex(r=>r.no===no)
while(index===-1){
no = prompt('学号不存在!请重新输入学号:')
index = this.students.findIndex(r=>r.no===no)
}
this.students.splice(index,1)
alert('删除成功!')
},
//系统主菜单方法
menu:function(){
//接收用户的输入
let no = prompt('*****学生管理系统*****\n1.查询学生 2.添加学生 3.修改学生 4.删除学生 0.退出系统')
//判断用户输入的是什么
switch(no){
case '1':
//调用显示所有学生信息的方法
this.show()
break;
case '2':
//调用添加学生信息的方法
this.add()
break;
case '3':
//调用修改学生信息的方法
this.update()
break;
case '4':
//调用删除学生信息的方法
this.delete()
break;
default:
alert('成功退出系统!欢迎下次使用!')
return //跳转整个方法
}
// 再次调用自身方法(递归)
this.menu()
}
}
// 使用学生管理对象,调用menu方法
studentManager.menu()
</script>
</body>
</html>