目录
一、对象是什么?
对象是一个具体的事物。
对象是一组无序的相关属性和方法的集合,所有的事物都是对象,比如,字符串,数值,数组,函数等
二、对象的构成
1.属性
属性:是指事物的特征,在对象中用属性来表示(常用名词)
2.方法
方法:是指事物的行为,在对象中用方法来表示(常用动词)
示例:
//代码表示
<script>
var iphone12 = { //iphone:对象名
price: 9999, //price:属性 9999:属性值
sendTEL: function () { //方法
console.log("我能打电话")
},
}
console.log(iphone12.price);
console.log(iphone12.sendTEL())
</script>
三、对象的创建及使用
创建对象的三种方式
1.对象字面量:
花括号{ }里面包含了表达对象的属性和方法
示例:
// var obj ={} //创建了一个空对象
总结:
1、创建对象用字面量{ }创建对象,里面的属性或者方法采用的是:键:值 (键值对)的方式
多个属性或者方法之间是 ,(用逗号)隔开
方法 冒号后面跟的是一个匿名函数
2、 使用对象
(1)调用对象的属性,使用 对象名.属性名的方式,可以理解为,对象 的 属性
(2)调用对象的属性,也可使用 对象名[‘属性名’]的方式,注意加引号
调用对象的方法: 对象名.方法名() ,对象名.方法名() ,千万别忘了加小括号
3、变量、属性、函数、方法的总结
变量:单独声明赋值、单独存在
属性:对象里面的变量称为属性、不需要声明,用来描述该对象的特征
函数:单独存在的、通过 函数名() 的方式就可以调用
方法:对象里面的函数称为方法、方法不需要声明、使用 对象.方法名() 的方式就可以调用,方法用来描述该对象的行为和功能
变量和函数都需要声明,属性和方法不需要声明就可直接使用
2.利用new Object创建对象
<script>
var obj = new Object()
obj.name = '小坤';
obj.age = 18;
obj.sayHi = function () {
console.log("我能说:只因你太美!")
}
console.log(obj.name);
console.log(obj['age']);
console.log(obj.sayHi());
</script>
注意:在这里使用new Object() 创建对象,使用的是 =(等号)赋值的方法来添加对象的属性和方法
new 操作符做了哪些事(面试题)
1.创建一个空对象 new Object()
2.把空对象的__proto__,指向构造函数的原型对象prototype
3.把空对象作为this的指向上下文
4.如果函数无返回值,则返回this
引用类型:数组,对象,函数 每一个引用类型都有一个__proto__属性 隐式原型对象[[prototype]] 每一个函数都有一个 显式原型对象 prototype 1.创建一个空对象 new Object() 2.把空对象的__proto__,指向构造函数的原型对象prototype 3.把空对象作为this的指向上下文 4.如果函数无返回值,则返回this
3.利用构造函数创建对象
为什么需要用构造函数创建对象?因为前面两种创建方法一次只能创建一个对象,请看下面代码:
<script>
var obj1 = {
name: '张三疯',
age: 18,
sayHi: function () {
console.log("hello")
}
}
var obj2 = {
name: '李四',
age: 20,
sayHi: function () {
console.log("hello")
}
}
</script>
可以发现,创建的对象属性和方法都相同,如果需要创建很多个,一个一个创建效率就会很低。但是,我们可以利用一个函数去重复创建对象,这个函数称为构造函数。构造函数中封装的不是普通代码,而是对象。
构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new运算符一起使用,我们可以把对象中一些公共的属性和方法抽取出来封装到这个函数里面。
构造函数的语法格式:
function 构造函数名(){ //this可以理解为: 对象的...
this.属性=值;
this.方法=function(){}
}
使用构造函数:new 构造函数名 //注意:构造函数名首字母大写哟
//使用new调用构造函数返回的是一个对象
示例:
<script>
function Obj(name, age) { //创建构造函数,传入两个参数
this.name = name;
this.age = age;
this.sayHi = function () {
console.log("hello!");
}
}
var obj1 = new Obj('小蔡', 18) //使用new调用构造函数,返回的是一个对象
console.log(typeof (obj1)); //使用typeof()函数判断obj1的数据类型,证明返回的是对象
console.log(obj1.name); //获取名称
console.log(obj1.age); //获取年龄
console.log(obj1.sayHi()); //调用方法
</script>
总结:
1、构造函数和对象的区别:
构造函数是把对象相同的属性(公共部分)封装在一起,泛指的某一大类,如:明星/汽车图纸
他类似于java里面的类(class)对象:特指的一个具体事物,如:刘德华/一辆真实的汽车
2、new关键字执行构造函数创建对象的过程
- 在内存中创建一个新的空对象
- 让this指向这个新对象
- 执行构造函数里面的代码,给这个对象添加属性和方法
- 返回这个新对象(所以构造函数里面不需要return)
通过new关键字创建对象的过程也加对象的实例化
for in 遍历对象
let obj = {name:'cxk',Music:'鸡你太美'};
for(var item in obj){
console.log(item); // name,Music
console.log(obj[item]); // cxk 鸡你太美
}
Object.keys()遍历对象
作用:遍历对象
返回结果:返回对象中每一项key的数组
// 1. 定义一个对象
var obj = { 0:'熊大',1:'熊二',2:'光头强' }
// 2. 使用Object.keys()方法
var keyValue = Object.keys(obj)
// 3. 打印结果
console.log(keyValue) // 得到是:["0","1","2"]
也可以结合forEach来使用
Object.keys(要遍历的对象).forEach((v,i) => {})
Object.keys(obj).forEach(key => {
console.log(key, obj[key]);
})
// 得到的是:0---熊大
// 1---熊二
// 2---光头强
拷贝对象--扩展运算符
拓展运算符 ...
用于取出参数对象所有可遍历属性然后拷贝到当前对象。
一层嵌套为深拷贝
let person1={name:"Amy",age:16};
let someone1={...person1}
person1.age=17
console.log(someone1); // {name:"Amy",age:16}
多层嵌套为浅拷贝,也就是只能深拷贝一层嵌套的数据
let aa = {
age: 18,
name: 'aaa',
address: {
city: 'shanghai'
}
}
let bb = {...aa};
bb.address.city = 'shenzhen';
console.log(aa.address.city); // shenzhen
这种拷贝方式如果只是一层数组或是对象,其元素只是简单类型的元素,那么属于深拷贝,如果数组或对象中的元素是引用类型的元素,那么就是浅拷贝
如何合并对象
Object.assign()
同名属性会被覆盖
Object.assign种第一个值是目标对象,第二个值是源对象const obj1={a:"1",b:"2"} const obj2={b:"3",c:"4"} const result = Object.assign(obj1,obj2) console.log(result) //a:1 b:3 c:4 obj1中b的值被后面传入的obj2的值给覆盖掉了
扩展运算符
同名属性会被覆盖
使用…扩展运算符合并对象obj1对象在前和在后最后打印的结果是不同的
const obj1={a:"1",b:"2"}; const obj2={b:"3",c:"4"}; const result = {...obj1,...obj2}; console.log(result) //a:1 b:3 c:4 obj1中b的值被后面传入的obj2的值给覆盖掉了
如何删除对象属性
使用 delete 操作符
delete 将完全从对象中删除属性,会导致原始对象的发生改变,但速度很慢。
const item = {
species: 'dog',
age: 3,
name: 'celeste',
gender: 'female'
};
delete item.gender;
Object.keys(item); // ['species', 'age', 'name']
- delete操作符移除对象指定属性,删除成功返回true,否则返回false。
- 删除的属性不存在,delete不会起任何作用 ,但是仍会返回true。
- 如果原型链有同名属性,只会删除自身的属性。
- delete不能删除全局作用域函数以及作用域中用let或const声明的属性。
- delete可以删除对象的函数。
- 不可设置属性不能被删除。比如Math、Array、Object内置对象属性以及使用Object.defineProperty()方法设置的属性。
使用对象解构(较多属性操作时推荐)
通过用展开运算符(…)可以将需要省略特定属性的对象解构到新对象。这个技巧在需要删除多个属性时特别有用,并且不会更改原始对象。
const item = {
species: 'dog',
age: 3,
name: 'celeste',
gender: 'female'
};
const { gender,name, ...newItem } = item; // 删除 gender,name,两个属性且生成一个深拷贝的新对象
Object.keys(item); // ['species', 'age', 'name', 'gender']
Object.keys(newItem ); // ['species', 'age']
console.log(Object.keys(item),Object.keys(newItem ),item == newItem);//false
使用Reflect (单个属性操作时推荐)
ES6新增的方法,Reflect.deleteProperty(对象,属性名),返回一个布尔值。
const item = {
species: 'dog',
age: 3,
name: 'celeste',
gender: 'female'
};
Reflect.deleteProperty(item, 'gender')
Object.keys(item); // ['species', 'age', 'name']
日期对象
getFullYear()
使用 getFullYear() 获取年份
getTime()
getTime() 返回从 1970 年 1 月 1 日至今的毫秒数
setFullYear()
如何使用 setFullYear() 设置具体的日期
toUTCString()
如何使用 toUTCString() 将当日的日期(根据 UTC)转换为字符串
getDay()
如何使用 getDay() 和数组来显示星期,而不仅仅是数字
转自菜鸟教程更多对象前往菜鸟教程查看
举例:
var mydate = new Date();
console.log(mydate);
console.log(mydate.toLocaleDateString()); //2022/4/8 以本地日期字符串显示
console.log(mydate.toLocaleTimeString()); //11:29:08 以本地时分秒字符串显示
console.log(mydate.toLocaleString()); //2022/4/8 11:29:08 以本地日期字符串显示
console.log(mydate.getFullYear());//年份
console.log(mydate.getMonth()); //月份 0-11使用时要+1
console.log(mydate.getDate()); //日期
console.log(mydate.getHours()); //小时 24小时制
console.log(mydate.getMinutes()); //分钟
console.log(mydate.getSeconds()); //秒
console.log(mydate.getMilliseconds()); //毫秒 1s=1000ms
console.log(mydate.getDay()); // 0-6 星期日-->0 星期一-->1 使用时要进行判断转化
console.log(mydate.getTime()); //毫秒数 距离1970.1.1的毫秒数
console.log(mydate.Date.now()); //也表示毫秒数 距离1970.1.1的毫秒数
vue中设置日期及其格式模板
created() {
const date = new Date()
const Y = date.getFullYear() // 年
const M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1; //月
const D = date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate() //日
// const HH = date.getHours() < 10 ? '0' + (date.getHours()) : date.getHours() //时
// const MM = date.getMinutes() < 10 ? '0' + (date.getMinutes()) : date.getMinutes() //分
this.startDate = `${Y}-${M}-${D}`;
this.endDate = `${Y}-${M}-${D}`;
// this.dateValue = moment(new Date());
// console.log(moment().format("YYYY-MM-DD"));
// console.log(this.startDate, this.endDate,);
},
字符串对象+方法
字符串的索引从零开始, 所以字符串第一字符为 [0],第二个字符为 [1], 等等
字符串(String)使用长度属性length来计算字符串的长度
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置
// var a = new String("asdasffafg")
// document.write(a.length)
// for(var b = 0; b<=a.length-1;b++){
// document.write(a[b])//索引号 取值范围[0, b.length - 1]
// }
// var a = new String("asdafgsdfgsdfasd")
// document.write(a.indexOf("3"))
// .indexOf(参数1,参数2)
//从参数2的位置开始查找参数1的位置 默认从 0 开始
//参数1: 必需 查找的子串
//参数2: 可选 开始查找到的位置
//返回值:若查找到该子串 返回该字串在整个字符串第一次出现的位置 查找不到返回-1
// .lastindexOf(参数1,参数2)
// 从参数2的位置开始查找参数1的位置 默认从 最后一位 开始
计时器与定时器
计时器:setInterval(参数1,参数2) 间隔参数2的时间 执行一次参数1 的代码(不断执行)
clearInterval(); 取消setInterval的设置
定时器:setTimeout(参数1,参数2) 延迟参数2的时间,执行参数1里的代码 参数1 :待执行的代码串(只执行一次)
clearTimeout(); 取消setTimeout的设置
更多细节可查看链接
注意:
如setInterval(参数1,参数2);
参数一若为函数写法应是(函数名,参数2)或("函数名()",参数2),注意小括号在哪种情况下应该写。
参数一若为匿名函数写法应是(function(){},参数2)
使用举例:
//方法一 function gundong() { oDiv.scrollTop += 100; console.log(oDiv.scrollTop); } timer = setInterval("gundong()", 500); //方法二 function gundong() { oDiv.scrollTop += 100; console.log(oDiv.scrollTop); } timer = setInterval("gundong()", 500); //匿名函数 timer = setInterval(function () { document.documentElement.scrollTop -= 20; //高度值每次减少数值 累减 gdsz = document.documentElement.scrollTop; // console.log(gdsz); if (gdsz <= 0) { //计时器停止条件 clearInterval(timer); } }, 10);
防抖与节流
防抖:若一段时间内多次触发事件,则重新计时。
节流:若一段时间内多次触发事件,则只有一次生效。
防抖与节流常用在定时器上面。读上面两句话感觉没什么区别,其实区别大了,(如上图)比如要实现所有路口点单击后触发显示同一个提示框(单击不同点显示内容不同,显示框4s后会自动消失),若按照节流思路来做会导致单击其他路口点时显示框不足4s就消失,因为只有一次生效,所以此处应使用防抖思路来解决。
防抖简单方法封装:
<template>
<div>
<button @click="timerClick">测试</button>
</div>
</template>
<script>
export default {
data() {
return {
timer: null,//作用:控制定时器
}
},
methods: {
// 自定义防抖事件
timerClick() {
console.log("触发事件立即执行的操作");
clearTimeout(this.timer);//执行前先清除上次的定时器
this.timer = setTimeout(function () {
console.log("4秒后的操作");
}, 4000)
console.log("重新计时");
},
}
}
</script>
节流简单方法封装:
<template>
<div>
<button @click="timerClick">测试</button>
</div>
</template>
<script>
export default {
data() {
return {
flag: true,//作用:判断是否需操作执行
}
},
methods: {
// 自定义防抖事件
timerClick() {
console.log("触发事件立即执行的操作");
let thit = this;
if (this.flag) { // 判断下次是否可执行
this.flag = false; //一次事件未执行完成下次既不可执行
setTimeout(function () { // 注意此处this指向
console.log("4秒后的操作");
thit.flag = true; // 一次事件执行完成,下次可执行
}, 4000)
console.log("只触发了一次");
}
},
}
}
</script>
阻止默认行为
return false;放在要阻止执行的位置即可;还有其他更多方法,后续持续整理
举例:
<body>
<form action="">
<p>
<label for="uname">邮箱:</label>
<input type="text" id="uname" name="uname">
</p>
<p>
<label for="pwd">密码:</label>
<input type="password" id="pwd" name="pwd">
</p>
<input type="submit" value="提交" id="but">
<!-- 提交有默认行为 提交 -->
</form>
</body>
<script>
var _input1=document.getElementById("uname")
var _input2=document.querySelector("#pwd")
var _but = document.querySelector("#but")
_but.onclick = function(){
var a = _input1.value
var b = _input2.value
if(a.indexOf("@")===-1){
alert("请输入正确邮箱格式");
return false;//阻止提交默认行为
}
if(b.length<6){
alert("密码长度最少六位");
return false;//阻止提交默认行为
}
}
</script>
关于递归
递归指的是在函数的定义中使用函数自身的方法
递归通常不在意具体操作,只关心初始条件、结束条件和上下层的变化关系。
递归函数需要有临界停止点(结束条件),即递归不能无限制的执行下去。通常这个点为必须经过的一个数。
递归可以被栈替代。有些递归可以优化。比如遇到重复性的可以借助空间内存记录而减少递归的次数