class类的学习
一、class类的简介
- 传统的JS只有对象的概念,没有class类的概念,因为JS是基于原型的面向对象语言
举个栗子:
// 构造函数
function Person(name) {
this.name = name
}
Person.prototype.say = function() {
return `My name is ${this.name}`
}
// 实例化
const p = new Person('zhangsan')
console.log(p.say())
- ES6引入class类的概念,通过关键字class来定义类
举个栗子:
class Person {
// 构造函数 类被实例化就会立即调用
constructor(name) {
this.name = name // this表示的是实例化对象 即p
}
say() {
return `My name is ${this.name}`
}
}
// 类的实例化
const p = new Person('lisi')
console.log(p.say())
二、类的继承
- 使用关键字extends来继承父类
- 必须使用super()来将父类实例对象上的属性和方法加到子类的this上
- 如果子类没有constructor(),super()会自动加上
- 子类会继承父类的属性和方法
- 静态属性和静态方法必须通过类的类名来调用(关键字static)
举个栗子:
class Father {
// 静态属性 可以被类调用
static prop = 1
constructor(surname, gender) {
this.surname = surname
this.gender = gender
}
say() {
return `My surname is ${this.surname}`
}
sleep(){
return 'Father will go to sleep'
}
// 静态方法 可以被类调用 (this指向的是类而不是类的实例)
static work() {
return 'I will go to work'
}
}
class Son extends Father {
constructor(surname, gender, skill) {
super(surname, gender)
this.skill = skill
}
// 重写父类的say()方法
// say() {
// return '子类的say()方法'
// }
say() {
super.say() // 继承父类的say() 方法
return '子类的say()方法'
}
study() {
return `Son can ${this.skill.join('、')}`
}
}
// 类的实例化
const p = new Son('wang', 'man', ['弹钢琴', '跳舞', '游泳'])
console.log(p.say())
console.log(p.sleep())
console.log(p.study())
console.log(Son.prop,'----------1')
console.log(Son.work(),'----------2')
console.log(Father.prop,'----------1')
console.log(Father.work(),'----------2')
console.log(p.prop,'----------3') // undefined
// console.log(p.work(),'----------3') // 报错
三、类的注意事项
-
在类中定义方法时候,不可以给方法加上function关键字,因为JS中构造函数是用function定义的,两个隔开。
-
所有方法不要用逗号隔开,否则会报错。
-
函数模拟是有变量提升功能的,因为默认函数就是提升的,但是class类是没有提升功能的
四、class类应用
1. es6实现拖拽:
<script>
/**
* 功能:拖拽(鼠标按下、移动、放开)
*
* div1为父类,可基础拖拽;div2是子类,限制拖拽的位置(不可以拖拽出屏幕)
* constructor()构造器相当于初始化方法
*/
class Drag {
constructor(id) {
this.oDiv = document.querySelector(id)
this.divX = 0
this.divY = 0
this.oDiv.onmousedown = this.fnDowm.bind(this)
}
// 鼠标按下去时,获取div1距离左边和顶部的距离
fnDowm(e) {
this.divX = e.clientX - this.oDiv.offsetLeft
this.divY = e.clientY - this.oDiv.offsetTop
document.onmousemove = this.fnMove.bind(this)
document.onmouseup = this.fnUp.bind(this)
// 阻止默认事件 (可选中文字)
e.preventDefault()
}
// 鼠标移动
fnMove(e) {
this.oDiv.style.left = e.clientX - this.divX + 'px'
this.oDiv.style.top = e.clientY - this.divY + 'px'
}
// 鼠标放开
fnUp(e) {
document.onmousemove = null
document.onmouseup = null
}
}
// 子类继承
class LimitDrga extends Drag {
fnMove(e) {
// 继承父类的移动方法
super.fnMove(e)
// 子类自己的方法:限制移动的位置
this.oDiv.style.left = this.oDiv.offsetLeft <= 0 ? 0 : this.oDiv.offsetLeft
this.oDiv.style.top = this.oDiv.offsetTop <= 0 ? 0 : this.oDiv.offsetTop
}
}
// 调用
new Drag('#div1')
new LimitDrga('#div2')
</script>
2. react实现拖拽:
父类:
export default class extends Component {
constructor() {
super()
this.divX = 0
this.divY = 0
this.state = {
needX: 0,
neddY: 0
}
}
fnDown = () => {
return (e) => {
this.divX = e.clientX - e.target.offsetLeft
this.divY = e.clientY - e.target.offsetTop
document.onmousemove = this.fnMove.bind(this)
e.preventDefault()
}
}
fnMove(e) {
this.setState({
needX: e.clientX - this.divX + 'px',
needY: e.clientY - this.divY + 'px'
})
}
fnUp = () => {
return (e) => {
document.onmousemove = null
}
}
render() {
return (
<div className="box1" id="div1" style={{left: this.state.needX, top: this.state.needY}} onMouseDown={this.fnDown()} onMouseUp={this.fnUp()}>DIV1</div>
)
}
}
子类:
export default class extends Drag {
fnMove(e) {
// 继承父类的move方法,但子类还可以在父类的方法上添加自己的逻辑
super.fnMove.bind(this)
this.state.needX = e.clientX - this.divX <= 0 ? 0 : e.clientX - this.divX + 'px'
this.state.needY = e.clientY - this.divY <= 0 ? 0 : e.clientY - this.divY + 'px'
this.setState({})
}
render() {
return (
<div className="box2" id="div2" style={{left: this.state.needX, top: this.state.needY}} onMouseDown={this.fnDown()} onMouseUp={this.fnUp()}>DIV1</div>
)
}
}
五、总结
- class类是基于原型的继承的语法糖
- class的出现使得代码更加优雅,代码量减少
- class类能清晰的指定构造函数和抽象方法
- class类在声明时就可以设定属性和方法,不需要再往函数的原型中添加方法
- 使用class类时必须实例化
- 使用extends关键字实现继承