简介
类的由来
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);
这种写法跟传统的面向对象语言(比如 C++ 和 Java)差异很大,为了使对象原型的写法更加清晰、更像面向对象编程的语法,创造了新的class写法。
ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到
上面的代码用 ES6 的class改写:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
类的方法定义位置
构造函数的prototype属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
//类的原型上增加了一个对象{},目前每一个对象都是函数。
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
由于类的方法都定义在prototype对象上面,所以类的新方法可以添加在prototype对象上面。Object.assign()方法可以很方便地一次向类添加多个方法。
class Point {
constructor(){
// ...
}
}
Object.assign(Point.prototype, {
toString(){},
toValue(){}
});
Object.assign(target,source1,source2,...)
该方法主要用于对象的合并,将源对象source的所有可枚举属性合并到目标对象target上,此方法只拷贝源对象的自身属性,不拷贝继承的属性。
constructor 方法
constructor()方法是类的默认方法(构造方法),通过new命令生成对象实例时,自动调用该方法。
class Person {
constructor() {
console.log("我进来啦")
}
}
const dema = new Person() //实例化时浏览器会直接打印‘我进来啦’
一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加。
constructor()方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
类的实例
生成类的实例的写法,与 ES5 完全一样,也是使用new命令。前面说过,如果忘记加上new,像函数那样调用Class(),将会报错。
class Point {
// ...
}
// 报错
var point = Point(2, 3);
// 正确
var point = new Point(2, 3);
类的属性和方法,除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
var point = new Point(2, 3);
point.toString() // (2, 3)
point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true
上面代码中,x和y都是实例对象point自身的属性(因为定义在this对象上),所以hasOwnProperty()方法返回true,而toString()是原型对象的属性(因为定义在Point类上),所以hasOwnProperty()方法返回false。这些都与 ES5 的行为保持一致。
hasOwnProperty**是用来判断一个对象是否有你给出的名称的属性或对象。 **有则返回true,没有返回false,不过需要注意的是,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。
getter和setter
与 ES5 一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
class Person {
constructor() {
console.log("我进来啦")
}
get prop() {
return "哎,我是写死的返回值"
}
set prop(value) {
console.log("谁要修改我!")
}
}
const dema = new Person()
console.log(dema) //Person {}
dema.prop = '修改属性' //谁要修改我!
console.log(dema.prop) //哎,我是写死的返回值
属性表达式
类的属性名,可以采用表达式。
let methodName = 'getArea';
class Square {
constructor(length) {
// ...
}
[methodName]() {
// ...
}
}
上面代码中,Square类的方法名getArea,是从表达式得到的。
静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
父类的静态方法,可以被子类继承。
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
}
Bar.classMethod() // 'hello'
实例属性的新写法
实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层。
class Person {
age = 2
constructor() {
this.name = "222"
}
}
const dema = new Person()
console.log(dema) //{ "age": 2, "name": "222"}
定义在外层,需要用等号。。。。。