class

2019-02-15  本文已影响0人  撑船的摆渡人

ES6引入class(类)这个概念,通过class关键字可以定义类。该关键字的出现使得其在对象写法上更加清晰,更像是一种面向对象的语言。

class Person { //定义了一个名字为Person的类
    constructor(name, age){ //constructor是一个构造方法,用来接收参数
        this.name = name; //this代表的是实例对象
        this.age = age;
    }
    say(){ //这是一个类的方法,注意千万不要加上function
        return `我叫${this.name},${this.age}岁了`
    }
}
let obj = new Person('andy',18);
console.log(obj.say());

类自身指向的就是构造函数,所以可以认为ES6中的类其实就是构造函数的另外一种写法。

console.log(typeof Person); //function
console.log(Person === Person.prototype.constructor); // true

实际上类的所有方法都定义在类的prototype属性上

class Person { //定义了一个名字为Person的类
    constructor(name, age){ //constructor是一个构造方法,用来接收参数
        this.name = name; //this代表的是实例对象
        this.age = age;
    }
    say(){ //这是一个类的方法,注意千万不要加上function
        return `我叫${this.name},${this.age}岁了`
    }
}
Person.prototype.say = function(){ //定义与类中相同名字的方法。
    return `覆盖类中的方法,我叫${this.name},${this.age}岁了`
}
let obj = new Person('andy',18);
console.log(obj.say());

也可以通过prototype属性对类添加方法

Person.prototype.addFn=function(){
    return "我是通过prototype新增加的方法addFn";
}
let obj = new Person('andy',18);
console.log(obj.addFn());

还可以通过Object.assign方法来为对象动态添加方法

Object.assign(Person.prototype,{
    getName:function(){
        return this.name;
    },
    getAge:function(){
        return this.age;
    }
})
let obj = new Person('andy',18);
console.log(obj.getName());
console.log(obj.getAge());

constructor方法是类的构造函数的默认方法,通过new命令生成对象实例时,自动调用该方法。

class Box {
    constructor(){
        console.log('实例化对象时,自动调用')
    }
}
let obj2 = new Box();

constructor方法如果没有显示定义,会隐式生成一个constructor方法。所以即使你没有添加构造函数,构造函数也是存在的。constructor方法默认返回实例对象this,但是也可以指定constructor方法返回一个全新的对象,让返回的实例对象不是该类的实例。

class Desk {
    constructor(){
        this.haha = '你好'
    }
}
class Body {
    constructor(){
        return new Desk();// 没有用this,直接返回一个全新的对象
    }
}
let obj3 = new Body();
console.log(obj3.haha);

constructor中定义的属性可以称为实例属性(既定义在this对象上),constructor外声明的属性都是定义在原型上的,可以称为原型属性(既定义在class上)。hasOwnProperty()函数用于判断属性是否是实例属性。其结果是一个布尔值,true说明是实例属性,false说不是实例属性。in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。

class Box{
    constructor(num1,num2){
        this.num1 = num1;
        this.num2 = num2;
    }
    sum(){
        return num1 + num2;
    }
}
let box = new Box(12,88);
console.log(box.hasOwnProperty('num1'));
console.log(box.hasOwnProperty('num2'));
console.log(box.hasOwnProperty('sum'));
console.log('num1' in box);
console.log('num2' in box);
console.log('sum' in box);
console.log('say' in box);

类的所有实例共享一个原型对象,他们的原型都是Person.prototype,所以proto属性时相等的

class Person{
    constructor(m,n){
        this.m = m;
        this.n = n;
    }
    sum(){
        return m + n;
    }
}

p1与p2都是Person的实例,它们的proto都指向Person的prototype

let p1 = new Person(1,2);
let p2 = new Person(4,8);
console.log(p1.__proto__,p1.__proto__ === p2.__proto__);

由此,也可以通过proto来为类增加方法。使用实例的proto属性改写原型,会改变Class的原始定义,影响到所有实例,所以不推荐使用!

p1.__proto__.sub = function(){
    return this.n - this.m
}
console.log(p1.sub());
console.log(p2.sub());

class不存在变量提升,所以需要先定义在使用。因为ES6不会把类的声明提升到代码头部,但是ES5存在变量提升,可以先使用,然后在定义。

ES5可以先使用在定义,存在变量提升

new A();
function A(){
    console.log('ES5执行了')
}

ES6不能使用在定义,不存在变量提升,会报错

new B();
class B{
    constructor(){
        console.log('ES6执行时保错,B is not defined')
    }
}
上一篇下一篇

猜你喜欢

热点阅读