ES6-Class
ES6-Class
Class 的基本用法
class Person{
constructor(name,age){
this.name = name;
this.age = age;
//每次实例化都是重复创建,不建议
this.getAge = function(){
return age;
}
}
// 多次实例化共享,也就是原型上的方法
speak(){
console.log('invock speak');
}
}
本质上就是构造函数
typeof Person; //function
//通过原型添加方法,不建议生产环境使用
Person.prototype.run = function(){};
表达式形式
var Person = class {
constructor(){
console.log('初始化'):
}
};
立即执行的类
new (class {
constructor(){
}
})();
实例属性和实例方法
class Person{
name = 'xiaoming';
age = 18;
//每次实例化都会重复创建
getAge = function(){
return this.age;
}
constructor(name,age){
this.name = name;
this.age = age;
}
}
静态属性和静态方法
class Person{
constructor(){
console.log('constructor');
}
//不要这么写,目前只是提案,有兼容性问题
//static version = '1.0.0';
//建议改写为静态方法
static getVersion(){
return '1.0.0';
}
static speak(){
console.log('static speak',this); //这里的this指向Person类对象
}
speak(){
console.log('speak',this); //这里的this指向Person实例
}
}
// 等价,不建议,没有封装性
Person.version = '1.0.0';
Person.speack = function(){
}
私有属性和私有方法
一般情况下,类的属性和方法都是公开的
模拟私有属性和方法
_ 开头表示私有
将私有属性和方法移出类,因为是在同一个作用域内,因此多个实例获取的属性值相等
(function () { let name = ''; class Person { constructor(username) { name = username; } speak() { console.log('speak'); } getName() { return name; } } window.Person = Person; })(); (function () { const p = new Person('Alex'); console.log(p.name); console.log(p.getName()); })();
Class继承
子类继承父类
class Person {
constructor(name, sex) {
this.name = name;
this.sex = sex;
this.say = function () {
console.log('say');
};
}
speak() {
console.log('speak');
}
static speak() {
console.log('static speak');
}
}
class Programmer extends Person {
constructor(name, sex) {
super(name, sex);
}
}
子类构造函数中,this 操作不能放在 super 前面
super作为函数调用
代表父类的构造方法,只能用在子类的构造方法中,用在其他地方就会报错
super 虽然代表了父类的构造方法,但是内部的 this 指向子类的实例
super作为对象使用
在构造方法中使用或一般方法中使用
super 代表父类的原型对象 Person.prototype 所以定义在父类实例上的方法或属性,是无法通过 super 调用的
通过 super 调用父类的方法时,方法内部的 this 指向当前的子类实例
super作为对象使用
在静态方法中使用
指向父类,而不是父类的原型对象
通过 super 调用父类的方法时,方法内部的 this 指向当前的子类,而不是子类的实例
使用 super 的时候,必须显式指定是作为函数还是作为对象使用,否则会报错
类和对象的一些注意事项
构造函数
function Parent(name){
this.name = name;
}
function Children(name,age){
Parent.call(this,name);
this.age = age;
}
Children.prototype.foots = ['fish','rice','chicken'];
Children.prototype.sport = 'football';
let xiaoming = new Children("xiaoming",18);
let xiaohong = new Children("xiaohong",20);
//会被定义到小明这个对象的实例上
xiaoming.sport = 'basketball';
//会被定义到小明这个对象的实例上
xiaoming.foots = ['apple'];
console.log(xiaoming);
console.log(xiaohong);
通过实例对象修改原型上面的属性(属性为基本类型),并不是修改,而是在该实例对象创建了一个同名属性
通过实例对象修改原型上面的引用类型,如果整体修改该引用类型,并不是修改,而是在该实例对象创建了一个同名属性,不改变原型上面的引用类型
通过实例对象修改原型上面的引用类型,如果修改该引用类型(也称对象,每一个对象都是键值对的组合)的属性,会修改原型上面的引用类型
Class
class Father {
constructor(name){
this.name = name;
}
}
class Son extends Father{
sex = 'men';
constructor(name,age){
super(name);
this.age = age;
this.sayHi = function(){
console.log('hi');
}
// 可以通过绑定作用域解决方法被单独提取时,this指向问题
this.sayThis = this.sayThis.bind(this);
}
sayThis(){
console.log(this);
}
}
Son.prototype.name = "小红";
let son = new Son('小明',18);
console.log(son);
console.log(son.__proto__.constructor === Son);
const { sayThis } = son;
sayThis();
实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层
而class中定义的方法都是实例对象原型链上的方法
不管是不是class的方式,实例对象要想实现原型属性的话,必须通过prototype的形式赋值才行
上面代码中,sayThis方法中的this,默认指向Son类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境(由于 class 内部是严格模式,所以 this 实际指向的是undefined),从而导致找不到sayThis方法而报错。