具有object属性的函数的新实例

New instance of function with object property

本文关键字:实例 函数 object 属性 具有 新实例      更新时间:2023-09-26

函数是JavaScript中的第一类对象-但是如何与new结合使用呢?

我知道如何创建一个既像函数又像对象的对象

fetch.proxy = '127.0.0.1'
fetch(url)

但是我想弄清楚如何将此与创建new实例相结合,以便我可以按照以下方式做一些事情:

a = new Fetch(host, username) 
a(path1) // fetches username@host/path1
a(path2) // fetches username@host/path2

(对于只有一个实例的例子不是很有用)

下面的方法不起作用,因为应用new返回一个对象(所以得到TypeError: object is not a function)。

var Fetch = function(a, b){
    if ( (this instanceof arguments.callee) ){
        //called as constructor
        this.host = a
        this.username = b;
        this.host = 'localhost'
    } else {
   //called as function
   console.log("Fetching "+this.username+'@'+this.host+a);
    }
};
a = new Fetch('host', 'username') 
a('/path1') // TypeError: object is not a function
a('/path2') // TypeError: object is not a function

我一直在玩Fetch.prototype.constructor基于http://tobyho.com/2010/11/22/javascript-constructors-and/和它的Javascript构造函数属性的意义是什么?但我必须承认,我已经开始怀疑这是否可能。

你有什么好主意吗?

如何与new结合使用?

那样做没有意义。new Foo所做的就是创建一个继承Foo.prototype的新对象。然而,目前不可能从Function.prototype以外的原型继承一些函数,因此使用new Something创建函数没有任何优势。


因为你没有在你的例子中使用prototype,这并不重要。从Fetch返回一个函数:

var Fetch = function(host, username){
  function fetch(path) {
     console.log("Fetching " + fetch.username + '@' + fetch.host + path);
  }
  fetch.username = username;
  fetch.host = host;
  return fetch;
};

现在你可以调用Fetch,或者不调用new **,这没有区别:

var a = Fetch(host, username);
// same as
var a = new Fetch(host, username);

注意,我在上面的例子中将this.username更改为fetch.username。每个函数都有自己的this值,默认情况下引用函数实例本身,所以this.username不能工作。

允许在创建后通过a.username = 'something else';等更改主机或用户名。如果你不想这样做,只需将fetch.username更改为username


**:如果函数显式地返回一个对象,那么new将返回该值,而不是继承Fetch.prototype新创建的对象。

如果你想要某种继承,你可以要求你的构造函数创建并返回一个你将原型化的新函数,这要感谢setProtototypeOf:

const Fetch = function (host, user)
{
  var fetch // new instance of function, relay to model
  
  fetch = function(path) {
    // note we use the closure on instance 'fetch'
    return Fetch.model.apply(fetch, arguments)
  }
  
  // 'setPrototypeOf' is not as borderline as '__proto__',
  // but it has some caveats anyway. Check for example MDN
  // about this.
  Object.setPrototypeOf(fetch, Fetch.model)
  if (host) fetch.host     = host
  if (user) fetch.username = user
  
  return fetch
}
// we name 'model' here; it also works if we 
// say 'prototype' instead.
// It would have been both more meaningful and more confusing at the
// same time, as the prototype would not get used the standard way.
Fetch.model = function (path)
{
  console.log("Fetching " + this.username + '@' + this.host + path)
}
Fetch.model.host     = 'localhost'
Fetch.model.username = 'peter'
var fetch = new Fetch	// 'new' is not needed: can say '= Fetch()'
fetch.host = 'paradise'
fetch('/register')
See console output below