在javascript中区分普通函数和构造函数

时间:2013-11-02 21:15:32

标签: javascript node.js oop inheritance ecmascript-5

我正在尝试确定javascript中的函数是简单的,简单的(匿名)函数,还是构造函数(具有原型的函数)。到目前为止,我已经提出了以下功能:

function isPlainFunction(value) {
    var own = Object.getOwnPropertyNames(value.prototype),
        ctorIndex = own.indexOf('constructor');

    if ( ctorIndex !== -1 ) {
        own.splice( ctorIndex, 1);
    }

    if (own.length) {
        return false;
    }

    // walk prototype chain
    var proto = Object.getPrototypeOf(value.prototype);

    if (proto === Object.prototype) {
        return true;
    }

    return isPlainFunction(proto);
}

我只针对ES5,(node.js),但我不确定这是否涵盖了所有边缘情况,或者是否还有一些我没有找到关于此主题的内容。

我(大致)考虑了以下测试用例:

assert.ok( isPlainFunction(function(){}) );

var bar = function(){};
bar.prototype = { get one(){ return 1 } };

assert.equal( isPlainFunction(bar), false );

var foo = function(){};
foo.prototype = Object.create( bar );

assert.equal( isPlainFunction(bar), false );

也就是说,任何具有原型的函数或从非本机类型之一继承原型......

3 个答案:

答案 0 :(得分:2)

如果您要测试的是一个函数是否应该用作构造函数,那么很遗憾,这无法准确确定。

您可以在任何函数上调用new运算符,无论是否以这种方式使用都没有问题。

如果我有这种方法,例如:

function doSomethingWithThisObject(someValue) {
    this.someVariable = someValue;
}

具有以下原型:

doSomethingWithThisObject.prototype = { prototypeVariable : 'I came from prototype' };

我可以通过以下方式使用它:

// Use my function as a constructor:
var obj = new doSomethingWithThisObject('hi there!');
console.log(obj.someVariable); // prints "hi there!"
console.log(obj.prototypeVariable); // prints "I came from prototype"

// Use my function in an object:
var myObject = {
    doSomething : doSomethingWithThisObject
};
myObject.doSomething('hi again!');
console.log(myObject.someVariable); // prints "hi again!"
console.log(myObject.prototypeVariable); // prints "undefined"

// Use my function to change global state:
doSomethingWithThisObject('you owe me ice cream!');
console.log(someVariable); // prints "you owe me ice cream!"
console.log(prototypeVariable); // prints "undefined"

除非在代码中的某处指定了意图,否则无法确定其中一个用例是否正确。

有些人建议使用大写的第一个字母命名构造函数方法,以确定它们应该用作构造函数。如果您根据项目的编码指南决定这个建议,您可以简单地检查函数的名称是否以大写字母开头,这将表示编写该函数的人打算将其用作构造函数。

答案 1 :(得分:0)

正如Ben Barkay所说,任何函数都可以通过 new 关键字成为JS中的构造函数。在幕后所有 new 正在设置函数的上下文 - 你可以通过一个简单的测试看到这个:

function test() {
     console.log(this)
}

test()
    output: Window {top: Window, window: Window…}
new test()
    output: test {}
            test {}

在JS中你需要创建一个构造函数的函数是一个 new 关键字,所有 new 都设置函数的 this 变量。所以任何函数都可以成为构造函数。

区分anon函数更容易:如果它没有名称,则它是匿名的:

//anon:
(function() {
    console.log("I'm anon")
})()

var anon = function() {
    console.log("I, too, am anon")
}

如果您以编程方式需要函数的名称,则可以通过function.name

获取它

答案 2 :(得分:0)

确定某个功能是否没有扩展prototype,例如可以假设它比普通函数更多,以下函数将返回false

   function isPlainFunction(value) {
        if (typeof value !== 'function') {
            return false;
        }

        var own = Object.getOwnPropertyNames(value.prototype);

        if ( own.length >= 2 || ( own.indexOf('constructor') < 0 && own.length >= 1 ) ) {
            return false;
        }

        return Object.getPrototypeOf(value.prototype) === Object.prototype;
    }