类的由来
传统方法
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);
es6类Class语法
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
上面代码定义了一个“类”,可以看到里面有一个constructor
方法,这就是构造方法,而this
关键字则代表实例对象。也就是说,ES5
的构造函数Point
,对应 ES6
的Point
类的构造方法。
关于Class
1、
class
是一个关键字,可以定义类,类方法之间不需要逗号份隔开,方法前面不需要加function
2、类里边有一个constructor
构造方法,是类的默认方法,通过new
命令生成对象实例时,自动调用该方法,类中必须有该方法,如果没有显示定义,一个空的constructor
方法会被默认添加
4、constructor
方法默认返回实例对象(this
),也可以指定返回另外一个对象
5、类必须使用new
调用
6、实例的属性除非显示定义在其本身(即定义在this
对象上),否则都是定义在原型上(即class
上)
7、Object.getOwnPropertyNames()
获取对象上实例的属性或方法,不管是否可枚举
8、对象名称.hasOwnProperty()
返回一个布尔值,判断对象是否包含特定的自身(非继承)属性
9、Object.getPrototypeOf()
方法来获取实例对象的原型,然后再来为原型添加方法/属性。
10、Object.assign(对象.prototype,{添加的方法})
方法可以很方便地一次向类添加多个方法
11、类的内部所有定义的方法,都是不可枚举的
//ES6 的类,完全可以看作构造函数的另一种写法。
//类的数据类型就是函数,类本身就指向构造函数。
class Point {
// ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true
类的所有方法都定义在类的prototype
属性上面。
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
在类的实例上面调用方法,其实就是调用原型上的方法。
class B {}
let b = new B();
b.constructor === B.prototype.constructor // true
prototype
对象的constructor
属性,直接指向“类”的本身
class Point {
constructor(){
// ...
}
}
Object.assign(Point.prototype, {
toString(){},
toValue(){}
});
Point.prototype.constructor === Point // true
class Point {
constructor(x, y) {
// ...
}
toString() {
// ...
}
}
Object.keys(Point.prototype)
// []
Object.getOwnPropertyNames(Point.prototype)
// ["constructor","toString"]
toString
方法是Point
类内部定义的方法,它是不可枚举的。这一点与 ES5
的行为不一致。
class parent {
constructor(name,sex) {
this.name = name,
this.sex = sex;
this.active = function () {
return "i am a people";
}
}
Getwho() {
return this.name;
}
Setwho(){
this.name="wyj";
}
}
class son extends parent {
constructor(name,sex){
super(name,sex);
}
toString(){
}
}
son.prototype.hello="hi";
son.prototype.bye=function(){};
var person=new son("wy","girl");
console.log(person);
for(var i in person){
console.log(i);
}
console.log("_______es5");
//父函数
function sum(max,min,method){
this.max=max;
this.min=min;
this.method=method
}
sum.prototype.add=function(){
}
sum.prototype.toString=function(){
}
sum.prototype.total="不可计算";
//子函数
function sub(){};
var s=new sum(2,1,sub);
console.log(s);
for(var i in s){
console.log(i);
}
console.log(Object.keys(son.prototype));
console.log(Object.getOwnPropertyNames(son.prototype));
console.log(Object.keys(sum.prototype));
console.log(Object.getOwnPropertyNames(sum.prototype));
es6写法截图,虽然写了toString(),但是toString是parent上的方法,不可枚举
es5普通构造函数截图,可遍历
通过
Object.keys()
:获得所有实例属性,并仅需可枚举的
Object.getOwnPropertyName()
:获得所有实例属性,无论他是否可枚举
官网案例:
var Point = function (x, y) {
// ...
};
Point.prototype.toString = function() {
// ...
};
//ES5 的写法,toString方法就是可枚举的
Object.keys(Point.prototype)
// ["toString"]
Object.getOwnPropertyNames(Point.prototype)
// ["constructor","toString"]
//定义类
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
的行为保持一致。
与 ES5
一样,类的所有实例共享一个原型对象。
var p1 = new Point(2,3);
var p2 = new Point(3,2);
p1.__proto__ === p2.__proto__
//true
es6实现继承实例
class parent {
constructor(name,sex) {
this.name = name,
this.sex = sex;
this.active = function () {
return "i am a people";
}
}
Getwho() {
return this.name;
}
Setwho(){
this.name="wyj";
}
}
class son extends parent {
constructor(name,sex){
super(name,sex);
}
}
son.prototype.hello="hi";
var person=new son("wy","girl");
console.log(person);
es5与es6继承区别
1、ES5的继承是通过 prototype
或 构造函数
机制来实现。
2、ES5
的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))
ES6
的继承机制实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this
3、ES6通过class关键字定义类,里面有构造方法,类之间通过**extends
** 关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其调用。如果不调用super方法,子类得不到this对象。
super关键字指代父类的实例,父类的this对象