<script>
// 类成员:member,能够直接写在类的{}里面的内容(写的内容的上级一定是{})
// 定义类
class Student {
// 类成员:属性(变量)和方法(函数)
/*
属性:变量,不需要let
方法:函数,不需要function
*/
// 属性
name = '张三'
age // 值:undefined
// 方法
study() {
// 有this:本质是有function关键字(不是箭头函数)
console.log(this.name + '今年' + this.age)
}
}
const s = new Student()
console.log(s)
// 正常对象访问即可:没有特殊性
console.log(s.name, s.age)
s.study()
// CRUD
s.gender = 'male'
s.age = 18
delete s.name
// 小结
// 类成员:属性和方法
// 属性作用:保存数据
// 方法作用:数据加工
// 属性保存在new出来的对象里面,方法自动放到原型对象中
</script>
注意:
// 类成员:属性和方法
// 属性作用:保存数据
// 方法作用:数据加工
// 属性保存在new出来的对象里面,方法自动放到原型对象中
// 类成员:属性(变量)和方法(函数)
属性:变量,不需要let
方法:函数,不需要function
<script>
// 构造器:constructor()特点是,只要new类,new出来的对象会第一时间自动调用constructor方法
class Student {
// 构造器
// 作用:给属性赋值,一般都有形参
constructor(name, age) {
console.log('我执行了')
console.log(name, age)
// 给属性赋值:任何时候任何地方访问属性,必须要对象参与
this.name = name
this.age = age
}
}
new Student()
// new 类名 和 new 类名():之前没有区别,是因为没有constructor
// new 类名() 括号就是对应constructor的() 传参数给constructor的
const s1 = new Student('张三', 18)
console.log(s1)
const s2 = new Student('李四', 18)
console.log(s2)
// 小结
// 1. 如果想要让类产生的对象不一样:数据不相同,增加一个constructor方法,用来给属性做初始化
// 2. constructor()产生对象后,对象自己调用:new的时候
// s2.constructor() // 报错:不允许调用
</script>
注意:
1.构造器:constructor()特点是,只要new类,new出来的对象会第一时间自动调用constructor方法
2.作用:给属性赋值,一般都有形参
3. new 类名 和 new 类名():之前没有区别,是因为没有constructor
new 类名() 括号就是对应constructor的() 传参数给constructor的
// 1. 如果想要让类产生的对象不一样:数据不相同,增加一个constructor方法,用来给属性做初始化
// 2. constructor()产生对象后,对象自己调用:new的时候
// s2.constructor() // 报错:不允许调用
(语法: class 子类 extends 父类{})
<script>
// 面向对象三大特点:封装、继承和多态
// 继承:体现代码的复用
// 老师跟学生都有姓名和性别,都需要初始化
// 可以将公共代码形成一个独立的类:Person
class Person {
specialName = 'Person'
constructor(name, age) {
console.log('我执行了')
this.name = name
this.age = age
}
}
// 凡是人类都需要用到姓名和年龄:老师和学生不例外
// 为了节省初始化name和age属性的代码:可以让学生类和老师类都继承Person类
// 语法: class 子类 extends 父类{}
class Teacher extends Person { }
class Student extends Person { }
// 实例化的时候:实例化子类,不要实例化父类
const t = new Teacher('张三', 30)
console.log(t)
// 继承的效果:子类拥有父类的成员(属性或者方法),可以直接使用:实现了代码的复用(正是因为继承的继承:才让面向对象能够非常强大,实现代码高级复用:框架存在的本质)
const s = new Student('李四', 28)
console.log(s)
</script>
注意:
1.面向对象三大特点:封装、继承和多态
2.继承:体现代码的复用
3.语法: class 子类 extends 父类{}
4.实例化的时候:实例化子类,不要实例化父类
5.继承的效果:子类拥有父类的成员(属性或者方法),可以直接使用:实现了代码的复用(正是因为继承的继承:才让面向对象能够非常强大,实现代码高级复用:框架存在的本质)
<script>
// 体验继承和实际开发的应用
class Person {
specialName = 'Person'
constructor(name, age) {
console.log('我执行了')
this.name = name
this.age = age
}
eat() {
console.log('吃东西')
}
drink() {
console.log('喝东西')
}
}
// 凡是人类都需要用到姓名和年龄:老师和学生不例外
// 为了节省初始化name和age属性的代码:可以让学生类和老师类都继承Person类
// 语法: class 子类 extends 父类{}
// 继承:解决的公共代码的复用问题
class Student extends Person { }
// 任何时候开发绝对不是为了单纯的继承:继承了公共代码之外还要有自己的功能
class Teacher extends Person {
study() {
console.log(this.name + "沉迷代码")
}
}
// 实例化对象
const t = new Teacher('前端', 30)
console.log(t)
t.eat()
// 实战思想
// 1. 公共代码放父类中
// 2. 子类继承父类(公共代码的使用权),一定会有自己的内容要处理(额外的方法之类)
</script>
<script>
// 重写:父类与子类拥有同名的属性和方法
class Person {
name = 'person'
makeMoney() {
console.log('我靠种田为生')
}
}
class NewPerson extends Person {
// 自己也有name属性,也有makeMoney()方法
name = 'newPerson'
makeMoney() {
console.log('我靠代码为生')
}
}
const np = new NewPerson()
console.log(np)
// 证明属性的覆盖性
console.log(np.name) // 证明成功:newPerson
// 证明方法的存在性
np.makeMoney() // 访问的是子类的:就近原则
// 如何访问到父类的?通过原型的上级去找
np.__proto__.makeMoney() // 还是自己的原型中
np.__proto__.__proto__.makeMoney() // 可以访问:没有被覆盖(一般覆盖)
// 重写:override,目的之一就是为了访问的时候访问自己的(逻辑发生了修改):针对特殊性
</script>
注意:
1. 重写具有覆盖性
2.访问的是子类的:就近原则
super(在原基础上增加)
<script>
// 重写:父类与子类拥有同名的属性和方法
class Person {
name = 'person'
makeMoney() {
console.log('我靠键盘为生')
}
}
// 需求:子类要重写父类的makeMoney方法,要求在原来的基础之上修改
// super关键字:在子类重写父类的方法中(makeMoney),调用父类的被重写的方法:super代表父类对象(上级对象)
class Student extends Person {
// 重写的目的:在原来的基础上做提升(扩展||优化)
makeMoney() {
// 调用父类被重写的方法
// super.被重写方法()
super.makeMoney()
console.log('我在原来的基础上学会了敲代码')
}
}
const s = new Student()
s.makeMoney()
</script>
注意:
1.super关键字:在子类重写父类的方法中(makeMoney),调用父类的被重写的方法:super代表父类对象(上级对象)
2.重写的目的:在原来的基础上做提升(扩展||优化)
3.// 调用父类被重写的方法
// super.被重写方法()
<script>
// 构造方法的重写
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
// 还有其他公共代码
}
// 学生有姓名和年龄,学生还有学号
class Student extends Person {
// 有学号需要初始化:原来的构造方法不够用:扩展
// 重写构造方法
constructor(name, age, stuno) {
// 构造方法被重写:必须先调用父类的构造方法
// super.constructor() // 依然报错:super.方法名()是因为不知道被重写的方法名字叫什么:但是constructor构造方法名字是确定,所有系统简化了这种调用方式:super()
// super()调用必须要在使用this之前
super(name, age)
// 构造方法的重写是实际开发中应用最多的
// 补充:学号
this.stuno = stuno
// super(name, age) // 报错:必须在使用this之前
// 习惯:一旦重写了构造方法:第一行代码写调用父类的构造方法
}
}
const s = new Student('安琪拉', 18, '000001')
console.log(s)
// 小结
// 重写需要考虑构造方法的特殊性:如果构造方法被重写
// 1. 一定需要在子类的构造方法,调用父类的构造方法
// 2. 调用方式:super(传入必要的参数)
</script>
注意:
1.super()调用必须要在使用this之前
2. // 重写需要考虑构造方法的特殊性:如果构造方法被重写
// 一定需要在子类的构造方法,调用父类的构造方法
// 调用方式:super(传入必要的参数)
<!DOCTYPE html>
<html lang="zh-CN">
<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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
.box {
width: 400px;
height: 300px;
border: 1px solid #ccc;
margin: 100px auto;
}
.hd {
height: 45px;
}
.hd span {
display: inline-block;
/*将行内元素转换成行内块元素,宽高才起作用*/
width: 90px;
background-color: pink;
line-height: 45px;
text-align: center;
cursor: pointer;
}
.hd span.current {
/*交集选择器,标签指定式选择器*/
background-color: purple;
/*紫色*/
}
.bd li {
height: 255px;
background-color: purple;
display: none;
/*设置隐藏*/
}
.bd li.current {
display: block;
/*显示*/
}
</style>
</head>
<body>
<div class="box">
<div class="hd">
<span class="current">体育</span>
<span>娱乐</span>
<span>新闻</span>
<span>综合</span>
</div>
<div class="bd">
<ul>
<li class="current">我是体育模块</li>
<li>我的娱乐模块</li>
<li>我是新闻模块</li>
<li>我是综合模块</li>
</ul>
</div>
</div>
<script>
// 需求:鼠标移入到对应的tab栏(菜单)上下都有切换内容
// 1. 采用面向对象:一个类
class TabExchange {
// 2. 有没有数据需要初始化:获取span,获取所有li:constructor()
constructor(selector) {
// 数据需要跨函数访问:类中所有的方法最终都是由new出来的对象调用:里面的this都是同一个,因此可以将数据保存到对象this里面
// 2.1 获取box
this.ele = document.querySelector(selector)
// console.log(this.ele)
// 2.2 获取所有的span
this.spans = this.ele.querySelectorAll('span')
// 2.3 获取所有的li
this.lis = this.ele.querySelectorAll('li')
}
// 3. 给所有的span做鼠标移入事件:新开一个方法来实现这个功能
mouseover() {
console.log(this)
// let that = this
// 3.1 遍历所有的span:给span添加鼠标移入事件
this.spans.forEach((span, index) => {
span.onmouseover = () => {
// console.log(this)
// 3.2 事件处理:排他所有的span,当前有类current,其他没有
this.spans.forEach((item) => {
item.classList.remove('current')
})
span.classList.add('current')
// 3.3 事件处理:排他所有的li,当前span对应的li有current,其他没有
this.lis.forEach((item) => {
item.classList.remove('current')
})
this.lis[index].classList.add('current')
}
})
}
}
// 4. 调用类:实例化,调用对应的方法(建议大家先做)
let te = new TabExchange('.box')
te.mouseover()
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<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>Document</title>
<style>
.current {
/* 浮动 */
float: left;
/* 宽高 */
width: 200px;
height: 200px;
border-radius: 50%;
border: 20px solid skyblue;
/* 内容居中 */
text-align: center;
line-height: 200px;
/* 字体 */
font-size: 24px;
}
</style>
</head>
<body>
<script>
// 使用面向对象方法,实现动态的创建元素,创建好的元素可以放到指定的元素后面做孩子(父元素.appendChild(子元素)
// 1. 上来先定义一个类:CreateElement
class CreateElement {
// 2. 有没有数据要初始化:有,创建元素:constructor(),创建元素、添加指定的类、添加指定的文本:元素要给其他方法用,用this保存
constructor(tag, className, text) {
// 2.1 创建元素,根据tag来创建,存入到this中
this.ele = document.createElement(tag)
// console.log(this)
// 2.2 给元素添加类
this.ele.classList.add(className)
// 2.3 给元素添加文本
this.ele.innerText = text
}
// 3. 增加一个方法:appendTo()可以让用户指定父元素,将子元素放到父元素的里面当做最后一个孩子
appendTo(selector) {
// 3.1 获取父元素
// 3.2 将this中的ele元素添加到父元素去
document.querySelector(selector).appendChild(this.ele)
}
}
// 4. 实例化调用
let div = new CreateElement('div', 'current', '做人,死了也挺好')
div.appendTo('body')
new CreateElement('span', 'current', '做人,活着也挺好').appendTo('body')
</script>
</body>
</html>```
* 案例②:
```javascript
<!DOCTYPE html>
<html lang="zh-CN">
<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>Document</title>
<style>
.current {
/* 浮动 */
float: left;
/* 宽高 */
width: 200px;
height: 200px;
border-radius: 50%;
border: 20px solid skyblue;
/* 内容居中 */
text-align: center;
line-height: 200px;
/* 字体 */
font-size: 24px;
}
</style>
</head>
<body>
<script>
// 使用面向对象方法,实现动态的创建元素,创建好的元素可以放到指定的元素后面做孩子(父元素.appendChild(子元素)
// 1. 上来先定义一个类:CreateElement
class CreateElement {
// 2. 有没有数据要初始化:有,创建元素:constructor(),创建元素、添加指定的类、添加指定的文本:元素要给其他方法用,用this保存
constructor(tag, className, text) {
// 2.1 创建元素,根据tag来创建,存入到this中
this.ele = document.createElement(tag)
// console.log(this)
// 2.2 给元素添加类
this.ele.classList.add(className)
// 2.3 给元素添加文本
this.ele.innerText = text
}
// 3. 增加一个方法:appendTo()可以让用户指定父元素,将子元素放到父元素的里面当做最后一个孩子
appendTo(selector) {
// 3.1 获取父元素
// 3.2 将this中的ele元素添加到父元素去
document.querySelector(selector).appendChild(this.ele)
}
}
// 4. 实例化调用
// let img = new CreateElement('img', 'current', '') // 图片的核心是src:原来没有
// img.appendTo('body')
// 原来的CreateElement这个类的绝大部分功能都已经实现好了:现在就缺图片的src
// 另外:CreateElement是创建所有元素,包含图片
// 发现:新需求只要用到原来的代码,又需要修改一点点:继承extends,重写(扩展src属性)
// 1. 创建一个新类:CreateImg 继承 CreateElement
class CreateImg extends CreateElement {
// 2. 初始化有问题:重写父类的构造函数(方法):constructor
constructor(src, className) {
// 2.1 先执行父类的构造方法:super('img',className,'')
super('img', className, '')
// console.log(this.ele)
// 2.2 扩展src功能
this.ele.src = src
}
}
// 测试
let img = new CreateImg('images/b1.jpg', 'current')
img.appendTo('body')
// 创建div:跟img没有关系
let div = new CreateElement('div', 'current', '做人还是活着吧')
div.appendTo('body')
</script>
</body>
</html>