具有object属性的新函数实例

时间:2015-07-08 10:45:05

标签: javascript

函数是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

(仅有1个实例不是那么有用的例子)

以下方法不起作用,因为应用new返回一个对象(所以get 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

我一直在根据http://tobyho.com/2010/11/22/javascript-constructors-and/What it the significance of the Javascript constructor property?使用Fetch.prototype.constructor,但必须承认我已开始质疑它是否可行。

你有什么好主意吗?

2 个答案:

答案 0 :(得分:1)

  

如何与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继承的新创建的对象。

答案 1 :(得分:0)

如果您想要某种继承,则可以要求构造函数创建并返回一个新函数,该函数将因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