ES6-10笔记(class类)

摘要:
类Javascript是一种基于对象的语言。几乎所有你遇到的都是一个物体。然而,它不是真正的面向对象编程(OOP)语言,因为它的语法中没有类。从阮一峰老师的引用中摘录,该类声明ES5只有JavaScript中的对象。如果要模拟类以生成对象实例,则只能定义构造函数,然后使用新运算符来完成它。letAnimal=函数(典型值

class类

ES6-10笔记(class类)第1张

Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。摘自阮一峰老师语录

class声明

ES5的JavaScript中只有对象,想要模拟类去生成一个对象实例,只能通过定义一个构造函数,然后通过new操作符来完成。

let Animal = function (type) {
  this.type = type
}

Animal.prototype.walk = function () {
  console.log(`I am walking`)
}

let dog = new Animal('dog')
let monkey = new Animal('monkey')

//构造函数生成实例的执行过程
1.当使用了构造函数,并且new 构造函数(),后台会隐式执行new Object()创建对象;
2.将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this就代表new Object()出来的对象。
3.执行构造函数的代码。
4.返回新对象(后台直接返回);

ES6引入了Class(类)这个概念,通过class关键字可以定义一个类

class Animal {
  constructor (type) {
    this.type = type
  }
  walk () {
    console.log(`I am walking`)
  }
}
let dog = new Animal('dog')
let monkey = new Animal('monkey')

但是Class的类型还是function,并且console.log(Animal.prototype);结果几乎是一样的,所以可以认为class声明类的方式是function声明类方式的语法糖。甚至在class声明类后仍可使用ES5的方式来为这个类添加,覆盖方法。

console.log(typeof Animal); //function

ES5中打印的console.log(Animal.prototype)
//{eat: ƒ, constructor: ƒ}
//eat: ƒ ()
//constructor: ƒ (type)
//__proto__: Object

ES6中打印的console.log(Animal.prototype)
//{constructor: ƒ, eat: ƒ}
//constructor: class Animal
//eat: ƒ eat()
//__proto__: Object

除了constructor后边分别是f(type)和class Animal

class不存在变量提升,所以需要先定义再使用。因为ES6不会把类的声明提升到代码头部,但是ES5就不一样,ES5存在变量提升,可以先使用,然后再定义。

//ES5可以先使用再定义,存在变量提升
new A();
function A(){

}
//ES6不能先使用再定义,不存在变量提升 会报错
new B();//B is not defined
class B{

}

Setters&Getters

类中的属性,可以直接在constructor中通过this直接定义,还可以通过get/set直接在类的顶层定义

class Animal {
  constructor (type, age) {
    this.type = type
    this._age = age
  }
  get age () {
    return this._age
  }
  set age (val) {
    this._age = val
  }
}

get可以定义一个只读属性

class Animal {
  constructor (type) {
    this.type = type
  }
  get addr () {
    return '北京动物园'
  }
}

get/set可以进行一些简单封装,如下

class CustomHTMLElement {
  constructor (element) {
    this.element = element
  }
  get html () {
    return this.element.innerHTML
  }
  set html (value) {
    this.element.innerHTML = value
  }
}

get/set还可以模拟设置私有属性,并可以通过get和set对获取属性和读取属性进行一些逻辑判断

let _age = 4
class Animal{
	constructor(type) {
	    this.type = type
	}
	get age() {
		if(this.type == 'dog'){
				return _age
		}else{
			return "I don't know"
		}
	}
	set age(val){
		if(val<7&&val>4){
			_age = val
		}
	}
	eat () {
		console.log('i am eat food')
	}
}

let dog = new Animal('dog')
let cat = new Animal('cat')
console.log(dog.age)//4
console.log(cat.age)//I don't know  在get age中只有dog能拿到_age
dog.age = 6
console.log(dog.age)//6
dog.age = 8
console.log(dog.age)//6  在set age中传入参数必须小于7大于4才能生效

继承

ES5中继承的实现

// 定义父类
let Animal = function (type) {
  this.type = type
}
// 定义方法
Animal.prototype.walk = function () {
  console.log(`I am walking`)
}
// 定义静态方法
Animal.eat = function (food) {
  console.log(`I am eating`)
}
// 定义子类
let Dog = function () {
  // 初始化父类
  Animal.call(this, 'dog')
  this.run = function () {
    console.log('I can run')
  }
}
// 继承
Dog.prototype = Animal.prototype

ES6中通过extends关键字实现继承。

子类必须在constructor方法中调用super方法,之后才能使用this关键字,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象。如果不调用super方法,子类就得不到this对象。在这一点上ES5的继承与ES6正好相反,ES5先创建自己的this对象然后再将父类的属性方法添加到自己的this当中。

如果子类没有显式的定义constructor,那么下面的代码将被默认添加(不信可以尝试下,哈)。换言之,如果constructor函数中只有super的话,该constructor函数可以省略。

class Animal {
  constructor (type) {
    this.type = type
  }
  walk () {
    console.log(`I am walking`)
  }
  static eat () {
    console.log(`I am eating`)
  }
}

class Dog extends Animal {
  constructor () {
    super('dog')
  }
  run () {
    console.log('I can run')
  }
}

静态方法 static Methods&静态属性

静态方法是面向对象最常用的功能,在ES5中利用function实现的类是这样实现一个静态方法的

let Animal = function (type) {
  this.type = type
  this.walk = function () {
    console.log(`I am walking`)
  }
}

Animal.eat = function (food) {
  console.log(`I am eating`);
}

在ES6中使用static的比纳基是不是静态方法

class Animal {
  constructor (type) {
    this.type = type
  }
  walk () {
    console.log(`I am walking`)
  }
  static eat () {
    console.log(`I am eating`)
  }
}

静态方法不需要实例化可以直接通过类调用

class Animal{
    static a(){
        return "我是Animal类中的,实例方法,无须实例化,可以直接调用"
    }
}
//通过类名直接调用
console.log(Animal.a());//我是Animal类中的,实例方法,无须实例化,可直接调用!

静态方法只能在静态方法中调用,不能在实例方法中调用

class Animal{
    static a(){
        return "我只允许被静态方法调用哦!"
    }
    static b(){
        //通过静态方法b来调用静态方法a
        console.log(this.a());
    }
}
Animal.b();//输出:我只允许被静态方法调用


通过实例方法来调用静态方法会报错

class Animal{
    static a(){
        return "我只允许被静态方法调用哦!"
    }
    b(){
        console.log(this.a());//TypeError: this.a is not a function
    }
}
var obj=new Animal();
obj.b();

//其他地方想要调用静态方法可借助类来调用,如使用Animal.b()
class Animal{
    static a(){
        return "我只允许被静态方法调用哦!"
    }
    static b(){
        //通过静态方法b来调用静态方法a
        console.log(this.a());
    }
    c(){
    	console.log(Animal.b())
    }
}
Animal.b();//输出:我只允许被静态方法调用
let dog = new Animal()
Animal.c()////输出:我只允许被静态方法调用

父类的静态方法,可以被子类继承

class Animal {
    static a() {//父类Animal的静态方法
        return '我是父类的静态方法a';
    }
}
class Dog extends Animal {}
//子类Dog可以直接调用父类的静态方法a
console.log(Dog.a()); 

想通过子类的静态方法调用父类的静态方法,需要从super对象上调用

class Animal {
    static a() {
        return '我是通过super来调取出来的';
    }
}
class Dog extends Animal {
    static a(){
        return super.a();
    }
}
console.log(Dog.a()); //我是通过super来调取出来的

静态属性指的是 Class 本身的属性, 即Class.propname, 而不是定义在实例对象( this) 上的属性。

class Animal{
   constructor(){
       this.name="实例属性"
   }
}
Animal.prop1="静态属性1";
Animal.prop2="静态属性2";
console.log(Animal.prop1,Animal.prop2);//静态属性1  静态属性2

类的应用场景

前端各种框架起飞,基本不需要去使用类来实现或者完善前端页面功能,在服务端写node.js的话可能会经常使用类语法。

下方代码是用类实现在同一个页面设置多个分页列表。(这个功能多数UI框架也解决了。。。)

class PageUtil{
	constructor(pageNo,pageSize,total){    //构造初始变量
		this.pageNo = pageNo;     //起始页面
		this.pageSize = pageSize  //一页数据条数
		this.total = total        //数据总数
		this.currentPage = 0      //当前选中页数
		this.pageTotal = Math.ceil(this.total/this.pageSize)   //总页数
	}
	nextPage(){     //下一页
		if(this.currentPage < this.pageTotal){
			this.currentPage++
		}
	}
	beforePage(){    //上一页
		if(this.currentPage > 1){
			this.currentPage--
		}
	}
	jumpPage(page){     //跳页
		this.currentPage = page
	}
	changePageSize(pageSize){    //改变页大小
		this.pageSize = pageSize
		this.pageTotal = Math.ceil(this.total/this.pageSize)   //总页数
	}
	getTotalPage(){    //获取总页数
		return Math.ceil(this.total/this.pageSize)
	}
}


class DialogPage extends PageUtil{    //继承PageUtil类
	constructor(pageNo,pageSize,total,pageTotal){
		super(pageNo,pageSize,total)
		this.pageTotal = pageTotal
	}
	getTotalPage(){
		return this.pageTotal || super.getTotalPage()   //重写getTotalPage方法
	}
}
const contentPage = new PageUtil(1,10,100)   //实例化2个pageUtil对象
contentPage.getTotalPage()
console.log(contentPage.currentPage)
contentPage.nextPage()
console.log(contentPage.currentPage)
const dialogPage = new DialogPage(1,10,100,10)
console.log(dialogPage.currentPage)
dialogPage.getTotalPage()

实现一个类具有Push,PoP功能

class Myarray {
       constructor(arr) {
       this.arr = arr;
   }
   myPop() {
       if (this.arr.length === 0) return undefined;
       return Number(this.arr.splice(this.arr.length - 1, 1))
   }
   myPush() {
       let _this = this;
       Array.from(arguments, el => _this.arr.splice(_this.arr.length, 0, el))
       return this.arr.length;
   }
}
let arr = Array.of(1, 5, 6, 7, 8)
let myArray = new Myarray(arr);
console.log(myArray.myPop(), arr)
console.log(myArray.myPush(null), arr)

免责声明:文章转载自《ES6-10笔记(class类)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【Unity优化】内存优化OpenEuler gcc生成32位程序下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

前端经典面试题解密:JS的new关键字都干了什么?

前言 new关键字在实例化获取对象时都做了什么?是一道经常出现在前端面试时的问题。如果只是简单的了解new关键字是实例化构造函数获取对象,是万万不能够的。更深入的层级发生了什么呢?同时面试官想从这道题里面考察什么呢?下面胡哥为各位小伙伴一一来解密。 一、new关键字 new关键字的作用:通过new关键字实例化构造函数,获取对象。说一千道一万,不如来段代码看...

Js基础知识4-函数的三种创建、四种调用(及关于new function()的解释)

在js中,函数本身属于对象的一种,因此可以定义、赋值,作为对象的属性或者成为其他函数的参数。函数名只是函数这个对象类的引用。 函数定义 1 //函数的三种创建方法(定义方式) 2 function one(){ //函数声明语句,不属于任何对象,始终默认为全局对象 3 console.log(...

类型初始值设定项引发异常

-上午打开VS编译程序的时候,突然出现了这个运行时错误“类型初始值设定项引发异常”。昨天还没有这个错误呢,今天就突然出现,搞得我一头雾水。上网搜了一下,发现有很多人遇到了这个问题。经过一番折腾解决了这个问题后,发现很多人都没有意识到其症结所在,于是写这个随笔,给大家点启发,也给自己做个备忘。症状描述: 我的程序需要连接一台MQ服务器(其实就是个台式机,每天...

Java中类加载过程和对象创建过程

类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在。如果有,就直接使用;如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加载非静态内容,再加载静态内容 3, 加载非静态内容:把.class中的所有非静态内容加载到方法区下的非静态区域内 4, 加载静态内容:     4.1、把.c...

c++学习笔记——字面值常量类

字面值常量类:数据成员都是字面值类型的聚合类是字面值常量类。如果一个类不是聚合类,但是它符合一下要求,则它也是个字面值常量类:                       1、数据成员都必须是字面值类型。                       2、类必须至少含有一个constexpr构造函数。                       3、如果一个...

Java高级开发_性能优化的细节

一、核心部分总结: 尽量在合适的场合使用单例【减负提高效率】 尽量避免随意使用静态变量【GC】 尽量重用对象,避免过多过常地创建Java对象【最大限度地重用对象】 尽量使用final修饰符【内联(inline)】 尽量使用局部变量【栈快】 尽量处理好包装类型和基本类型两者的使用场所【堆栈】 慎用synchronized,尽量减小synchronize的方...