Javascript是一种基于对象(object-based)的语言,你遇到的全部东西几乎都是对象。可是,它又不是一种真正的面向对象编程(OOP)语言,由于它的语法中没有class(类)。摘自阮一峰老师语录html
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关键字能够定义一个类node
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{ }
类中的属性,能够直接在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能够定义一个只读属性this
class Animal { constructor (type) { this.type = type } get addr () { return '北京动物园' } }
get/set能够进行一些简单封装,以下prototype
class CustomHTMLElement { constructor (element) { this.element = element } get html () { return this.element.innerHTML } set html (value) { this.element.innerHTML = value } }
get/set还能够模拟设置私有属性,并能够经过get和set对获取属性和读取属性进行一些逻辑判断code
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中继承的实现htm
// 定义父类 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') } }
静态方法是面向对象最经常使用的功能,在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)