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
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