我正在做我的LIPS项目(JavaScript中基于Scheme的Lisp(,我想添加一种向任何对象添加字符串表示的方法。代码如下所示:
注意:您可以忽略方案代码。最后是简化的用例,这只是为了上下文以及我为什么需要这个。
(add-repr! HTMLElement (lambda (x)
(let ((tag (--> x.tagName (toLowerCase))))
(string-append "<" tag ">" x.innerHTML "</" tag ">"))))
当我评估时,它工作正常:
(document.createElement "span")
;; or
(document.querySelector ".klas")
但是它在评估代码时有问题:
(let ((div (document.createElement "div")))
(. div 'constructor 'prototype))
我的解释器认为这是 HTML 的实例,JavaScript 代码看起来像这样:
var repr = new Map();
// values in map are lisp lambdas that are JavaScript functions
// keys are constructor functions
...
var fn;
if (repr.has(constructor)) {
fn = repr.get(constructor);
} else {
repr.forEach(function(value, key) {
if (obj instanceof key) {
fn = value;
}
});
}
if (fn) {
if (typeof fn === 'function') {
return fn(obj, quote);
} else {
throw new Error('toString: Invalid repr value');
}
}
我检查 obj 是否是给定类型的实例(来自add-repr!
的 HTMLElement(,并且它为原型返回 true。
并抛出未定义 x.tagName 的异常,因为它不是实例而是原型。
为了简化代码(我为上下文添加了方案代码(,这是代码:
document.createElement('div').constructor.prototype instanceof HTMLElement;
它返回 true,因为原型Object.create(HTMLElement)
。有没有办法检测该值是否实际上是没有该原始值的任何值的原型。
var x = document.createElement('div').constructor.prototype;
// context is lost I can't access original value
// check if x is instanceof HTMLElement, but also it's constructed value and not prototype of any value.
如果你认为你可以检查是否有构造函数值,这个循环对象:
document.createElement('div').constructor.prototype.constructor.prototype.constructor
总结这个问题,我想检测值是否是两者中的任何一个,但不是两者兼而有之:
document.createElement('div')
document.createElement('div').constructor.prototype
我在写这篇文章时想到的想法是这样的:
var x = document.createElement('div').constructor.prototype;
if (x instanceof HTMLElement && x !== x.constructor.prototype) {
// real instance
}
这是正确的方法吗?我也在看Object.getPrototypeOf
但它只是返回HTMLElement
对象(我正在测试的对象(。我需要它适用于任何嵌套的原型链,因为它是编程结构,用户可以使用任何东西。
为了检测某物是否是原型对象,无论HTMLElement
如何,我建议这样做
hasOwnProperty(x, "constructor") &&
typeof x.constructor == "function" &&
x.constructor.prototype == x
用户尝试计算的表达式的上下文无关紧要,他们不妨尝试直接打印(. HTMLElement 'prototype)
。
另外,我建议不要通过Map
将实例的"表示"函数绑定到其构造函数。add-repr!
应该只在类的原型上创建一个.repr()
方法,使用Symbol("lips-repr()")
作为属性键。