【问题标题】:What would be the equivalent of `instanceof` when using functional inheritance?使用函数继承时,“instanceof”的等价物是什么?
【发布时间】:2016-02-14 18:41:33
【问题描述】:

在 JavaScript 中,有一种实现继承的模式,称为“函数继承”,在 Crockfords “JavaScript:优秀部分”的第 5 章中进行了描述。

与使用伪经典模式相比,该模式的一个缺点是我们失去了使用instanceof 运算符区分类型的能力。

有什么方法可以达到同样的目标吗?我们怎么知道两个对象在某种程度上是相关的,因为它们是相同的父/基“类型”?

此外,即使它们是同一类型的后代,我们如何判断它们本身是不同的类型?

我不知道不能使用instanceof是不是一个很大的损失,但看起来不像。

备注

对 Crockford 的解释不熟悉的可以看一个例子:JSFiddle,取自here

【问题讨论】:

  • 不是每个人都读过那本书。请准确解释“功能继承”是什么。您以哪种方式“失去了使用 instanceof 运算符区分类型的能力”?

标签: javascript inheritance functional-programming instanceof


【解决方案1】:

instanceof 运算符并不特殊。您可以按照Mozilla Developer Network 中的说明自行实施。有关详细信息,请参阅以下问题的已接受答案:

JavaScript inheritance and the constructor property

下面是 instanceof 运算符在 JavaScript 中的实现方式:

function instanceOf(object, constructor) {
    while (object != null) {
        if (object == constructor.prototype) { //object is instanceof constructor
            return true;
        } else if (typeof object == 'xml') { //workaround for XML objects
            return constructor.prototype == XML.prototype;
        }
        object = object.__proto__; //traverse the prototype chain
    }
    return false; //object is not instanceof constructor
}

想要实现instanceOf 的功能继承?这也很容易做到:

var object = child({ name: "a functional object" });

alert(object.instanceOf(child)); // true
alert(object.instanceOf(base));  // true
alert(object.sayHello());        // Hello, I'm a functional object

function base(spec) {
    var that = {};
    that.name = spec.name;
    that.constructors = [base];
    that.instanceOf = instanceOf;
    return that;
}

function child(spec) {
    var that = base(spec);
    that.sayHello = sayHello;
    that.constructors.push(child);
    return that;

    function sayHello() {
        return "Hello, I'm " + this.name;
    }
}

function instanceOf(constructor) {
     return this.constructors.indexOf(constructor) >= 0;
}

当然,在真正的函数式编程中根本不需要使用instanceof

【讨论】:

  • 您能否详细说明为什么在函数式编程中不需要instanceof?我知道有类型化和非类型化的实现。有什么理由我们永远不需要知道变量的类型?
  • @pgpb.padilla instanceof 运算符在运行时检查值的类型,允许您根据值的类型执行不同的操作。在函数式编程中,sum type 用于相同目的。但是,它是在编译时而不是运行时检查的。例如,如果您想编写一个根据您是否给它一个 CatDog 来执行不同操作的函数,那么参数的类型将是 Either Cat Dog,它的值将是 Left someCat 或 @ 987654338@。那有意义吗?希望对您有所帮助。
  • 我真的不太了解 Haskell 或 sum 类型,但 Ben'sthis question 的评论对我来说很有意义。基本上他说,多态性的全部意义在于让 Cat 和 Dog 以完全相同的方式处理,因此必须检查它们的类型将失去重点。
【解决方案2】:

所以想象一下我们有这些:

mammal { giveBirth }
reptile { layEgg }
cat : mammal { purr, playWithChildren }
dog : mammal { bark }
lion : mammal { purr }

cat继承mammal并实现purr()等...)

现在假设您有一系列动物。

我认为您要问的是我们如何判断 animals[0] 是否为 cat

想知道animals[0] 是否是cat 的愿望来自于我们知道猫可以做某些事情的事实。而不是知道animals[0] 是否是cat,我们真正想知道的是animals[0] 咕噜声。也许animals[0].purr !== undefined 比知道它是否是cat 更准确。这确实意味着我们需要检查每个功能,而不是我们知道实现多个功能的猫的容器概念,但它使实现更加健壮和面向未来(考虑我们是否只关心咕噜声和狮子被添加到后面的动物种类)。

至于关于继承的问题,我建议我们不需要知道动物是否是mammal,我们需要知道它们是否giveBirth。这将再次确保我们的实现更具未来性,因此当我们稍后添加 marsupial 时,我们所有关于分娩而不是产卵的逻辑仍然存在。

【讨论】:

    【解决方案3】:

    在对象中存储一个父对象,然后

    if (obj1.parentObject == obj2.parentObject) {//Do your things}
    

    【讨论】:

    • 看看小提琴链接,这种方法不起作用,因为对父母的引用不同。父级只是代表相同类型的父级,不一定是相同的对象。
    【解决方案4】:

    虽然inctanceof 在“功能继承”(“JavaScript:好的部分”)中没有特定的类型和区别。
    它是关于匿名函数之间的交换和关系,这些函数通常会生成具有私有功能的对象。
    这些函数的逻辑层次结构是根据条件偏好设置的。
    函数可以相互调用,扩展“父”对象方法,扩展其功能。
    例如,在“功能继承”中创建一个名为“哺乳动物”的新类型,如下所示:

    var mammal = function (spec) { 
        var that = {}; 
        that.get_.name = function () { 
        return spec.name; 
        }; 
        that.says = function () { 
        return spec.saying || ''; 
        }; 
        return that; 
    }; 
    var myMammal = mammal({name: 'Herb'});
    

    通过一些有条件的协议,我们可以接受它作为父类型(类)。
    现在我们可以创建另一个匿名函数来负责“哺乳动物”类型(类)的子类型(子类)。此函数将调用“父”函数mammal() 来获取具有基本功能的对象:

    var cat = function (spec) { 
        spec.saying = spec.saying || 'meow'; 
        var that = mammal(spec); 
        that.purr = function (n) { 
            var i, s = ''; 
            for (i = 9; i < n; i += 1) { 
                if (s) { 
                   s += 
                } 
                s += 'r'; 
            } 
            return s; 
        }; 
        that.get_name = function () { 
            return that.says() + ' ' + spec.name + ' ' + that.says(); 
        }; 
        return that; 
    }; 
    var myCat = cat({name: 'Henrietta'}); 
    

    【讨论】:

    • 我不知道这个解释是如何解决问题的,你的意思是说问题提出的不正确吗?如果有,请详细说明。
    • 是的,这就是“功能继承”的工作原理,但这如何回答“如何区分类型?这个问题
    • 我已经得出了这样一个概念,即在“功能继承”中没有instanceof 和伪类型的唯一替代方案。关系的实现和条件总会有不同的
    猜你喜欢
    • 2020-05-12
    • 1970-01-01
    • 2016-03-17
    • 1970-01-01
    • 2018-08-21
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    相关资源
    最近更新 更多