ES6类(Class)基本⽤法和静态属性+⽅法详解
ES6 类(Class)基本⽤法和静态属性+⽅法详解
JavaScript语⾔的传统⽅法是通过构造函数,定义并⽣成新对象,prototype 属性使您有能⼒向对象添加属性和⽅法。下⾯是通过传统的⽅式创建和使⽤对象的案例:
//Person.js
function Person(x,y){
this.x = x;
this.y = y;
}
String = function (){
return (this.x + "的年龄是" +this.y+"岁");
}
export {Person};
//index.js
import {Person} from './Person';
let person = new Person('张三',12);
console.String());
1.Class的基本⽤法
ES6引⼊了Class(类)这个概念,作为对象的模板,通过class关键字,可以定义类。基本上,ES6的class可以看作只是⼀个语法糖,它的绝⼤部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像⾯向对象编程的语法⽽已。上⾯的代码⽤ES6的“类”改写,就是下⾯这样。
//Person.js
class Person{
// 构造
constructor(x,y){
this.x = x;
this.y = y;
}
toString(){
return (this.x + "的年龄是" +this.y+"岁");
}
}
export {Person};
//index.js
import {Person} from './Person';
let person = new Person('张三',12);
console.String());
上⾯代码定义了⼀个“类”,可以看到⾥⾯有⼀个constructor⽅法,这就是构造⽅法,⽽this关键字则代表实例对象。也就是说,ES5的构造函数Person,对应ES6的Person类的构造⽅法。Person类除了构造⽅法,还定义了⼀个toString⽅法。注意,定义“类”的⽅法的时候,前⾯不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,⽅法之间不需要逗号分隔,加了会报错。
ES6的类,完全可以看作构造函数的另⼀种写法。
//Person.js
console.log(typeof Person);//function
console.log(Person === structor);//true
上⾯代码表明,类的数据类型就是函数,类本⾝就指向构造函数。
//Person.js
console.log(Person.prototype);//输出的是⼀个对象
构造函数的prototype属性,在ES6的“类”上⾯继续存在。事实上,类的所有⽅法都定义在类的prototype属性上⾯,通过以下⽅式可是覆盖类中的⽅法,当然定义类的时候也可以通过这个⽅式添加⽅法。
//index.js
Person.prototype = {
getName(){
return '张三';
},
getAge(){
return '12';
}
};
在类的实例上⾯调⽤⽅法,其实就是调⽤原型上的⽅法
//index.js
console.structor === structor);//true
Object.assign⽅法可以给对象Person动态的增加⽅法,⽽Person.prototype = {}是覆盖对象的⽅法,或者在初始化的时候添加⽅法。
//index.js
Object.assign(Person.prototype,{
getWidth(){
console.log('12');
},
getHeight(){
console.log('24');
}
});
console.log(Person.prototype);
toString⽅法是Person类内部定义的⽅法,ES6中它是不可枚举的,这⼀点与ES5的⾏为不⼀致,ES5是可以枚举的。
//index.js
//ES5
console.log(Object.keys(Person.prototype));//["toString", "getWidth", "getHeight"]
console.OwnPropertyNames(Person.prototype));//["constructor", "toString", "getWidth", "getHeight"]
//ES6
console.log(Object.keys(Person.prototype));//["getWidth", "getHeight"]
console.OwnPropertyNames(Person.prototype));//["constructor", "toString", "getWidth", "getHeight"]
Object.keys(obj),返回⼀个数组,数组⾥是该obj可被枚举的所有属性。OwnPropertyNames(obj),返回⼀个数组,数组⾥是该obj上所有的实例属性。
在ES6中,类的属性名可以使⽤表达式,具体实现⽅式如下
console.log('输出⽂章的标题1');
}
typeof的用法}
//index.js
import Article from './Article';
//console.log(Article.prototype);
let article = new Article();
constructor⽅法是类的构造函数是默认⽅法,通过new命令⽣成对象实例时,⾃动调⽤该⽅法。⼀个类必须有constructor⽅法,如果没有显式定义,⼀个默认的constructor⽅法会被添加。所以即使你没有添加构造函数,也是有默认的构造函数的。⼀般constructor⽅法默认返回实例对象this,但是也可以指定constructor⽅法返回⼀个全新的对象,让返回的实例对象不是该类的实例。
//ConstructorStu.js
import Article from './Article';
export default class ConstructorStu{
// 构造
constructor() {
console.log('constructor');
return new Article();
}
}
//index.js
import ConstructorStu from './ConstructorStu';
console.log('==111==');
console.log(new ConstructorStu() instanceof ConstructorStu);//false
console.log('==222==');
let cons = new ConstructorStu();
console.log('==333==');
console.log('==444==');
运⾏结果
==111==
constructor
false
==222==
constructor
==333==
==444==
说明:类的构造函数,不使⽤new是没法调⽤的,即使你使⽤实例对象去调⽤也是不⾏的,这是它跟普通构造函数的⼀个主要区别。
实例的属性除⾮显式定义在其本⾝(即定义在this对象上),否则都是定义在原型上(即定义在class上)。hasOwnProperty()函数⽤于指⽰⼀个对象⾃⾝(不包括原型链)是否具有指定名称的属性。如果有,返回true,否则返回false。
this.x = x;
this.y = y;
}
toString(){
return (this.x + "的年龄是" +this.y+"岁");
}
}
let person = new Person('lis',8);
console.String());
console.log(person.hasOwnProperty('x'));//true
console.log(person.hasOwnProperty('y'));//true
console.log(person.hasOwnProperty('toString'));//false
console.log(person.__proto__.hasOwnProperty('toString'));//true
说明:上⾯结果说明对象上有x,y属性,但是没有toString属性。也就是说x,y是定义在this对象上,toString定义在类上。
let person1 = new Person('张三',12);
let person2 = new Person('李四',13);
console.log(person1.__proto__ === person2.__proto__);//true
类的所有实例共享⼀个原型对象,person1和person2都是Person的实例,它们的原型都是Person.prototype,所以
__proto__属性是相等的。这也意味着,可以通过实例的__proto__属性为Class添加⽅法。
let person1 = new Person('张三',12);
let person2 = new Person('李四',13);
person1.__proto__.getH = function (){
return "Height";
};
console.H());
console.H());
上⾯代码在person1的原型上添加了⼀个getH⽅法,由于person1的原型就是person2的原型,因此person2也可以调⽤这个⽅法。⽽且,此后新建的实例person3也可以调⽤这个⽅法。这意味着,使⽤实例的__proto__属性改写原型,必须相当谨慎,不推荐使⽤,因为这会改变Class的原始定义,影响到所有实例。
__proto__参考资料:
class不存在变量提升,需要先定义再使⽤,因为ES6不会把类的声明提升到代码头部,但是ES5就不⼀样,ES5存在变量提升,可以先使⽤,然后再定义。
//正确
new A();
function A(){
}//ES5可以先使⽤再定义,存在变量提升
//错误
new B();
class B{
}//B is not a constructor
//ES6不能先使⽤再定义,不存在变量提升
这个类的名字是Expression⽽不是Expre,Expre只在Class的内部代码可⽤,指代当前类。
//Expression.js
const Expression = class Expre{
static getAge(){
return '12';
}
getClassName(){
return " ClassName1= " +Expre.name + " ClassName2= " +Expression.name;
}
};
let exp = new Expression();
//let exp = new Expre();错误
/
/bundle.js:7935 Uncaught ReferenceError: Expre is not defined
console.ClassName());//ClassName1= Expre ClassName2= Expre
//console.Age());错误
//bundle.js:7935 Uncaught ReferenceError: Expre is not defined
console.Age());
说明:Expre.name和Expression.name返回的都是Expre,返回的都是当前。
如果类的内部没⽤到的话,可以省略Expre,也就是可以写成下⾯的形式
//Expression.js
const MyExpre = class{
getClassName(){
return MyExpre.name;
}
};
let myExpre = new MyExpre();
console.ClassName());//MyExpre
说明:如果省略了class后⾯的那个名字Expre,MyExpre.name返回的就是MyExpre,如果没有省略MyExpre.name返回就是class后⾯的那个名字Expre。
采⽤Class表达式,可以写出⽴即执⾏的Class
//Expression.js
let person = new class{
// 构造
constructor(props) {
this.props = props;
}
getProps(){
return this.props;
}
}('构造函数的参数');
console.Props());//构造函数的参数
私有⽅法是常见需求,但ES6不提供,只能通过变通⽅法模拟实现。⼀种做法是在命名上加以区别,在⽅法前⾯加上_(下划线),表⽰这是⼀个只限于内部使⽤的私有⽅法。但是,这种命名是不保险的,在类的外部,还是可以调⽤到这个⽅法。另⼀种⽅法就是索性将私有⽅法移出模块,因为模块内部的所有⽅法都是对外可见的。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论