如何将方法添加到(JSON)对象的原型?

kor*_*dge 30 javascript json prototype

假设我从服务器收到一些JSON对象,例如Person对象的一些数据:

{firstName: "Bjarne", lastName: "Fisk"}
Run Code Online (Sandbox Code Playgroud)

现在,我希望在这些数据之上有一些方法,例如用于计算fullName:

fullName: function() { return this.firstName + " " + this.lastName; }
Run Code Online (Sandbox Code Playgroud)

这样我就可以

var personData = {firstName: "Bjarne", lastName: "Fisk"};
var person = PROFIT(personData);
person.fullName(); // => "Bjarne Fisk"
Run Code Online (Sandbox Code Playgroud)

我基本上想要在这里做的是向对象的原型添加一个方法.该fullName()方法是通用的,因此不应添加到数据对象本身.喜欢..:

personData.fullName = function() { return this.firstName + " " + this.lastName; }
Run Code Online (Sandbox Code Playgroud)

......会导致很多冗余; 并且可以说是"污染"数据对象.

将此类方法添加到简单数据对象的当前最佳实践方法是什么?

编辑:

略微偏离主题,但如果上面的问题可以解决,那么就可以做一些很好的伪 - pattern matching就像这样:

if ( p = Person(data) ) {
   console.log(p.fullName());
} else if ( d = Dog(data) ) {
   console.log("I'm a dog lol. Hear me bark: "+d.bark());
} else {
   throw new Exception("Shitty object");
}
Run Code Online (Sandbox Code Playgroud)

PersonDog如果data对象具有正确的属性,将添加方法.如果没有,返回falsy(即数据并不能匹配/相符).

奖励问题:有没有人知道使用或启用此功能的库(即使其变得简单)?它已经是一个JavaScript模式?如果是这样,它叫什么; 你有一个详细阐述的链接吗?谢谢 :)

pht*_*ier 22

假设你的Object来自一些解析服务器输出以生成Object的JSON库,它通常在其原型中没有特别的东西; 为不同的服务器响应生成的两个对象将不共享原型链(当然除了Object.prototype;))

如果您控制从JSON创建"Person"的所有位置,您可以反过来做事:创建一个"空"Person对象(在其原型中使用类似fullName的方法),并使用生成的对象扩展它来自JSON(使用$ .extend,_.extend或类似的东西).

var p = { first : "John", last : "Doe"};

function Person(data) {
   _.extend(this, data);
}

Person.prototype.fullName = function() {
   return this.first + " " + this.last;   
}

console.debug(new Person(p).fullName());
Run Code Online (Sandbox Code Playgroud)


Sco*_*yet 9

这里有另一种可能性. JSON.parse接受第二个参数,该参数是用于恢复遇到的对象的函数,从叶节点到根节点.因此,如果您可以根据其内在属性识别您的类型,则可以在reviver函数中构造它们.这是一个非常简单的例子:

var MultiReviver = function(types) {
    // todo: error checking: types must be an array, and each element
    //       must have appropriate `test` and `deserialize` functions
    return function(key, value) {
        var type;
        for (var i = 0; i < types.length; i++) {
            type = types[i];
            if (type.test(value)) {
                return type.deserialize(value);
            }
        }
        return value;
    };
};

var Person = function(first, last) {
    this.firstName = first;
    this.lastName = last;
};
Person.prototype.fullName = function() {
    return this.firstName + " " + this.lastName;
};
Person.prototype.toString = function() {return "Person: " + this.fullName();};
Person.test = function(value) {
    return typeof value.firstName == "string" && 
           typeof value.lastName == "string";
};
Person.deserialize = function(obj) {
    return new Person(obj.firstName, obj.lastName);
};

var Dog = function(breed, name) {
    this.breed = breed;
    this.name = name;
}
Dog.prototype.species = "canine";
Dog.prototype.toString = function() {
    return this.breed + " named " + this.name;
};
Dog.test = function(value) {return value.species === "canine";};
Dog.deserialize = function(obj) {return new Dog(obj.breed, obj.name);};


var reviver = new MultiReviver([Person, Dog]);

var text = '[{"firstName": "John", "lastName": "Doe"},' +
            '{"firstName": "Jane", "lastName": "Doe"},' +
            '{"firstName": "Junior", "lastName": "Doe"},' +
            '{"species": "canine", "breed": "Poodle", "name": "Puzzle"},' +
            '{"species": "canine", "breed": "Wolfhound", "name": "BJ"}]';

var family = JSON.parse(text, reviver)
family.join("\n");

// Person: John Doe
// Person: Jane Doe
// Person: Junior Doe
// Poodle named Puzzle
// Wolfhound named BJ
Run Code Online (Sandbox Code Playgroud)

这取决于您能够明确地识别您的类型.例如,如果有其他类型,甚至是Person的子类型,它也具有firstName和lastName属性,这将不起作用.但它可能涵盖一些需求.


Mat*_*wne 5

如果您正在处理普通的JSON数据,那么每个人对象的原型就是这样Object.prototype.为了使它成为一个具有原型的对象,Person.prototype你首先需要一个Person构造函数和原型(假设你以传统的方式进行Javascript OOP):

function Person() {
    this.firstName = null;
    this.lastName = null;
}
Person.prototype.fullName = function() { return this.firstName + " " + this.lastName; }
Run Code Online (Sandbox Code Playgroud)

然后你需要一种方法将一个普通对象变成一个Person对象,例如,如果你有一个函数调用mixin它只是将所有属性从一个对象复制到另一个对象,你可以这样做:

//example JSON object
var jsonPerson = {firstName: "Bjarne", lastName: "Fisk"};

var person = new Person();
mixin(person, jsonPerson);
Run Code Online (Sandbox Code Playgroud)

这只是解决问题的一种方法,但希望能给你一些想法.


更新:现在Object.assign()可以在现代浏览器中使用,您可以使用它而不是编写自己的mixin函数.还有一个垫片可以Object.assign()在旧浏览器上工作; 请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill.