没有”浅析“,只是记录一下我遇到的问题,并分析一下
铺垫
在ES6之前定义一个类的原型:
function Obj(name = "") {
// 实例属性
this.name = name;
return this;
}
// 类的静态属性
Obj.prototype.age = 0;
const o = new Obj("sunzehui");
console.log(o.constructor.prototype.age, o.name); // 0 ’sunzehui‘
类的静态属性所有实例共享,类的实例属性每个实例每份单独的。
先说说我的问题,按照我的惯性思维,理所当然的以为,在构造函数里执行的是实例属性,在构造函数外执行的是类的静态属性,那在 class 语法糖里应该也是这样的吧?
class Obj {
age = 0;
constructor(name = "") {
this.name = name;
}
}
const o = new Obj("sunzehui");
console.log(o.constructor.prototype.age, o.name); // undefined sunzehui
实际上,不是这样的。
因为 class 要模拟真正的类,概念上的类应该是 class 只是声明,不会存在内存空间,而是在代码区。
声明 class 的时候,age 仅仅是个声明,所以它在 class 里会放在闭包里等待实例化,之后将这个属性动态定义到实例上。
那它在闭包里还没声明,怎么拿到他?
加个 static 修饰,会挂到类的原型的构造函数上!
这样就拿到了。
为什么会有这个问题?
在使用 bookshelf 时,官网给的文档是用的自己实现的类继承(文档应该是最新的)
// 官方文档的写法
const knex = require('knex')({
client: 'mysql',
connection: process.env.MYSQL_DATABASE_CONNECTION
})
const bookshelf = require('bookshelf')(knex)
const User = bookshelf.Model.extend('User', {
tableName: 'users',
posts() {
return this.hasMany(Posts)
}
})
new User({id: 1}).fetch().then()
我在实际使用的时候,编辑器已经提示 .extend 将要废弃了。那好啊,我直接用 ES6 的 class 语法糖咯。
// 自己改造后的写法
class User extends bookshelf.Model{
tableName = "users";
posts(){
return this.hasMany(Posts)
}
}
哈哈爽翻了,代码提示都有,比那种写法好多了。
高兴没多久,不一会,报错了,在使用orderBy
的时候说 tableName is undefind
。很明显我已经写好了,遂打断点。
获取tableName
那里出了问题,也就是上面所说的问题。
解决方案:
因为 class 语法糖的类属性是在obj.prototype.constructor
里面,我也不能修改人家代码,凑合用吧。
Customer.prototype.tableName = "customers";
11月14号补充
已经找到正确写法了,是看 @types 那个仓库的实例代码看到的。
DefinitelyTyped/bookshelf-tests.ts at master · DefinitelyTyped/DefinitelyTyped (github.com)
// 正确的写法
class User extends bookshelf.Model{
get tableName() { return "users" };
posts(){
return this.hasMany(Posts)
}
}
完美解决!