es5没有类,只有构造函数。ES6新增了class,用于创建类。本文通过es5来实现es6的class(一个Animal类),让初学者对类的特点及底层原理有更深刻的理解
特点
- 只能通过new来调用,否则会抛出类型错误(类的调用检测)
解决方法:通过构造函数内this指向来判断抛出错误
function Animal () { // 只能通过new来调用
this.name = '熊猫'; // 实例属性
if (!(this instanceof Animal)) {
throw TypeError(`Class constructor An cannot be invoked without 'new'`);
}
}
// Animal(); // 报错,直接调用
let animal = new Animal();
console.log(animal)
- 原型上的属性和方法可被继承,但不可枚举
根据babel实现方式,开发一个defineProperty方法来批量添加
Object.defineProperty()
直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
MDN文档链接地址
// 定义原型属性及方法
function defineProperty (constructor, protoProperties, staticProperties) {
// 有传入需要定义的原型属性和方法
if (Array.isArray(protoProperties)) {
define(constructor.prototype, protoProperties)
}
// 有传入需要定义的静态属性和方法
if (Array.isArray(staticProperties)) {
define(constructor, staticProperties)
}
}
function define (target, protoProperties) {
for(let i = 0; i < protoProperties.length; i++) {
let property = protoProperties[i];
let {key, ...config} = property;
Object.defineProperty(target, key, {
configurable: true,
enumerable: false, // 不可枚举,通过prototype是看不到的
...config
});
}
}
let Animal = (function () {
function ClassModel () {
if (!(this instanceof ClassModel)) {
throw TypeError(`Class constructor An cannot be invoked without 'new'`);
}
}
defineProperty(ClassModel, [
{
key: 'age',
value: 10
}, {
key: 'eat',
value: function () {
console.log('eat');
}
}
], [
{
key: 'chineseName',
value: '佳佳'
}, {
key: 'like',
value: function () {
console.log('吃竹子');
}
}
])
return ClassModel;
})();
let animal = new Animal();
console.log(Animal.prototype) // 检查原型属性与方法是否被枚举出来
console.log(Animal.chineseName); // 静态属性
注意:由于在浏览器中,不可枚举属性只对以下方式有效,所以浏览器中依然可以看到属性被枚举出来,使用node执行
prototype
才会是空对象
- for…in循环
- Object.keys方法
- JSON.stringify方法
推荐vscode安装code runner插件,这样就不需要在外面跑这种代码片段了