0

在我的 JavaScript 应用程序中,我有几种对象,Query包括DocumentPosting. 文档包含一堆关于文档的元数据(标题、摘要等);一个 Posting 表示某个 Query 在某个级别检索到的某个 Document。同一个 Document 可能会被多个 Query 检索,因此可能有多个 Posting 与之关联。

该应用程序有两个相关视图:一个显示给定查询的所有过帐,另一个显示所有文档。由于用户可以以几乎相同的方式与这两个视图进行交互,我决定通过将 Document 实例作为一个或多个 Posting 实例的原型来使用原型继承。这样,Posting 继承了 Document 的所有元数据,并且只添加了自己的 Query 引用和排名值。奇迹般有效。

除了数据(查询、排名)之外,帖子还带有一些行为。我想排除这种行为,这样我就不会创建数千个相同的方法。在 Document 的情况下,我只是将我的所有功能移动到Document.prototype. 但是在 Postings 的情况下,我不能这样做,因为每个 Postings 都有不同的原型(其各自的文档)。虽然我可以将 Posting 使用的一些方法放入Document.prototype并以这种方式获取它们,但其中一些方法是多态的,需要针对 Document 和 Posting 以不同的方式实现。

我的问题是:如果我在 Posting 中使用原型继承来携带数据,我是否还能以某种方式排除行为,以便我为所有 Posting 实例重用相同的方法函数实例,而不是在每次创建时创建一批新的方法一个新的帖子?

function Document(id, title) {
    this.id = id;
    this.title = title;
}

// Here prototype is used to factor out behavior
Document.prototype.document = function() { return this; }
Document.prototype.toString = function() { return 'Document [' + this.id + ']: "' + this.title + '"'; }


function Posting(query, rank) {
    this.query = query;
    this.rank = rank;

    // Can I move these two definitions out of the Posting instance to avoid
    // creating multiple copies of these functions as I construct 1000s of Postings?
    this.document = function() { return Object.getPrototypeOf(this); }
    this.toString = function() { return this.document().toString() + ' at rank ' + this.rank; }
}

function createPosting(query, document, rank) {
    // here prototype is used to share data
    Posting.prototype = document;
    var posting = new Posting(query, rank);
    return posting;
}

更新

我在上面的代码示例中犯了一个错误:进行继承的正确方法(如下面的评论中所指出的)是首先设置原型:Posting.prototype = document;我认为我的其余问题仍然有效:-)

4

2 回答 2

0

为什么不将函数保存在 Posting 的构造函数之外。

function Document(id, title) {
    this.id = id;
    this.title = title;
}

// Here prototype is used to factor out behavior
Document.prototype.document = function() { return this; }
Document.prototype.toString = function() { return 'Document [' + this.id + ']: "' + this.title + '"'; }

function PostingToString()
{
  return this.document().toString() + ' at rank ' + this.rank;
}
function PostingDocument ()
{
    return Object.getPrototypeOf(this);
}
function Posting(query, rank) {
    this.query = query;
    this.rank = rank;

    this.document = PostingDocument; 
    this.toString = PostingToString;
}


function createPosting(query, document, rank) {
    var posting = new Posting(query, rank);
    // here prototype is used to share data
    posting.prototype = document;
    return posting;
}
于 2013-06-21T18:15:54.030 回答
0

很难在浏览器中测试 Javascript 的内存使用情况......正如 Gene .bind() 的评论中指出的那样,复制了该函数,因此 Parthik Gosar 的解决方案不会节省任何内存。此外,它仍然引用了在大多数浏览器中并未真正作为引用处理的函数。因此,即使没有 bind() 函数,这也会消耗大量内存。

这种方法应该可以节省大量内存......

var staticFcts = {
    'document': {
        'document': function() { return this; },
        'posting': function() { return Object.getPrototypeOf(this); }
    },
    'toString': {
        'document': function() { return 'Document [' + this.id + ']: "' + this.title + '"'; },
        'posting': function() { return this.document().toString() + ' at rank ' + this.rank; }
    }   
};

var myOwnProxy = function(method) {  
    var c = staticFcts[method][this.typeOf].bind(this);
    return c();
}



function Document(id, title) {
    this.id = id;
    this.title = title;
}

Document.prototype.document = function() { var p = myOwnProxy.bind(this,'document');     return p.call(); };
Document.prototype.toString = function() { var p =     myOwnProxy.bind(this,'toString');return p.call(); }; 
Document.prototype.typeOf = 'document'; // default type is 'document', this is necessary
// because there is no way in Javascript to determine the class name.
// Unfortunantely "Proxy" (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)  is not widely supported either.

function Posting(query, rank) {
    this.query = query;
    this.rank = rank;
}

function createPosting(query, document, rank) {
    Posting.prototype = document;
    var posting = new Posting(query, rank);
    posting.typeOf = 'posting'; //overwrite type

    return posting;
}


var docs = [];
var postings= [];

var now = new Date().getTime();

// memory and performance test
for($i=0;$i<100000;$i++) {
 var d = new Document(1,'document1');
 var p = createPosting('query1', d, 1);
    docs.push(d);
    postings.push(p);
}
console.log('needed time', ((new Date().getTime())-now)/1000 + ' sec');

function roughSizeOfObject( object ) {

    var objectList = [];
    var stack = [ object ];
    var bytes = 0;

    while ( stack.length ) {
        var value = stack.pop();

        if ( typeof value === 'boolean' ) {
            bytes += 4;
        }
        else if ( typeof value === 'string' ) {
            bytes += value.length * 2;
        }
        else if ( typeof value === 'number' ) {
            bytes += 8;
        }
        else if
        (
                typeof value === 'object'
            && objectList.indexOf( value ) === -1
        )
        {
            objectList.push( value );

            for( i in value ) {
                stack.push( value[ i ] );
        }
        }
    }
    return bytes;
}   

console.log('memory usage: ', roughSizeOfObject(docs) + roughSizeOfObject(postings));

西蒙

于 2013-06-21T21:45:13.097 回答