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

How to distinguish HTMLElement from its constructor.prototype?

我正在研究我的 LIPS project(JavaScript 中基于方案的 Lisp),我想添加一种方法来向任何对象添加字符串表示形式。代码如下所示:

NOTE: you can ignore scheme code. At the end there is simplified use case, this is only for context and why I need this.

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

我的解释器认为这是 HTMLElement 的实例,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 是否是给定类型的 instanceof(来自 add-repr! 的 HTMLElement)并且它 return 对原型是正确的。

并抛出 x.tagName 未定义的异常,因为它不是实例而是原型。

为了简化代码(我为上下文添加了方案代码)这是代码:

 document.createElement('div').constructor.prototype instanceof HTMLElement;

它 return 正确,因为原型是 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 但它只是 return HTMLElement 对象(我正在测试的对象)。我需要它适用于任何嵌套原型链,因为它是编程结构,用户可以使用任何东西。

为了检测某个东西是否是原型对象,不管HTMLElement,我建议做

hasOwnProperty(x, "constructor") &&
  typeof x.constructor == "function" &&
  x.constructor.prototype == x

用户尝试计算的表达式的上下文无关紧要,他们不妨尝试直接打印 (. HTMLElement 'prototype)

另外,我建议不要通过 Map 将实例的 "representation" 函数绑定到它的构造函数。您的 add-repr! 应该只在 class 的原型上创建一个 .repr() 方法,使用 Symbol("lips-repr()") 作为 属性 键。