如何区分 HTMLElement 和它的 constructor.prototype?



我正在做我的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()")作为属性键。

最新更新