Suponha que eu tenha um objeto foo
em meu código JavaScript. foo
é um objeto complexo e é gerado em outro lugar. Como posso mudar o protótipo do foo
objeto?
Minha motivação é definir protótipos apropriados para objetos serializados de .NET para literais JavaScript.
Suponha que eu tenha escrito o seguinte código JavaScript em uma página ASP.NET.
var foo = <%=MyData %>;
Suponha que MyData
seja o resultado de invocar o .NET JavaScriptSerializer
em um Dictionary<string,string>
objeto.
Em tempo de execução, isso se torna o seguinte:
var foo = [{"A":"1","B":"2"},{"X":"7","Y":"8"}];
Como você pode ver, foo
torna-se uma série de objetos. Eu gostaria de poder inicializar foo
com um protótipo apropriado. Eu não deseja modificar a Object.prototype
nem Array.prototype
. Como posso fazer isso?
javascript
function-prototypes
Rio Vivian
fonte
fonte
extend
ou com o Googlegoog.inherit
? Muitos desenvolvedores fornecem maneiras de construir herança antes de chamar onew
construtor idoso - o que é antes de nós recebermosObject.create
e não precisamos nos preocupar com a substituiçãoObject.prototype
.Respostas:
EDITAR fevereiro de 2012: a resposta abaixo não é mais precisa. __proto__ está sendo adicionado ao ECMAScript 6 como "opcional normativo", o que significa que sua implementação não é obrigatória, mas se for, deve seguir o conjunto de regras fornecido. Isso não está resolvido no momento, mas pelo menos fará parte oficialmente da especificação do JavaScript.
Esta questão é muito mais complicada do que parece na superfície, e está além do nível de pagamento da maioria das pessoas no que diz respeito ao conhecimento interno de Javascript.
A
prototype
propriedade de um objeto é usada ao criar novos objetos filho desse objeto. Mudá-lo não reflete no próprio objeto, ao invés disso, é refletido quando esse objeto é usado como um construtor para outros objetos, e não tem nenhuma utilidade na mudança do protótipo de um objeto existente.Os objetos têm uma propriedade interna [[prototype]] que aponta para o protótipo atual. A maneira como funciona é sempre que uma propriedade em um objeto é chamada, ela começa no objeto e então sobe pela cadeia [[protótipo]] até encontrar uma correspondência, ou falha, após o protótipo raiz do objeto. É assim que o Javascript permite a construção e modificação de objetos em tempo de execução; tem um plano para buscar o que precisa.
A
__proto__
propriedade existe em algumas implementações (muitas agora): qualquer implementação do Mozilla, todas as do webkit que eu conheço, algumas outras. Esta propriedade aponta para a propriedade interna [[prototype]] e permite modificação pós-criação em objetos. Todas as propriedades e funções serão instantaneamente alteradas para corresponder ao protótipo devido a essa pesquisa em cadeia.Esse recurso, embora esteja sendo padronizado agora, ainda não é uma parte necessária do JavaScript e, em linguagens que o suportam, tem uma grande probabilidade de derrubar seu código na categoria "não otimizado". Os mecanismos JS têm que fazer o melhor para classificar o código, especialmente o código "quente", que é acessado com frequência, e se você estiver fazendo algo sofisticado como modificar
__proto__
, eles não otimizarão seu código de forma alguma.Esta postagem https://bugzilla.mozilla.org/show_bug.cgi?id=607863 discute especificamente as implementações atuais
__proto__
e as diferenças entre elas. Cada implementação faz isso de maneira diferente, porque é um problema difícil e sem solução. Tudo em Javascript é mutável, exceto a.) A sintaxe b.) Objetos de host (o DOM existe fora do Javascript tecnicamente) e c.)__proto__
. O resto está completamente nas mãos de você e de todos os outros desenvolvedores, então você pode ver por que__proto__
se destaca como um polegar dolorido.Há uma coisa que
__proto__
permite que isso seja impossível de fazer: a designação de um protótipo de objeto em tempo de execução separado de seu construtor. Este é um caso de uso importante e um dos principais motivos pelos quais__proto__
ainda não morreu. É importante o suficiente para que tenha sido um ponto de discussão sério na formulação do Harmony, ou em breve será conhecido como ECMAScript 6. A capacidade de especificar o protótipo de um objeto durante a criação fará parte da próxima versão do Javascript e esta será o sino que indica__proto__
os dias está formalmente contado.No curto prazo, você pode usar
__proto__
se estiver visando navegadores que o suportem (não o IE, e nenhum IE jamais oferecerá). É provável que funcione no webkit e moz pelos próximos 10 anos, pois o ES6 não será finalizado até 2013.Brendan Eich - re: Abordagem de novos métodos de Objeto no ES5 :
fonte
non-writable, configurable
resolveria essas preocupações, forçando o usuário a reconfigurar explicitamente a propriedade. No final, as más práticas estão associadas aos abusos das capacidades de uma linguagem, não das capacidades em si. __Proto__ gravável não é inédito. Existem muitas outras propriedades graváveis não enumeráveis e, embora existam perigos, também existem as melhores práticas. A cabeça de um martelo não deve ser removida simplesmente porque pode ser usada indevidamente para ferir alguém.__proto__
é necessária, porque Object.create produzirá apenas objetos, não funções, por exemplo, nem símbolos, regexes, elementos DOM ou outros objetos hospedeiros. Se você deseja que seus objetos possam ser chamados, ou especiais de outras maneiras, mas ainda assim alterar sua cadeia de protótipo, você está preso sem__proto__
proxies configuráveis ou configuráveis__proto__
preocupação " em JSON". As outras preocupações de Brendan Eich são ridículas. Cadeias de protótipos recursivas ou usando um protótipo com métodos inadequados para o objeto dado são erros do programador, não falhas de linguagem e não devem ser um fator, e além disso podem acontecer com Object.create tanto quanto com livremente configurável__proto__
.__proto__
.ES6 finalmente especifica Object.setPrototypeOf (objeto, protótipo) que já está implementado no Chrome e Firefox.
fonte
Você pode usar
constructor
em uma instância de um objeto para alterar o protótipo de um objeto no local. Eu acredito que é isso que você está pedindo para fazer.Isso significa que se você tem o
foo
que é uma instância deFoo
:Você pode adicionar uma propriedade
bar
a todas as instâncias deFoo
, fazendo o seguinte:Aqui está um violino mostrando a prova de conceito: http://jsfiddle.net/C2cpw/ . Não tenho muita certeza de como os navegadores mais antigos se sairão usando essa abordagem, mas tenho quase certeza de que isso deve funcionar muito bem.
Se sua intenção é misturar funcionalidade em objetos, este snippet deve fazer o trabalho:
fonte
foo.__proto__.bar = 'bar';
Você pode fazer
foo.__proto__ = FooClass.prototype
, AFAIK que é compatível com Firefox, Chrome e Safari. Lembre-se de que a__proto__
propriedade não é padrão e pode ser desativada em algum momento.Documentação: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/proto . Consulte também http://www.mail-archive.com/[email protected]/msg00392.html para obter uma explicação de por que não existe
Object.setPrototypeOf()
e por que__proto__
está obsoleto.fonte
Você pode definir sua função de construtor de proxy e, em seguida, criar uma nova instância e copiar todas as propriedades do objeto original para ele.
Demonstração ao vivo: http://jsfiddle.net/6Xq3P/
O
Custom
construtor representa o novo protótipo, portanto, seuCustom.prototype
objeto contém todas as novas propriedades que você gostaria de usar com seu objeto original.Dentro do
Custom
construtor, você apenas copia todas as propriedades do objeto original para o novo objeto de instância.Este novo objeto de instância contém todas as propriedades do objeto original (elas foram copiadas para ele dentro do construtor), e também todas as novas propriedades definidas dentro
Custom.prototype
(porque o novo objeto é umaCustom
instância).fonte
Você não pode alterar o protótipo de um objeto JavaScript que já foi instanciado em um navegador cruzado. Como outros mencionaram, suas opções incluem:
__proto__
propriedadeNenhum deles é particularmente bom, especialmente se você tiver que percorrer recursivamente um objeto em objetos internos para alterar efetivamente o protótipo inteiro de um elemento.
Solução alternativa para questionar
Vou dar uma olhada mais abstrata na funcionalidade que parece que você deseja.
Basicamente, protótipos / métodos permitem apenas uma maneira de agrupar funções com base em um objeto.
Em vez de escrever
você escreve
A sintaxe acima foi cunhada como OOP por causa da sintaxe object.method (). Algumas das principais vantagens de OOPs sobre a programação funcional tradicional incluem:
obj.replace('needle','replaced')
vs ter que lembrar nomes comostr_replace ( 'foo' , 'bar' , 'subject')
e a localização das diferentes variáveisstring.trim().split().join()
) é potencialmente mais fácil de modificar e escrever do que funções aninhadasjoin(split(trim(string))
Infelizmente em JavaScript (como mostrado acima) você não pode modificar um protótipo já existente. Idealmente acima, você poderia modificar
Object.prototype
apenas para os objetos fornecidos acima, mas, infelizmente, a modificaçãoObject.prototype
poderia quebrar scripts (resultando em colisão e substituição de propriedades).Não há meio termo comumente usado entre esses 2 estilos de programação e nenhuma maneira OOP de organizar funções personalizadas.
O UnlimitJS fornece um meio-termo que permite definir métodos personalizados. Evita:
Usando seu código acima, eu simplesmente criaria um namespace de funções que você pretende chamar no objeto.
Aqui está um exemplo:
Você pode ler mais exemplos aqui UnlimitJS . Basicamente, quando você chama
[Unlimit]()
uma função, permite que a função seja chamada como um método em um objeto. É como um meio-termo entre o OOP e as estradas funcionais.fonte
Você não pode mudar a
[[prototype]]
referência de objetos já construídos, pelo que eu sei. Você poderia alterar a propriedade prototype da função do construtor original, mas, como você já comentou, esse construtor éObject
, e alterar as construções JS principais é uma coisa ruim.Você pode criar um objeto proxy do objeto construído que implementa a funcionalidade adicional de que você precisa. Você também pode fazer um monkeypatch de métodos e comportamentos adicionais atribuindo diretamente ao objeto em questão.
Talvez você consiga o que deseja de outra maneira, se estiver disposto a abordar de um ângulo diferente: O que você precisa fazer para mexer no protótipo?
fonte
__proto__
propriedade. Isso só funcionará em navegadores que suportam a__proto__
notação, que é o Chrome e o Firefox, e está obsoleto . Portanto, em resumo, você pode alterar a configuração[[prototype]]
de um objeto, mas provavelmente não deveria.Se você conhece o protótipo, por que não injetá-lo no código?
Então, uma vez que os dados são serializados, você obtém
agora você só precisa de um construtor que tenha um array como argumento.
fonte
Não há como realmente herdar
Array
ou "subclassificar" isso.O que você pode fazer é o seguinte ( AVISO: FESTERING CODE AHEAD ):
Isso funciona, mas causará certos problemas para qualquer pessoa que cruzar seu caminho (parece um array, mas as coisas darão errado se você tentar manipulá-lo).
Por que você não segue o caminho lógico e adiciona métodos / propriedades diretamente
foo
ou usa um construtor e salva seu array como uma propriedade?fonte
se você quiser criar um protótipo em tempo real, este é um dos caminhos
fonte
fonte
prototype
é estático? Não tenho certeza do que você quer dizer.prototype
é uma propriedade de uma função, não de um objeto.Object.prototype
existe;{}.prototype
não.Object.getPrototypeOf(foo)
para obter o objeto de protótipo do construtor. Você pode modificar as propriedades para modificar o protótipo do objeto. Ele só funciona em navegadores recentes, mas não pode dizer quais.Object.prototype
diretamente porque é mais provável queObject.getPrototypeOf(foo)
isso retorne. Não é muito útil.