Pergunta

I'been fazendo alguma herança em js, a fim de entendê-la melhor, e eu encontrei algo que me confunde.

Eu sei que quando você chamar uma 'função de construtor' com a nova palavra-chave, você recebe um novo objeto com uma referência ao protótipo que função.

Também sei que, a fim de tornar a herança prototípica você deve substituir o protótipo da função de construtor com uma instância do objeto que você quer ser o 'superclasse'.

Então eu fiz este exemplo bobo para tentar estes conceitos:

function Animal(){}
function Dog(){}

Animal.prototype.run = function(){alert("running...")};

Dog.prototype = new Animal(); 
Dog.prototype.bark = function(){alert("arf!")};

var fido = new Dog();
fido.bark() //ok
fido.run() //ok

console.log(Dog.prototype) // its an 'Object' 
console.log(fido.prototype) // UNDEFINED
console.log(fido.constructor.prototype == Dog.prototype) //this is true

function KillerDog(){};
KillerDog.prototype.deathBite = function(){alert("AAARFFF! *bite*")}

fido.prototype = new KillerDog();

console.log(fido.prototype) // no longer UNDEFINED
fido.deathBite(); // but this doesn't work!

(Isso foi feito no console da Firebug)

1) Por que se todos os novos objetos incluir uma referência à protótipo da função criador, fido.prototype é indefinido?

2) A cadeia de herança [obj] -> [construtor] -> [protótipo] em vez de [obj] -> [protótipo]

3) é a propriedade 'protótipo' do nosso objeto (Fido) já verificado? se assim for ... por que é 'deathBite' indefinido (na última parte)?

Foi útil?

Solução

1) Por que se todos os novos objetos contêm uma referência aos da função criadora protótipo, fido.prototype é indefinida?

Todos os novos objetos fazem manter uma referência ao protótipo que estava presente em seu construtor no momento da construção. No entanto, o nome da propriedade utilizada para armazenar esta referência não é prototype como é na função de construtor em si. Algumas implementações de JavaScript fazer permitir o acesso a esta propriedade 'escondido' através de algum nome da propriedade como __proto__ onde outros não (por exemplo Microsofts).

2) A cadeia de herança [obj] -> [Construtor] -> [protótipo] em vez de [obj] -> [protótipo]

No. Dê uma olhada nisso: -

function Base() {}
Base.prototype.doThis = function() { alert("First"); }

function Base2() {}
Base2.prototype.doThis = function() { alert("Second"); }

function Derived() {}
Derived.prototype = new Base()

var x = new Derived()

Derived.prototype = new Base2()

x.doThis();

Este alertas "Primeiro" não segundo lugar. Se a cadeia de herança foi via o construtor veríamos "Segundo". Quando um objeto é construído a actual referência realizada na propriedade Funções protótipo é transferido para o objeto de referência oculta para o seu protótipo.

3) é a propriedade 'protótipo' do nosso objeto (Fido) já verificado? se então... porque é 'deathBite' indefinido (no última parte)?

A atribuição a um objeto (que não seja uma função) uma propriedade chamada prototype não tem significado especial, como dito anteriormente um objeto não mantém uma referência ao seu protótipo através de um tal nome da propriedade.

Outras dicas

Você não pode mudar protótipo de um objeto uma vez que foi instanciado com new.

No seu exemplo acima, linhas como

fido.prototype = new KillerDog();

simplesmente cria um novo atributo chamado prototype no objeto fido, e conjuntos que atributo para um novo objeto KillerDog. Não é diferente do que

fido.foo = new KillerDog();

Como o código está ...

// Doesn't work because objects can't be changed via their constructors
fido.deathBite();

// Does work, because objects can be changed dynamically, 
// and Javascript won't complain when you use prototype 
//as an object attribute name
fido.prototype.deathBite();

O comportamento especial prototype só se aplica aos construtores em javascript, onde construtores são functions que serão chamados com new.

Resposta por números às suas perguntas:

    propriedade protótipo
  1. O objeto não é chamado prototype. As utilizações comuns [[prototype]] para designá-lo. Firefox torna esta propriedade pública sob o nome de __proto __.
  2. A cadeia de herança é [obj] ? [prototype object]. Sua premissa original ([obj] ? [constructor] ? [prototype]) é incorreta e pode facilmente refutá-la modificando constructor e / ou constructor.prototype, e verificar quais métodos podem ser chamados em seu [obj] -. Você vai descobrir que essas modificações não mudam nada
  3. propriedade prototype em objetos não são verificados e não utilizados. Você pode configurá-lo para o que quiser. JavaScript usa-lo em função de objetos somente durante a construção do objeto.

Para demonstrar a # 3 aqui está o código de Dojo :

dojo.delegate = dojo._delegate = (function(){
  // boodman/crockford delegation w/ cornford optimization
  function TMP(){}
  return function(obj, props){
    TMP.prototype = obj;
    var tmp = new TMP();
    if(props){
      dojo._mixin(tmp, props);
    }
    return tmp; // Object
  }
})();

Como você pode ver ele tira proveito do fato de que prototype é usado apenas em um lugar, reutilizando a mesma função TMP para todos os objetos delegadas com diferentes protótipos. Na verdade prototype é atribuído diretamente antes de invocar a função com new, e vai ser alterado depois que não afetam quaisquer objetos criados.

Você pode encontrar a seqüência criada objeto na minha resposta à entre [[prototype]] e protótipo em JavaScript .

Eu sei que isso já foi respondida, mas, há uma maneira melhor de fazer herança. Chamar um construtor apenas com a finalidade de herança não é desejável. Um dos efeitos indesejáveis ??é.

function Base() {this.a = "A"}
function Child() {this.b = "B"};

Child.prototype = new Base();

propriedade Agora Você adicionou "a" para o protótipo da criança que você não pretendia.

Aqui é o caminho certo (eu não inventei isso, Ext-JS e outros libs usar este)

// This is used to avoid calling a base class's constructor just to setup inheritance.
function SurrogateCtor() {}

/**
 * Sets a contructor to inherit from another constructor
 */
function extend(BaseCtor, DerivedCtor) {
  // Copy the prototype to the surrogate constructor
  SurrogateCtor.prototype = BaseCtor.prototype;
  // this sets up the inheritance chain
  DerivedCtor.prototype = new SurrogateCtor();
  // Fix the constructor property, otherwise it would point to the BaseCtor
  DerivedCtor.prototype.constructor = DerivedCtor;
  // Might as well add a property to the constructor to 
  // allow for simpler calling of base class's method
  DerivedCtor.superclass = BaseCtor;
}

function Base() {
  this.a = "A";
}

Base.prototype.getA = function() {return this.a}

function Derived() {
  Derived.superclass.call(this);  // No need to reference the base class by name
  this.b = "B";
}

extend(Base, Derived);
// Have to set methods on the prototype after the call to extend
// otherwise the prototype is overridden;
Derived.prototype.getB = function(){return this.b};
var obj = new Derived();

Uma forma ainda mais fácil é adicionar um terceiro parâmetro para estender onde você especifica o método da classe derivada de modo que você não tem que ligar para ampliar e, em seguida, adicionar métodos para o protótipo

extend(BaseCtor, DerivedCtor, {
  getB: function() {return this.b}
});

Depois, há muitas outras coisas que você poderia fazer para o açúcar sintático.

blog sobre isso: http: // js -bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

Vale notar que no ECMAScript 5 (ou seja, a versão mais recente da linguagem JavaScript), você pode ter acesso ao interno [[Prototype]] propriedade de uma instância através de Object.getPrototypeOf :

Object.getPrototypeOf(fido) === Dog.prototype
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top