抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

没有”浅析“,只是记录一下我遇到的问题,并分析一下

铺垫

在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 里会放在闭包里等待实例化,之后将这个属性动态定义到实例上。

image-20211111202449776

那它在闭包里还没声明,怎么拿到他?

加个 static 修饰,会挂到类的原型的构造函数上!

image-20211111202851851

这样就拿到了。

为什么会有这个问题?

在使用 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。很明显我已经写好了,遂打断点。

image-20211111204107635

获取tableName那里出了问题,也就是上面所说的问题。

解决方案:

因为 class 语法糖的类属性是在obj.prototype.constructor里面,我也不能修改人家代码,凑合用吧。

Customer.prototype.tableName = "customers";

image-20211111204618609

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)
  }
}

完美解决!

评论