如何将方法添加到 (JSON) 对象的原型
How to add methods to a (JSON) object's prototype?
假设我从服务器收到一些JSON对象,例如Person对象的一些数据:
{firstName: "Bjarne", lastName: "Fisk"}
现在,我想要在这些数据之上使用一些方法,例如用于计算全名:
fullName: function() { return this.firstName + " " + this.lastName; }
这样我就可以
var personData = {firstName: "Bjarne", lastName: "Fisk"};
var person = PROFIT(personData);
person.fullName(); // => "Bjarne Fisk"
我在这里基本上想做的是向对象的原型添加一个方法。fullName()
方法是通用的,因此不应添加到数据对象本身。喜欢。。:
personData.fullName = function() { return this.firstName + " " + this.lastName; }
。会导致大量冗余;并且可以说"污染"了数据对象。
将此类方法添加到简单数据对象的当前最佳实践方法是什么?
编辑:
有点跑题了,但如果上面的问题可以解决,就可以做一些不错的伪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");
}
Person
和 Dog
将添加方法,如果data
对象具有正确的属性。如果不是,则返回 falsy(即数据不匹配/不符合(。
奖励问题:有谁知道使用或启用此功能的库(即使其变得容易(?它已经是一种JavaScript模式了吗?如果是这样,它叫什么;你有详细说明的链接吗?感谢:)
假设你的对象来自某个解析服务器输出以生成对象的 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());
这里还有另一种可能性。 JSON.parse 接受第二个参数,该参数是用于恢复遇到的对象的函数,从叶节点到根节点。 因此,如果您可以根据它们的内在属性识别您的类型,则可以在齐磊函数中构造它们。 下面是一个非常简单的示例:
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
这取决于你能够明确地识别你的类型。 例如,如果有其他类型,甚至是 Person 的子类型,它也具有 firstName 和 lastName 属性,这将不起作用。 但它可能会满足一些需求。
如果您正在处理纯 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; }
然后你需要一种方法将一个普通对象变成一个Person对象,例如,如果你有一个名为mixin
的函数,它只是将所有属性从一个对象复制到另一个对象,你可以这样做:
//example JSON object
var jsonPerson = {firstName: "Bjarne", lastName: "Fisk"};
var person = new Person();
mixin(person, jsonPerson);
这只是解决问题的一种方法,但希望能给你一些想法。
更新:现在Object.assign()
可以在现代浏览器中使用,您可以使用它而不是编写自己的mixin函数。还有一个垫片可以使Object.assign()
在旧浏览器上运行;请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill。
你可能不应该这样做。
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 );
换句话说,您要更改现有对象的原型(又名.class(。从技术上讲,您可以这样做:
var Person = {
function fullName() { return this.firstName + " " + this.lastName; }
};
// that is your PROFIT function body:
personData.__proto__ = Person ;
在那之后,如果你会得到true
personData instanceof Person
使用 new-ish Object.setPrototypeOf((。 (IE11 和所有其他浏览器现在都支持它。
您可以创建一个包含所需方法的类/原型,例如您的 fullName((,然后
Object.setPrototypeOf( personData, Person.prototype );
正如警告(在上面链接的MDN页面上(所暗示的那样,这个函数不能轻易使用,但是当你改变现有对象的原型时,这是有意义的,这就是你似乎所追求的。
我认为使用数据传输方法并不常见,但这似乎是一个好主意。
该项目允许您将函数与数据一起编码,但它不被认为是标准的,当然需要使用相同的库进行解码。
https://github.com/josipk/json-plus
匿名对象没有原型。 为什么不直接拥有这个:
function fullName(obj) {
return obj.firstName + ' ' + obj.lastName;
}
fullName(person);
如果绝对必须使用方法调用而不是函数调用,则始终可以执行类似操作,但使用对象。
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();
无需使用原型即可在准系统对象中绑定自定义方法。
在这里,您有一个优雅的示例,它不会污染您的代码,避免冗余代码
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);
https://jsfiddle.net/bmde6L0r/中提供的示例
- jQuery匹配JSON对象的部分文本
- 如何在Javascript中将JSon对象转换为数组
- 我可以在json对象中添加一个函数吗
- 使用JS将数组转换为json对象
- 如何为json对象中的段发送array[]
- 将JSON对象传递给angular指令
- 更改JSON对象的结构
- 访问JSON对象内部的数组元素
- 在ejs-partial中对JSON对象进行迭代
- 遍历 JSON 对象并检查 URL 是否以某个值结尾
- 访问嵌套JSON对象的键,其中键是动态的
- json对象中缺少对象循环
- 发送json对象或使用express路由呈现视图
- 在play2框架中向json对象添加下拉列表项
- 元素名称上带有短划线 (-) 字符的 Json 对象
- autocomplete不接受源的json对象
- 如何在javascript中创建动态json对象
- 在使用客户端脚本时拾取JSON对象
- 如何通过json对象数组为嵌套对象赋值
- 构造JSON对象