0

我试图确定 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 );

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

4

3 回答 3

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"

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

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

于 2013-11-03T12:09:55.620 回答
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;
    }
于 2013-11-20T00:09:41.287 回答
0

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

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 获取

于 2013-11-03T15:44:37.587 回答