类和构造函数区别
class Person{
constructor(name,age) {
this.name=name;
this.age=age;
// 这样子的speak方法就不是共享的
//this.speak=()=>{};
}
speak(){
console.log('speak');
}
//run(){}
}
console.log(typeof Person);//function
// 本质上是下面的内容,但是我们平时上面写比较方便且直观
console.log(Person.prototype.speak);
Person.prototype.run=function (){};
// function Person(name,age){
// this.name=name;
// this.age=age;
// // 这样子的speak方法就不是共享的
// //this.speak=()=>{};
// }
//
// // 需要在其原型上添加方法才是共享的
// Person.prototype.speak=function (){};
Class的两种定义形式
- 声明形式
- 表达式形式
// 1.声明形式
// class Person{
// constructor() {}
// speak(){}
// }
// 2.表达式形式
// 构造函数
// function Person(){}
// 我们可以把匿名函数赋值给一个变量/常量
// const Person=function (){}
// 类的表达式形式
// 我们可以把匿名类赋值给一个变量/常量
// const Person=class {
// constructor() {
// console.log('constructor');
// }
// speak(){}
// };
// new Person();
// 定义即被调用立即执行
(function (){
console.log('func');
})();
new (class{
constructor() {
console.log('constructor');
}
})();
实例属性、静态方法和静态属性
// 实例方法和实例属性
class Person{
age=0;
sex='male';
getSex=function (){
return this.sex;
}
// 实例对象的方法
speak(){
console.log('speak');
}
constructor(name,sex) {
this.name=name;
this.sex=sex;
}
// 静态方法
static speak(){
console.log('人类可以说话');
console.log(this);
}
// 不要这么写,有兼容性问题
// 静态属性
// static version='1.0';
// 通常这样写
static getVersion(){
return '1.0';
}
}
// 静态方法
// Person.speak=function (){
// console.log('人类可以说话');
// console.log(this);
// }
// 静态属性
// Person.version='1.0';
const p=new Person('Alex','female');
console.log(p);
p.speak();
// 静态方法
Person.speak();
console.log(Person.getVersion());
私有属性和方法
// class Person{
// constructor(name) {
// this._name=name;
// }
// speak(){
// console.log('speak');
// }
// getName(){
// return this._name;
// }
// }
// const p=new Person('jessica');
// console.log(p.getName());
// p.speak();
// // 模拟私有属性和方法
// // 1._开头表示私有(约定)
// console.log(p.getName());
// 2.将私有属性和方法移出类
(function () {
let name = '';
class Person {
constructor(username) {
name = username;
}
speak() {
console.log('speak');
}
getName() {
return name;
}
}
window.Person = Person;
})();
(function () {
const p = new Person('Alex');
console.log(p.name);//undefined
console.log(p.getName());//Alex
})();
继承extends
class Person{
constructor(name,sex) {
this.name=name;
this.sex=sex;
this.say=function (){
console.log('say');
};
}
speak(){
console.log('speak');
}
static speak(){
console.log('static speak');
}
}
Person.version='1.0';
class Programmer extends Person{
constructor(name,sex,feature) {
super(name,sex);
this.feature=feature;
}
// 同名覆盖
speak() {
console.log('Programmer speak');
}
static speak(){
console.log('Programmer static speak');
}
}
Programmer.version='2.0';
const zs = new Programmer('zs', '男','秃头');
console.log(zs.name);
console.log(zs.sex);
console.log(zs.feature);
zs.say();
zs.speak();
Programmer.speak();
console.log(Programmer.version);
super
- 作为函数调用
- 作为对象调用
- 注意事项(必须显式注明是函数调用还是对象调用)
// super作为对象使用
// 在构造方法或一般方法中使用
// super代表父类的原型对象 Person.prototype
// 所以定义在父类实例上的方法或属性,是无法通过super调用的
// 通过super调用父类的方法时,方法内部的this指向当前的子类实例
class Person{
constructor(name) {
this.name=name;
console.log(this);
}
speak(){
console.log('speak');
console.log(this);
}
}
class Programmer extends Person{
constructor(name,feature) {
super(name);
this.feature=feature;
console.log(super.name);
super.speak();
}
speak(){
super.speak();
console.log('Programmer speak');
}
}
new Person();
new Programmer();
class Person{
constructor(name) {
this.name=name;
//console.log(this);
}
speak(){
console.log('speak');
//console.log(this);
}
static speak(){
console.log('Person speak');
console.log(this);
}
}
class Programmer extends Person{
constructor(name,feature) {
super(name);
this.feature=feature;
console.log(super.name);
super.speak();
}
speak(){
super.speak();
console.log('Programmer speak');
}
// 静态方法中使用
// 指向父类,而不是父类的原型对象
// 通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例
static speak(){
super.speak();
console.log('Programmer speak');
}
}
Programmer.speak();
Class的应用
幻灯片的切换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Class 的应用</title>
<link rel="stylesheet" href="./slider.css" />
</head>
<body>
<div class="slider-layout">
<div class="slider">
<div class="slider-content">
<div class="slider-item">
<a href="javascript:;"
><img src="./imgs/1.jpg" alt="1" class="slider-img"
/></a>
</div>
<div class="slider-item">
<a href="javascript:;"
><img src="./imgs/2.jpg" alt="1" class="slider-img"
/></a>
</div>
<div class="slider-item">
<a href="javascript:;"
><img src="./imgs/3.jpg" alt="1" class="slider-img"
/></a>
</div>
<div class="slider-item">
<a href="javascript:;"
><img src="./imgs/4.jpg" alt="1" class="slider-img"
/></a>
</div>
</div>
</div>
</div>
<script src="./base.js"></script>
<script>
// console.log(BaseSlider);
class Slider extends BaseSlider {
constructor(el, options) {
super(el, options);
this._bindEvent();
}
_bindEvent() {
document.addEventListener('keyup', ev => {
// console.log(ev.keyCode);
if (ev.keyCode === 37) {
// ←
this.prev();
} else if (ev.keyCode === 39) {
// →
this.next();
}
});
}
}
new Slider(document.querySelector('.slider'), {
initialIndex: 1,
animation: true,
speed: 1000
});
</script>
</body>
</html>
/* css reset */
* {
padding: 0;
margin: 0;
}
a {
text-decoration: none;
outline: none;
}
img {
vertical-align: top;
}
/* layout */
.slider-layout {
width: 80%;
height: 420px;
margin: 0 auto;
}
/* slider */
.slider,
.slider-content,
.slider-item,
.slider-img {
width: 100%;
height: 100%;
}
.slider {
overflow: hidden;
}
.slider-item {
float: left;
}
.slider-animation {
transition-property: transform;
transition-duration: 0ms;
}
// 默认参数
const DEFAULTS = {
// 初始索引
initialIndex: 0,
// 切换时是否有动画
animation: true,
// 切换速度,单位 ms
speed: 300
};
// base
const ELEMENT_NODE = 1;
const SLIDER_ANIMATION_CLASSNAME = 'slider-animation';
class BaseSlider {
constructor(el, options) {
console.log(options)
if (el.nodeType !== ELEMENT_NODE)
throw new Error('实例化的时候,请传入 DOM 元素!');
// 实际参数
this.options = {
...DEFAULTS,
...options
};
const slider = el;
const sliderContent = slider.querySelector('.slider-content');
const sliderItems = sliderContent.querySelectorAll('.slider-item');
// 添加到 this 上,为了在方法中使用
this.slider = slider;
this.sliderContent = sliderContent;
this.sliderItems = sliderItems;
this.minIndex = 0;
this.maxIndex = sliderItems.length - 1;
this.currIndex = this.getCorrectedIndex(this.options.initialIndex);
// 每个 slider-item 的宽度(每次移动的距离)
this.itemWidth = sliderItems[0].offsetWidth;
this.init();
}
// 获取修正后的索引值
// 随心所欲,不逾矩
getCorrectedIndex(index) {
if (index < this.minIndex) return this.maxIndex;
if (index > this.maxIndex) return this.minIndex;
return index;
}
// 初始化
init() {
// 为每个 slider-item 设置宽度
this.setItemsWidth();
// 为 slider-content 设置宽度
this.setContentWidth();
// 切换到初始索引 initialIndex
this.move(this.getDistance());
// 开启动画
if (this.options.animation) {
this.openAnimation();
}
}
// 为每个 slider-item 设置宽度
setItemsWidth() {
for (const item of this.sliderItems) {
item.style.width = `${this.itemWidth}px`;
}
}
// 为 slider-content 设置宽度
setContentWidth() {
this.sliderContent.style.width = `${
this.itemWidth * this.sliderItems.length
}px`;
}
// 不带动画的移动
move(distance) {
this.sliderContent.style.transform = `translate3d(${distance}px, 0px, 0px)`;
}
// 带动画的移动
moveWithAnimation(distance) {
this.setAnimationSpeed(this.options.speed);
this.move(distance);
}
// 设置切换动画速度
setAnimationSpeed(speed) {
this.sliderContent.style.transitionDuration = `${speed}ms`;
}
// 获取要移动的距离
getDistance(index = this.currIndex) {
return -this.itemWidth * index;
}
// 开启动画
openAnimation() {
this.sliderContent.classList.add(SLIDER_ANIMATION_CLASSNAME);
}
// 关闭动画
closeAnimation() {
this.setAnimationSpeed(0);
}
// 切换到 index 索引对应的幻灯片
to(index) {
index = this.getCorrectedIndex(index);
if (this.currIndex === index) return;
this.currIndex = index;
const distance = this.getDistance();
if (this.options.animation) {
return this.moveWithAnimation(distance);
} else {
return this.move(distance);
}
}
// 切换上一张
prev() {
this.to(this.currIndex - 1);
}
// 切换下一张
next() {
this.to(this.currIndex + 1);
}
// 获取当前索引
getCurrIndex() {
return this.currIndex;
}
}
素材:1 2 3 4.jpg