js语言中,生成实例对象的传统方法就是通过构造函数: Es6 通过class (类)这个盖面,作为对象的模板,通过class,可以定义类。 新的class写法是一个语法糖,他绝大部分功能,es5都可以 看到,新的class写法智能让对象原型的写法更加清晰,更像面向对象变成语法而已。
- 例子
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);
p.toString();
//"(1,2)"
//改写class
class Point{
constructor(x,y){
this.x=x;
this.y=y;
}
toString () {
return `( ${this.x}, ${this.y} )`;
}
toValue () {
return this.x+this.y;
}
}
var p = new Point(1,2);
p.toString();
//"(1,2)"
p.toValue();
//3
定义了一个Point类,他里面有一个constructor方法,这就是构造方法;而this关键字母代表实例对象,也就是说Es5的构造函数Ponit对应Es6的Point类的构造方法,Point类除了构造方法,还定义了一个toString的方法,定义方法的时候前面不需要加Function这个关键字,直接将函数定义放进去,也不需要都好分隔。 构造函数的prototype属性,在es6的类上继续存在,实际上类的所有方法都定义在类的Prototype属性上面;
- 严格模式 在类和模块的内部默认就是严格模式 不需要指定运行模式
constructor 方法
constructor 方法是类的默认方法,通过new 命令生成实例时,自动调用该方法,一个类必须有constructor方法,如果没有显示定义,会被默认添加。
class A{
}
//等于
class A{
constructor(){
}
}
//定义一个空的类A JavaScript引擎会自动添加一个空的constructor方法
constructor 方法默认的返回实例对象(this);完全可以指定返回另外一个对象。
class A {
constructor(){
return Object.create(null)
}
}
new A() instanceof A
//false
//实例 instanceof 构造函数用来判断是否是构造函数的实例
类的实例对象
生成实例对象的写法,与Es一样都是使用New命令,实例属性除非显示定义在其本身(既定义在this对象上),否则都是定义在原型上既:定义在class上。
class A{
constructor(x,y){
this.x=x
this.y =y
}
toString(){
return `( ${this.x}, ${this.y} )`;
}
}
var B=new A(1,2)
A.toString();
A.hasOwnProperty(x)//true
A.hasOwnProperty(y)//true
A.hasOwnProperty('toString')//true
A.__proto__.hasOwnProperty('toString')//true
xy都是实例对象A自身的属性 定义在this上,所以hasOwnProperty都会返回true 而toString是原型对象的属性,所以hasOwnProperty返回false。 和Es5保持一致。
class表达式
const MyClass =class Me{
getClassName(){
return Me.name
}
}
let inst =new MyClass();
inst .getClassName();
//A
Me.name
//ReferenceError :Me is not defined
Me只有在Class 内部有定义, 如果类的内部没有用到的话可以省略Me改写成:
class MyClass =class {
getClassName(){
return Me.name
}
}
才有class表达式可以直接写出立即执行函数class
let person =new class{
constructor
(name){
this.name =name;
}
sayName(){
console.log(
this.name
)}
}('梅花十三');
person.sayName();
不存在变量提升
new Foo();//ReferenceError
class Foo{};
foo类的使用在前定义在后, 这样会报错,Es6不会吧类的生命提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义
this的指向
类的方法内部如果含有this,他默认指向类的实例,但是必须非常小心,一旦单独使用该方法,可能会报错。
class Logger{
printName(name="three"){
this.print(`hello${name}`)
}
print(text) {
console.log(text);
}
}
const logger =new Logger()
const {printName} =logger;
printName();// TypeError: Cannot read property 'print' of undefined
printName 方法中的this,默认指向Logger类的实例,但是如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境,因为找不到print方法而导致报错。
#####Class 的取值函数(getter)和存值函数(setter) 在类的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为
class MyClass1{
constructor(){
//...
}
get prop(){
return 'get'
}
set prop(value){
console.log('set'+value)
}
}
let inst =new MyClass1();
inst.prop=123;
inst.prop
prop属性有对应的存值函数和取值函数,因此赋值和读取行为都被自定义了。
class 静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果一个方法前面加上static ,就标识该方法不会被实例继承 而是直接通过类来讲。
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo =new Foo();
foo.classMethod()// foo.classMethod is not a function
Foo类的classMethod方法前有static关键字,表明该方法是一个静态方法,可以直接在Foo类上调用;而不是在Foo类的实例上调用如果在实例上 调用静态方法,标识不存在。 如果静态方法包含this关键字,这个this指的是类,而不是实例。
class Foo {
static bar () {
this.baz();
}
static baz () {
console.log('hello');
}
baz () {
console.log('world');
}
}
静态方法bar调用了this.baz,这里的this指的是Foo类,而不是Foo的实例,等同于调用Foo.baz。另外从这个例子还卡伊看出,静态方法可以于非静态方法重名。 父类静态方法可以被子类继承。
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
}
Bar.classMethod() // 'hello
静态方法也可以从super上调用。
Class 的静态属性和实例属性
静态属性是指class本身的属性,既class.propName,而不是定义在实例this上的属性。
class Foo {
}
Foo.prop=1;
Foo.prop
//Foo类定义了一个静态属性prop只有这种写法可行,因为 ES6 明确规定,Class 内部只有静态方法,没有静态属性。
- 类的实例属性
类的实例属性可以用等式,写入类的定义之中。
class MyClass1{
myProp=34;
constructor(){
console.log(this.myProp)
}
}
var myclass= new MyClass1();
myclass
// myProp就是MyClass1的实例属性,在MyClass的实例上可以读取这个属性。
基于# 阮一峰的ES6