ES6的class
class Person {
constructor(x, y) {
this.x = x;
this.y = y;
}
show() {
console.log('x---', this.x, 'y----', this.y);
}
}
类型为function
console.log(typeof Person) //function
构造函数的prototype属性,在ES6的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面
console.log(Person === Person.prototype.constructor) //true
console.dir(Person)
let p = new Person(1, 2);
//b是Person 类的实例,它的constructor方法就是Person 类原型的constructor方法
console.log(p.constructor === Person.prototype.constructor); //true
//Object.assign方法可以很方便地一次向类添加多个方法
Object.assign(Person.prototype, {
toString() { console.log('toString') },
toValue() { console.log('toValue') }
})
console.dir(Person);
prototype对象的constructor属性,直接指向“类”的本身,这与ES5的行为是一致的。
console.log(Person === Person.prototype.constructor); //true
console.log('keys', Object.keys(Person.prototype)) //keys只能获取可枚举的
//getOwnPerperty可以获取全部属性
console.log('getOwnPerperty', Object.getOwnPropertyNames(Person.prototype))
//在es5中的prototype上定义的方法是可以枚举的,在class内定义的是不可枚举的
var Person1 = function (x, y) {
//..
};
Person1.prototype.toString = function () {
// ...
};
console.log('keys', Object.keys(Person1.prototype)) //keys只能获取可枚举的
//getOwnPerperty可以获取全部属性
console.log('getOwnPerperty', Object.getOwnPropertyNames(Person1.prototype))
constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象
class Foo {
constructor() {
return Object.create(null); //返回null
}
}
console.log(new Foo() instanceof Foo)// false
类的构造函数,不使用new是没法调用的,会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行
Foo() // TypeError: Class constructor Foo cannot be invoked without 'new'
x和y都是实例对象Person自身的属性(因为定义在this变量上),所以hasOwnProperty方法返回true,而toString是原型对象的属性(因为定义在Person类上),所以hasOwnProperty方法返回false。这些都与ES5的行为保持一致。
console.log(p.hasOwnProperty('x')) // true
console.log(p.hasOwnProperty('y')) // true
console.log(p.hasOwnProperty('show')) // false
console.log(p.__proto__.hasOwnProperty('show')) // true
var p1 = new Person(2, 3);
var p2 = new Person(3, 2);
//p1和p2都是Point的实例,它们的原型都是Point.prototype,所以__proto__属性是相等的。
//这也意味着,可以通过实例的__proto__属性为Class添加方法
console.log(p1.__proto__ === p2.__proto__)
//true
不能想es5的方法一样无论在什么位置定义都可以,class需要先定义才能用
const MyClass = class Me {
getClassName() {
return Me.name;
}
};
//上面代码使用表达式定义了一个类。需要注意的是,这个类的名字是MyClass而不是Me,Me只在Class的内部代码可用,指代当前类。
let my = new MyClass();
console.log(my.getClassName()) // Me
//console.log(Me.name) // ReferenceError: Me is not defined
//立即执行class
let person = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}('旺旺');
person.sayName(); // "张三"
this的指向,类的方法内部如果含有this,它默认指向类的实例。但是,必须非常小心,一旦单独使用该方法,很可能报错
class Logger {
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
//printName(); // TypeError: Cannot read property 'print' of undefined
//解决方法1,在构造方法中绑定this,这样就不会找不到print方法了。
// class Logger {
// constructor() {
//将对象的this绑定到方法中的this上,无论怎么调用都是new的时候的this
// this.printName = this.printName.bind(this);
// }
// // ...
// }
//方法2,使用箭头函数
// class Logger {
// constructor() {
// this.printName = (name = 'there') => {
// this.print(`Hello ${name}`); //this就是指向定义时的this
// };
// }
// // ...
// }
//方法3,使用Proxy,获取方法的时候,自动绑定this。
function selfFun (target) {
//将绑定this后的方法存入weakMap中,如果对象不存在了会自动回收
const cache = new WeakMap();
const handler = {
get (target, key) {
//调用Reflect来执行get操作,获取target的key属性
const value = Reflect.get(target, key);
if (typeof value !== 'function') { //非方法
return value;
}
if (!cache.has(value)) { //方法
cache.set(value, value.bind(target));
}
return cache.get(value);
}
};
const proxy = new Proxy(target, handler);
return proxy;
}
const logger = selfFun (new Logger());