class是什么
- class是定义类的方法。ES6之前用构造函数的方式定义类,ES6引入了class。
- class是语法糖。
- class内部默认是严格模式。
- class不存在变量提升现象,必须要先声明后使用
使用
传统方式定义一个类
function Point1(x,y){
this.x = x
this.y = y
}
Point1.prototype.add = function(){
return this.x + this.y
}
var p1 = new Point1(3,9)
console.log(p1.add())
class方式定义一个类
class Point2{
constructor(x, y){
this.x = x
this.y = y
}
add(){
// 这里的add方法实际上是定义在原型上的。
return this.x + this.y
}
}
var p2 = new Point2(4,77)
console.log(p2.add())
类的数据类型
console.log(typeof Point1) // function
console.log(typeof Point2) // function
constructor
constructor 是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须要有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
class Point {
}
//等同于
class Point{
constructor(){
}
}
constructor 方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
class Foo{
constructor(){
return Object.create(null);
}
}
new Foo() instanceof Foo
//false
上面代码中,constructor函数返回一个全新的对象,结果导致实例对象不是Foo类的实例。
this指向问题
如果方法里有this,this指向的是实例
类的数据类型就是函数,类本身就是指向函数的
类的所有方法都是定义在类的prototype上的
类的私有变量
- 私有变量就是只能在类内部访问的变量,外部(类的实例化对象)无法访问的变量。
- 子类不能继承父类的私有变量。
私有变量的实现
- 私有变量定义在constructor 外面,并且加上#号;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#box {
position: absolute;
left: 100px;
top: 100px;
width: 100px;
height: 100px;
background: red;
}
#box2 {
position: absolute;
left: 200px;
top: 200px;
width: 100px;
height: 100px;
background: green;
}
</style>
</head>
<body>
<div id="box">文字</div>
<div id="box2">文字</div>
<script>
/*
抽象:
拖动之后元素跟随移动
封装:
封装成类
*/
class Drag {
startMouse = {
};
startEl = {
};
#el = null;//私有变量,在实例化对象中不能获取
constructor(el){
this.#el = el;
this.start();
}
start(){
let move = (e)=>{
this.move(e);
};
this.#el.addEventListener("mousedown",(e)=>{
this.startMouse = {
x: e.clientX,
y: e.clientY
};
this.startEl= this.getOffset();
// console.log(this.ondragstart);
this.ondragstart&&this.ondragstart(e);//start执行才会去执行ondragstart,所以ondragstart依赖于start
document.addEventListener("mousemove",move);
document.addEventListener("mouseup",()=>{
document.removeEventListener("mousemove",move);
this.end();
},{
once: true});
e.preventDefault();
});
}
move(e){
let nowMouse = {
x: e.clientX,
y: e.clientY
};
let disMouse = {
x: nowMouse.x - this.startMouse.x,
y: nowMouse.y - this.startMouse.y
};
this.setOffset(disMouse);
this.ondrag&&this.ondrag(e);
}
//拖拽结束
end(e){
this.ondragend&&this.ondragend(e);
}
// 获取元素的位置
getOffset(){
return {
x: parseFloat(getComputedStyle(this.#el)["left"]),
y: parseFloat(getComputedStyle(this.#el)["top"])
}
}
// 设置元素的位置
setOffset(dis){
this.#el.style.left = dis.x + this.startEl.x + "px";
this.#el.style.top = dis.y + this.startEl.y + "px"
}
}
{
let box = document.querySelector("#box");
let box2 = document.querySelector("#box2");
let d = new Drag(box);
let d2 = new Drag(box2);
let box2Clone = null;
d2.ondragstart = function(){
//console.log("开始拖拽");
box2Clone = box2.cloneNode(true);
//console.log(box2Clone);
document.body.appendChild(box2Clone);
box2.style.opacity = .5;
};
d2.ondrag = function(){
//console.log("拖拽中");
};
d2.ondragend = function(){
document.body.removeChild(box2Clone);
box2.style.opacity = 1;
};
}
</script>
</body>
</html>
为什么要使用私有变量
let d = new Drag(box);
d.el = box2;
上面的这个例子中,假如我们已经对一个元素实例化了,但是我们改变实例化对象的el 属性的话,那对el的这个拖拽就无法生效了,
el这个属性必须是私有属性。
类的继承
继承:继承可以使得子类具有父类的属性和方法并重新定义、追加属性和方法等。
class Person {
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name);
}
}
class Teacher extends Person {
constructor(name,age){
// 如果在子类中重新定义constructor,一定在这里调用 super
super(name,age);
this.speciality = "讲课";
}
skill(){
console.log("连续上课24小时");
}
}
console.log(new Person("小明",18));
console.log(new Teacher("小红",58));
类的静态属性
关于类有两个概念,1,类自身 ;2,类的实例对象
总的来说:静态的是指向类自身,而不是指向实例对象,主要是归属不同,这是静态属性的核心。
静态方法的使用:在方法前加上static关键字
class Foo {
static classMethod() {
return 'hello';
}
}
为什么使用静态方法:阻止方法被实例继承,类的内部相当于实例的原型,所有在类中直接定义的方法相当于在原型上定义方法,都会被类的实例继承,但是使用static静态方法定义的不会被实例继承,而且可以被实例直接应用Foo.classMethod(),此时写成new Foo.classMethod()会提示不存在此方法
静态方法中this指向:this指向类而不是类的实例
class Foo {
static bar () {
this.baz();
}
static baz () {
console.log('hello');
}
baz () {
console.log('world');
}
}
Foo.bar() // hello