如何向(JSON)对象的原型添加方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15054678/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to add methods to a (JSON) object's prototype?
提问by kornfridge
Let's say I receive some JSON object from my server, e.g. some data for a Person object:
假设我从我的服务器接收了一些 JSON 对象,例如 Person 对象的一些数据:
{firstName: "Bjarne", lastName: "Fisk"}
Now, I want some methods on top of those data, e.g. for calculating the fullName:
现在,我想在这些数据之上使用一些方法,例如用于计算 fullName:
fullName: function() { return this.firstName + " " + this.lastName; }
So that I can
这样我就可以
var personData = {firstName: "Bjarne", lastName: "Fisk"};
var person = PROFIT(personData);
person.fullName(); // => "Bjarne Fisk"
What I basically would want to do here, is to add a method to the object's prototype. The fullName()method is general, so should not be added to the data object itself. Like..:
我在这里基本上想做的是向对象的原型添加一个方法。该fullName()方法是通用的,因此不应添加到数据对象本身。喜欢..:
personData.fullName = function() { return this.firstName + " " + this.lastName; }
... would cause a lot of redundancy; and arguably "pollute" the data object.
...会造成大量冗余;并且可以说是“污染”了数据对象。
What is the current best-practice way of adding such methods to a simple data object?
将此类方法添加到简单数据对象的当前最佳实践方法是什么?
EDIT:
编辑:
Slightly off topic, but if the problem above can be solved, it would be possible to do some nice pseudo-pattern matchinglike this:
有点跑题了,但是如果上面的问题可以解决,就可以做一些不错的伪 -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");
}
Personand Dogwill add the methods if the dataobject has the right attributes. If not, return falsy (ie. data does notmatch/conform).
PersonDog如果data对象具有正确的属性,将添加方法。如果没有,返回falsy(即数据并不能匹配/相符)。
BONUS QUESTION:Does anyone know of a library that either uses or enables this (ie makes it easy)? Is it already a javascript pattern? If so, what is it called; and do you have a link that elaborates? Thanks :)
额外问题:有谁知道使用或启用此功能的库(即使其变得容易)?它已经是一个 javascript 模式了吗?如果有,它叫什么;你有详细说明的链接吗?谢谢 :)
采纳答案by phtrivier
Assuming your Object comes from some JSON library that parses the server output to generate an Object, it will not in general have anything particular in its prototype ; and two objects generated for different server responses will not share a prototype chain (besides Object.prototype, of course ;) )
假设您的 Object 来自某个解析服务器输出以生成 Object 的 JSON 库,它通常不会在其原型中包含任何特定内容;并且为不同的服务器响应生成的两个对象不会共享一个原型链(当然,除了 Object.prototype ;))
If you control all the places where a "Person" is created from JSON, you could do things the other way round : create an "empty" Person object (with a method like fullName in its prototype), and extend it with the object generated from the JSON (using $.extend, _.extend, or something similar).
如果您控制从 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());
回答by Scott Sauyet
There is another possibility here. JSON.parseaccepts a second parameter, which is a function used to revive the objects encountered, from the leaf nodes out to the root node. So if you can recognize your types based on their intrinsic properties, you can construct them in a reviver function. Here's a very simple example of doing so:
这里还有另一种可能。 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
This depends on you being able to unambiguously recognizing your types. For instance, if there were some other type, even a subtype of Person, which also had firstName and lastName properties, this would not work. But it might cover some needs.
这取决于您是否能够明确识别您的类型。例如,如果有一些其他类型,甚至是 Person 的子类型,它也有 firstName 和 lastName 属性,这将不起作用。但它可能会满足一些需求。
回答by Matt Browne
If you're dealing with plain JSON data then the prototype of each person object would simply be Object.prototype. In order to make it into an object with a prototype of Person.prototypeyou'd first of all need a Personconstructor and prototype (assuming you're doing Javascript OOP in the traditional way):
如果您正在处理纯 JSON 数据,那么每个 person 对象的原型就是Object.prototype. 为了使其成为具有原型的对象,Person.prototype您首先需要一个Person构造函数和原型(假设您以传统方式执行 Javascript OOP):
function Person() {
this.firstName = null;
this.lastName = null;
}
Person.prototype.fullName = function() { return this.firstName + " " + this.lastName; }
Then you'd need a way to turn a plain object into a Person object, e.g. if you had a function called mixinwhich simply copied all properties from one object to another, you could do this:
然后,您需要一种方法将普通对象转换为 Person 对象,例如,如果您调用了一个mixin将所有属性从一个对象复制到另一个对象的函数,您可以这样做:
//example JSON object
var jsonPerson = {firstName: "Bjarne", lastName: "Fisk"};
var person = new Person();
mixin(person, jsonPerson);
This is just one way of solving the problem but should hopefully give you some ideas.
这只是解决问题的一种方法,但希望能给你一些想法。
Update: Now that Object.assign()is available in modern browsers, you could use that instead of writing your own mixin function. There's also a shim to make Object.assign()work on older browsers; see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill.
更新:现在Object.assign()可以在现代浏览器中使用,您可以使用它而不是编写自己的 mixin 函数。还有一个 shim 可以Object.assign()在旧浏览器上工作;请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill。
回答by Ma?l Nison
You should probably not do this.
你可能不应该这样做。
JSON allows you to serialize a state, not a type. So in your use case, you should do something like this :
JSON 允许您序列化状态,而不是类型。因此,在您的用例中,您应该执行以下操作:
var Person = function ( data ) {
if ( data ) {
this.firstName = data.firstName;
this.lastName = data.lastName;
}
};
Person.prototype.fullName = function ( ) {
return this.firstName + ' ' + this.lastName;
};
//
var input = '{"firstName":"john", "lastName":"Doe"}';
var myData = JSON.parse( input );
var person = new Person( myData );
回答by c-smile
In other words you want to change prototype (a.k.a. class) of existing object. Technically you can do it this way:
换句话说,您想更改现有对象的原型(又名类)。从技术上讲,您可以这样做:
var Person = {
function fullName() { return this.firstName + " " + this.lastName; }
};
// that is your PROFIT function body:
personData.__proto__ = Person ;
After that if you will get trueon personData instanceof Person
在那之后,如果你true继续personData instanceof Person
回答by Tom
Use the new-ish Object.setPrototypeOf(). (It is supported by IE11 and all the other browsers now.)
使用新的Object.setPrototypeOf()。(现在 IE11 和所有其他浏览器都支持它。)
You could create a class/prototype that included the methods you want, such as your fullName(), and then
你可以创建一个包含你想要的方法的类/原型,比如你的 fullName(),然后
Object.setPrototypeOf( personData, Person.prototype );
As the warning (on MDN page linked above) suggests, this function is not to be used lightly, but that makes sense when you are changing the prototype of an existing object, and that is what you seem to be after.
正如警告(在上面链接的 MDN 页面上)所暗示的那样,不要轻易使用此功能,但是当您更改现有对象的原型时这是有意义的,这就是您所追求的。
回答by Juan Lago
You don't need to use prototypes in order to bind a custom method in your barebone object.
您不需要使用原型来绑定准系统对象中的自定义方法。
Here you have an elegant example that don't pollute your code avoiding redundant code
在这里你有一个优雅的例子,它不会污染你的代码,避免冗余代码
var myobj = {
title: 'example',
assets:
{
resources: ['zero', 'one', 'two']
}
}
var myfunc = function(index)
{
console.log(this.resources[index]);
}
myobj.assets.giveme = myfunc
myobj.assets.giveme(1);
Example available in https://jsfiddle.net/bmde6L0r/
回答by Explosion Pills
Anonymous objects don't have a prototype. Why not just have this:
匿名对象没有原型。为什么不只有这个:
function fullName(obj) {
return obj.firstName + ' ' + obj.lastName;
}
fullName(person);
If you absolutely must use a method call instead of a function call, you can always do something similar, but with an object.
如果你绝对必须使用方法调用而不是函数调用,你总是可以做类似的事情,但使用对象。
var Person = function (person) { this.person = person; }
Person.prototype.fullName = function () {
return this.person.firstName + ' ' + this.person.lastName;
}
var person = new Person(personData);
person.fullName();
回答by Billy Moon
I don't think it is common to transport methods with data, but it seems like a great idea.
我认为使用数据传输方法并不常见,但这似乎是一个好主意。
This project allows you to encode the functions along with your data, but it is not considered standard, and requires decoding with the same library of course.
该项目允许您将函数与数据一起编码,但它不被视为标准,当然需要使用相同的库进行解码。
https://github.com/josipk/json-plus

