ES5-ES6-ES7_class类
传统创建对象模板的方式
JavaScript 语言中,生成实例对象的传统方法是通过构造函数
//JavaScript 语言中,生成实例对象的传统方法是通过构造函数 function Point(x, y) {
this.x = x;
this.y = y;
} Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
}; var p = new Point(1, 2);
console.log(p.toString()); //(1, 2)
ES6创建对象模板的方式Class
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类
基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
ES6 的类,完全可以看作构造函数的另一种写法
//ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类
class Point {
constructor(x, y) { //构造方法,而this关键字则代表实例对象
this.x = x;
this.y = y;
} //toString方法。注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。
// 另外,方法之间不需要逗号分隔,加了会报错
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
} const p = new Point(1,2); //类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行
console.log(p.toString()); //(1, 2) console.log(typeof Point) //function,类的数据类型就是函数,类本身就指向构造函数
console.log(Point === Point.prototype.constructor) // true
constructor 方法
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
//定义了一个空的类Point,JavaScript 引擎会自动为它添加一个空的constructor方法
class Point {
} // 等同于
class Point {
constructor() {}
}
class Foo {
constructor() { //constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象
return Object.create(null); //constructor函数返回一个全新的对象,结果导致实例对象不是Foo类的实例
}
} console.log(new Foo() instanceof Foo); // false
类的实例对象
根据类创建实例对象——类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
} const p = new Point(1,2); //类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行
console.log(p.toString()); //(1, 2)
实例对象属性与原型对象属性——实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
} const p = new Point(1,2);
console.log(p.toString()); //(1, 2) //x和y都是实例对象point自身的属性(因为定义在this变量上)不是原型对象的,所以hasOwnProperty方法返回true
console.log(Point.hasOwnProperty('x')) // true
console.log(Point.hasOwnProperty('y'))// true
console.log(Point.__proto__.hasOwnProperty('y'))// false //toString是原型对象的属性(因为定义在Point类上),不是实例对象的,所以hasOwnProperty方法返回false
console.log(Point.hasOwnProperty('toString')) // false
console.log(Point.__proto__.hasOwnProperty('toString')) // true
通过__proto__属性为‘类’添加方法
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
var p1 = new Point(2,3);
var p2 = new Point(3,2); //p1和p2都是Point的实例,它们的原型都是Point.prototype,所以__proto__属性是相等的
console.log(p1.__proto__ === p2.__proto__) //true //可以通过实例的__proto__属性为“类”添加方法
p1.__proto__.printName = function () {
return 'Oops'
};
console.log(p1.printName()) // "Oops"
console.log(p2.printName()) // "Oops"
var p3 = new Point(4,2);
console.log(p3.printName()) // "Oops" //p1的原型上添加了一个printName方法,由于p1的原型就是p2的原型,因此p2也可以调用这个方法。
// 而且,此后新建的实例p3也可以调用这个方法。
// 这意味着,使用实例的__proto__属性改写原型,必须相当谨慎,不推荐使用,因为这会改变“类”的原始定义,影响到所有实例
立即执行的类的实例
let person = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}('张三'); person.sayName(); // "张三"
使用表达式的形式定义类
const MyClass = class Me {
getClassName() {
return Me.name;
}
}; //使用表达式定义了一个类。需要注意的是,这个类的名字是MyClass而不是Me,Me只在 Class 的内部代码可用,指代当前类 const p = new MyClass();
console.log(p.getClassName()); //Me,Me只在 Class 内部有定义。
变量提升——类不存在变量提升(hoist), ES6 不会把类的声明提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义
//Foo类使用在前,定义在后,这样会报错,
// 因为 ES6 不会把类的声明提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定
new Foo(); // ReferenceError: Foo is not defined
class Foo {}
私有方法
私有方法是常见需求,但 ES6 不提供,只能通过变通方法模拟实现
私有方法模拟实现方式一——在命名上加以区别,方法前面的下划线,表示这是一个只限于内部使用的私有方法。但是,这种命名是不保险的,在类的外部,还是可以调用到这个方法
class Widget {
foo (baz) { // 公有方法
this._bar(baz);
}
_bar(baz) { // 私有方法,_bar方法前面的下划线,表示这是一个只限于内部使用的私有方法
return this.snaf = baz;
}
} const w = new Widget();
console.log(w._bar('fffffff')) //fffffff,这种命名是不保险的,在类的外部,还是可以调用到这个方法
私有方法模拟实现方式二————将私有方法移出模块,因为模块内部的所有方法都是对外可见的
class Widget {
foo (baz) {
bar.call(this, baz);
}
} function bar(baz) {
return this.snaf = baz;
}
//foo是公有方法,内部调用了bar.call(this, baz)。这使得bar实际上成为了当前模块的私有方法
const w = new Widget();
console.log(w.foo('fffff'))
静态方法
静态方法在方法名前面添加一个叫static的修饰符来修饰,那么这个方法就是静态方法,可以直接通过类名来调用,不需要通过创建实例对象来调用
class Foo {
static classMethod () {
return 'hello static'
}
} console.log(Foo.classMethod())// hello static
如果通过实例对象来调用静态方法会报错
class Foo {
static classMethod () {
return 'hello static'
}
}
var f = new Foo()
console.log(f.classMethod())//报错:f.classMethod is not a function
Class的继承
Class 可以通过extends关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象
ES6 的继承机制实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this
如果子类没有定义constructor方法,这个方法会被默认添加,也就是说,不管有没有显式定义,任何一个子类都有constructor方法。
另一个需要注意的地方是,在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
} class ColorPoint extends Point {
constructor(x, y, color) { //this.color = color; //在调用super之前,this是不存在的,所以会报错
super(x, y); // 调用父类的constructor(x, y),
this.color = color;
} toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
} const cp = new ColorPoint(1,2,'red');
console.log(Object.getPrototypeOf(ColorPoint)); //[Function: Point]
console.log(Object.getPrototypeOf(ColorPoint) === Point); //true
通过继承创建的实例对象所属的类的实例——实例对象cp同时是ColorPoint和Point两个类的实例
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
} class ColorPoint extends Point {
constructor(x, y, color) { //this.color = color; //在调用super之前,this是不存在的,所以会报错
super(x, y); // 调用父类的constructor(x, y),
this.color = color;
} toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
} const cp = new ColorPoint(1,2,'red');
console.log(cp instanceof Point); // true
console.log(cp instanceof ColorPoint); // true
Object.getPrototypeOf()——Object.getPrototypeOf方法可以用来从子类上获取父类,可以使用这个方法判断,一个类是否继承了另一个类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
} class ColorPoint extends Point {
constructor(x, y, color) { //this.color = color; //在调用super之前,this是不存在的,所以会报错
super(x, y); // 调用父类的constructor(x, y),
this.color = color;
} toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
} const cp = new ColorPoint(1,2,'red');
console.log(Object.getPrototypeOf(ColorPoint)); //[Function: Point]
console.log(Object.getPrototypeOf(ColorPoint) === Point); //true
super关键字
super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数
super虽然代表了父类的构造函数,但是返回的是子类的实例,即super内部的this指的是子类,因此super()在这里相当于父类.prototype.constructor.call(this)。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
console.log(new.target.name);
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
} class ColorPoint extends Point {
constructor(x, y, color) {
//子类的构造函数之中的super(),代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错
super(x, y); // 调用父类的constructor(x, y),
this.color = color;
} toString() {
//super(); //SyntaxError: 'super' keyword unexpected here
// 作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
} const cp = new ColorPoint(1,2,'red'); //ColorPoint,创建子类对象的时候,this指向的是子类
console.log(cp.toString()) // red (1, 2)
super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类
由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的
如果属性定义在父类的原型对象上,super就可以取到
通过super调用父类的方法时,super会绑定子类的this
class Point {
constructor() {
this.x = 1;
}
toString() {
return '(' + this.x + ')';
}
}
Point.prototype.z = 200; class ColorPoint extends Point {
constructor() {
super();
this.x = 3
} toString() {
// 调用父类的toString(),通过super调用父类的方法时,super会绑定子类的this
return super.toString();
}
}
const cp = new ColorPoint();
console.log(cp.toString()) //(3)
ES5-ES6-ES7_class类的更多相关文章
- [js高手之路] es6系列教程 - new.target属性与es5改造es6的类语法
es5的构造函数前面如果不用new调用,this指向window,对象的属性就得不到值了,所以以前我们都要在构造函数中通过判断this是否使用了new关键字来确保普通的函数调用方式都能让对象复制到属性 ...
- Atitit js版本es5 es6新特性
Atitit js版本es5 es6新特性 Es5( es5 其实就是adobe action script的标准化)1 es6新特性1 Es5( es5 其实就是adobe action scrip ...
- 简述ES5 ES6
很久前的某一天,一位大神问我,你知道ES6相对于ES5有什么改进吗? 我一脸懵逼的反问,那个啥,啥是ES5.ES6啊. 不得不承认与大神之间的差距,回来深思了这个问题,结合以前的知识,算是有了点眉目. ...
- Es6 的类(class)
首先根据es5的类(原型对象)的基本点做参照. 序号 基本点 es5 >es6 1 实例属性(方法) √ √ 2 原型属性(方法) 或 公共属性(方法) √ √ 3 es5的私有变量 或 私有属 ...
- Atitit js es5 es6新特性 attilax总结
Atitit js es5 es6新特性 attilax总结 1.1. JavaScript发展时间轴:1 1.2. 以下是ES6排名前十的最佳特性列表(排名不分先后):1 1.3. Es6 支持情况 ...
- ES6入门——类的概念
1.Class的基本用法 概述 JavaScript语言的传统方式是通过构造函数,定义并生成新对象.这种写法和传统的面向对象语言差异很大,下面是一个例子: function Point(x, y) { ...
- JavaScript es6 class类的理解。
本着互联网的分享精神,在本篇文章我将会把我对JavaScript es6 class类的理解分享给大家. JavaScript 类主要是 JavaScript 现有的基于原型的继承的语法糖. 类语法 ...
- 【转】React Native中ES5 ES6写法对照
很多React Native的初学者都被ES6的问题迷惑:各路大神都建议我们直接学习ES6的语法(class Foo extends React.Component),然而网上搜到的很多教程和例子都是 ...
- ES6 | class类的基本语法总结
类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式.只要你的代码写在类或模块之中,就只有严格模式可用. 考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上 ...
- es6 --- class 类的继承使用
传统的javascript中只有对象,没有类的概念.它是基于原型的面向对象语言.原型对象特点就是将自身的属性共享给新对象.这样的写法相对于其它传统面向对象语言来讲,很有一种独树一帜的感脚!非常容易让人 ...
随机推荐
- echarts地图 禁止高亮显示(转载)
转载来源: https://blog.csdn.net/john1337/article/details/54666759 案例一:在实际应用中希望(没有数据的省会)禁止高亮颜色,解决方案: mapC ...
- Android RecyclerView预览item
参考: Android Tools Attributes listItem 和 Sample Data 的用法 笔记 tools:text TextView可以实现预览,不影响实际的效果 例如: to ...
- Mybatis框架基础支持层——解析器模块(2)
解析器模块,核心类XPathParser /** * 封装了用于xml解析的类XPath.Document和EntityResolver */ public class XPathParser { / ...
- C# 利用ReportViewer生成报表
本文主要是利用微软自带的控件ReportViewer进行报表设计的小例子,仅供学习分享使用,如有不足之处,还请指正. 涉及知识点: ReportViewer :位于Microsoft.Reportin ...
- Last Day in Autodesk
今天是我的最后一天在Autodesk上海了,以后将不再折腾那么大的软件了,还是回到CG开发中捣鼓短小精悍的东西——我还将继续整理开源CG生产工具. Today is my last day in Au ...
- Markdown:常用语法
1.标题 说明:一共可以6级标题,几级几个# 一级标题 #一级标题 2.代码 用前后扩上 Hello World! 3.代码块 用前后扩上 Hello World! 4.加粗 加粗了 **加粗了** ...
- python base64 decode incorrect padding错误解决方法
个人觉得原因应该是不同的语言/base64库编码规则不太统一的问题. python中base64串的长度需为4的整数倍,故对长度不为4整数倍的base64串需要用"='补足 如下代码: da ...
- Linux下图形数据库Neo4j单机安装
Neo4j数据库简介 Neo4j 是一个NoSQL的图形数据库(Graph Database).Neo4j使用图(graph)相关的概念来描述数据模型,把数据保存为图中的节点以及节点之间的关系.很多应 ...
- A problem has been detected and windows has been shut down to prevent damage to your computer.他么啥意思?看这里!【蓝屏】
A problem has been detected and windows has been shut down to prevent damage to your computer. 检测到问 ...
- 最简单的java浏览器
/** * Created by Admin on 2017/3/27. */ import java.awt.BorderLayout; import java.awt.Container; imp ...