Qual é o protótipo
O tipo de função possui um protótipo de propriedade, que é traduzido diretamente no protótipo. Esta propriedade é um ponteiro, apontando para um objeto, que contém algumas propriedades e métodos, que serão compartilhados por todas as instâncias (objetos) gerados pela função atual.
Com base no que foi dito antes, você pode obter o seguinte código:
function pessoa () {...} pessoa.prototype = {country: 'China', SayName: function () {...}}Primeiro, uma pessoa instância do tipo de função é criada e, em seguida, o protótipo do método da pessoa é um objeto, e a declaração aponta para um objeto. As propriedades e métodos nesse objeto serão compartilhados pela instância gerada pela função atual da pessoa. Isto é, dizer:
pessoa1 = nova pessoa (); pessoa2 = nova pessoa ();
Person1 e Person2 são gerados novamente através de instâncias do tipo de função da pessoa. Ambos têm o país imobiliário comum e o nome do método, porque todos têm um ponteiro (__proto__), apontando diretamente para o objeto apontado pela pessoa.prototipo. No entanto, observe que o ponteiro __proto__ não é padrão. É definido apenas por navegadores como Chrome e Firefox. De fato, essa propriedade não será usada, mas é usada apenas como uma compreensão do protótipo:
Em relação ao uso de protótipos e outros métodos, falaremos sobre isso mais especificamente mais tarde.
Criar um padrão de objeto
Em seguida, vamos dar uma olhada nos métodos e padrões comuns para criar objetos, bem como suas vantagens e desvantagens.
1. Modelo de fábrica
Assim como uma fábrica, o processo de criação de objetos concretos é abstraído e as funções são usadas para encapsular os detalhes da criação de objetos com interfaces específicas. Ao usar funções em vez de um trabalho parcial de repetição, o código é o seguinte:
função createPerson (nome, idade, trabalho) {var o = new Object (); o.name = nome; o.age = idade; O.JOB = Job; O.SayName = function () {alert (this.name); }; retornar o;} var pessoa1 = createPerson ("jiangshui", "22", "engenheiro");Isso cria uma pessoa, e o padrão de fábrica resolve o problema da criação repetida de vários objetos semelhantes, mas não resolve o problema de reconhecimento de objetos. Só que um objeto é simplesmente criado e, não importa se esse objeto é criado a partir de um modelo humano ou um modelo animal, é impossível distinguir o tipo desse objeto.
2. Modo construtor
Crie um construtor personalizado para definir propriedades e métodos de tipos de objetos personalizados.
função pessoa (nome, idade, trabalho) {this.name = name; this.age = idade; this.job = jpb; this.sayName = function () {alert (this.name); };}; var pessoa1 = nova pessoa (...);3. A diferença entre o modo construtor e o modo de fábrica:
Pessoa é um objeto do tipo de função. Após o novo, um objeto continuará sendo gerado. No entanto, como esse objeto recém -gerado é passado na função e atribuído a este ponteiro, o conteúdo passado se torna a propriedade ou método do objeto recém -gerado.
O hábito padrão dos construtores é capitalizado na primeira letra. A execução do código acima passa pelas seguintes etapas:
Nos casos gerados dessa maneira, todos eles contêm um atributo construtor por padrão, apontando para a função do construtor, por exemplo:
alerta (Person1.Constructor == Pessoa);
Portanto, usando o padrão do construtor, existe uma distinção de tipo e sua instância pode ser identificada como um tipo específico.
Além disso, o construtor é uma função comum. Como você deseja feedback para obter um novo objeto, você usa o novo para chamá -lo. Caso contrário, executá -lo diretamente é como uma função normal. Por exemplo, se você executar a pessoa.SayName () acima, o Window.name será exibido porque a função é executada em janela, portanto, este ponto para a janela.
O modo construtor também é falho. Os métodos no modo construtor são recriados em cada instância; portanto, as funções de mesmo nome em instâncias diferentes não são iguais. Por exemplo:
Person1.SayName == PERSON2.SayName; //falso
Ou seja, cada instância do objeto, atributos e métodos gerados pelo construtor são únicos e são copiados. Os atributos são únicos, porque essa é exatamente a diferença entre objetos, mas muitos métodos têm as mesmas funções e código. Se você copiá -los repetidamente muitas vezes, obviamente desperdiçará recursos.
Assim, podemos colocar a função do lado de fora e depois apontar para a função com um ponteiro no construtor. Na instância gerada, o método armazena um ponteiro para uma determinada função, o que significa uma função compartilhada:
função pessoa (nome, idade) {this.name = name; this.age = idade; this.sayName = SayName;} função dizname () {alert (this.name);}No entanto, dessa maneira, essa função se torna uma função global e não está altamente correlacionada com o construtor da pessoa e não possui encapsulamento.
Em seguida, venha ao modo de protótipo.
Modo de protótipo
Uma parte do básico sobre protótipos foi introduzida anteriormente. Simplificando, cada função possui um atributo de protótipo, apontando para um objeto (objeto protótipo) e algumas propriedades ou métodos podem ser colocados nesse objeto. Em seguida, a instância gerada por esta função terá um atributo irregular (__proto__) apontando para o protótipo.
Desse ponto de vista, você deve entender que as propriedades e métodos gerados pelo protótipo são compartilhados por todas as instâncias.
Isso apenas resolve o problema de compartilhar funções no modo construtor acima e nos exemplos. Por exemplo, o seguinte código:
function PERS () {....} Person.prototype.name = "Jiangshui"; Pessoa.prototype.sayName = function () {alert (this.name);}; var pessoa1 = new Person (); PERSON.SAYNAME (); // jiangshuiou
Person.prototype = {construtor: pessoa, nome: "jiangshui", SayName: function () {alert (this.name); }};O segundo método abrange todo o objeto de protótipo; portanto, você precisa especificar manualmente a propriedade do construtor, apontando para a função do construtor; caso contrário, ele apontará para o objeto.
Vamos resolver o relacionamento deles:
Use isprototypeOf () para determinar a relação entre objetos. Por exemplo:
Pessoa.prototype.isprototypeof (Person1);
Quando o código lê uma determinada propriedade de um objeto, uma pesquisa será executada. Comece com o objeto atual e, se não, procure o objeto protótipo apontado pelo ponteiro, sem procurar o construtor. A instância do objeto pode ser acessada, mas não pode substituir o valor do objeto de protótipo. Se um atributo com o mesmo nome que o objeto de protótipo estiver definido na instância, o processo de pesquisa termina na instância sem acessar o objeto de protótipo, portanto o objetivo da sobrescrição será alcançado. Portanto, mesmo que essa propriedade esteja definida como NULL, significa que a propriedade já existe na instância e a propriedade não será cancelada, para que a propriedade correspondente do protótipo possa ser acessada.
Portanto, você precisa usar o operador Excluir para excluir completamente os atributos da instância para que o protótipo possa ser revisado.
O protótipo é dinâmico e quaisquer modificações feitas no objeto do protótipo podem ser refletidas imediatamente na instância. O motivo é a relação de link solta entre a instância e o protótipo. Toda vez que o método de propriedade da instância é chamado, uma consulta será realizada. Se o protótipo mudar, o resultado da consulta também mudará.
Depois de entender o protótipo, também podemos adicionar novos métodos ou atributos ao objeto nativo. Tipos de referência nativos, como objeto, matriz, string, etc. são semelhantes aos construtores acima. Podemos usar o protótipo para expandir seus métodos. Por exemplo:
String.prototype.startswith = function (text) {return this.indexof (text) == 0;}; var msg = "hello world"; msg.startswith ("hello");Este código adiciona um método StartSwith à string de tipo de referência nativa, que deve passar em um parâmetro para verificar se a sequência a ser testada começa com um parâmetro. Devido à natureza dinâmica do protótipo, todas as variáveis do tipo de string obtêm esse método executando -o.
No entanto, esse método não é recomendado. Se você usar muito e demais código, ele levará a dificuldades de manutenção, confusão no código, etc. De um modo geral, um tipo de referência nativo será herdado primeiro e depois criado em um tipo recém -personalizado. Em relação à herança, resumiremos -a mais tarde.
O padrão de protótipo também não é onipotente. Todos os atributos e métodos no protótipo são compartilhados por todas as instâncias, por isso é muito adequado para funções e outras funções, mas para atributos que contêm tipos de referência, alguns conflitos surgirão. Por exemplo:
function pessoa () {} pessoa.prototype = {construtor: pessoa, amigos: ["Greg", "Jack"]}; var pessoa1 = new Person (); var pessoa2 = new pessoa (); pessoa1.friends.push ("Tom"); console.log (Person2.friends);Você verá em console que há um tom extra para os amigos da pessoa2, que não é o que eu quero, mas ao definir seu amigo para a pessoa1, isso afeta a pessoa da instância2.
Portanto, precisamos usá -lo em combinação com padrão de protótipo e padrão de construtor.
Use o modo construtor e o modo de protótipo em combinação
Este é o padrão mais comumente usado. O construtor é usado para definir as propriedades da instância e personalizar pela passagem de parâmetros; O protótipo é usado para definir métodos ou atributos que requerem compartilhamento entre todas as instâncias. Dessa forma, a personalização é alcançada, o compartilhamento é garantido e os problemas são evitados.
função pessoa (nome, idade, trabalho) {this.name = name; this.age = idade; this.Job = Job; this.friends = ["Greg", "Jack"];} Person.prototype = {Construtor: Pessoa, SayName: function () {alert (this.name); }}; var jiangshui = nova pessoa ("jiangshui", "22", "engenheiro");Exemplos de aplicação práticos
Ok, aqui você pode entender qual é o protótipo e como criar objetos, mas quais são os usos deles? De fato, meu trabalho anterior era apenas escrever algum código usando jQuery, e eu não podia usar o encapsulamento e, em seguida, gerar objetos para implementar funções etc. Então, quais são os usos desses?
Esse método de desenvolvimento é usado principalmente para o desenvolvimento modular e de montagem. Por exemplo, a função pop-up que você costuma usar, é claro que pode colar e copiar o código pop-up sempre e modificá-lo e usá-lo no projeto. Uma opção melhor é encapsular abstrivelmente seu código de função pop-up nesse componente, de modo que, quando você precisar usar pop-ups, você só precisa passar os parâmetros para gerar uma instância pop-up e você pode chamá-la.
Objetos de protótipo e cadeias de protótipo
No JavaScript, tudo é um objeto, mas também existem diferenças nos objetos. Pode ser dividido aproximadamente em duas categorias, a saber: objetos comuns (objeto) e objetos de função (função).
De um modo geral, os objetos gerados através da nova função são objetos de função e outros objetos são objetos comuns.
Dê um exemplo:
função f1 () {// TODO} var f2 = function () {// TODO}; var f3 = new function ('x', 'console.log (x)'); var o1 = {}; var o2 = new Object (); var o3 = new F1 (); console.log (typeof f1, // função tipo de f2, // função typeof f3, // função typeof o1, // objeto tipof o2, // objeto tipoof o3 // objeto); >> função objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objeto objetoF1 pertence à declaração de uma função. A maneira mais comum de definir uma função é que F2 é na verdade uma função anônima. Atribua essa função anônima ao F2, que pertence a uma expressão de função. F3 não é comum, mas também é um objeto de função.
A função é um objeto que vem com JS. Quando F1 e F2 forem criados, o JS criará automaticamente esses objetos através da nova função (). Portanto, esses três objetos são criados através da nova função ().
Existem duas maneiras de criar objetos em JavaScript: literais de objeto e novas expressões. A criação de O1 e O2 corresponde apenas a essas duas maneiras. Vamos nos concentrar no O3. Se você usar as idéias de Java e C# para entender, O3 é um objeto de instância de F1 e O3 e F1 são do mesmo tipo. Pelo menos eu pensei assim antes, mas não é ...
Então, como você entende isso? É muito simples. Veja se O3 é gerado através de uma nova função. Obviamente não. Como não é um objeto de função, é um objeto comum.
Após um simples entendimento de objetos de função e objetos comuns, vamos aprender sobre protótipos e cadeias de protótipo em JavaScript:
No JS, sempre que um objeto de função F1 é criado, algumas propriedades são incorporadas ao objeto, incluindo protótipo e __proto__, o protótipo é o protótipo objeto, que registra algumas propriedades e métodos de F1.
Deve -se notar que o protótipo é invisível para F1, ou seja, a F1 não procurará propriedades e métodos no protótipo.
função f () {} f.prototype.foo = "abc"; console.log (f.foo); //indefinidoEntão, qual é a utilidade do protótipo? De fato, a principal função do protótipo é a herança. Nos termos do leigo, as propriedades e métodos definidos no protótipo são deixados para seus "descendentes", para que as subclasses possam acessar totalmente as propriedades e métodos no protótipo.
Para saber como a F1 deixa protótipos para "descendentes", precisamos entender a cadeia de protótipos em JS. Neste momento, o __proto__ em JS entrou no mercado. Esse cara é muito estranho e oculto, para que você geralmente não o veja, mas existe em objetos comuns e objetos de função. Sua função é salvar o protótipo objeto da classe pai. Quando o JS cria um objeto através de uma nova expressão, ele geralmente atribui o protótipo da classe pai ao atributo __proto__ do novo objeto, que forma uma geração de herança ...
função f () {} f.prototype.foo = "abc"; var obj = new f (); console.log (obj.foo); //abcAgora sabemos que __proto__ em OBJ salva o protótipo de f, então o que é salvo em __proto__ no protótipo de F? Veja a seguinte foto:
Como mostrado na figura, o objeto.Protótipo armazenado no __proto__ do f.prototipo, e também há __proto__ no objeto.Protótipo Objeto. E, do resultado da saída, objeto.Prototype .__ Proto__ é nulo, indicando o ender do protótipo do objeto Obj. Como mostrado na figura abaixo:
Depois que o objeto OBJ possui uma cadeia de protótipo, quando o Obj.foo for executado, o OBJ primeiro descobrirá se ele tem o atributo, mas não encontrará seu próprio protótipo. Quando o Foo não pode ser encontrado, o OBJ procurará por sua vez ao longo da cadeia de protótipos ...
No exemplo acima, definimos o atributo foo no protótipo de f, e depois o OBJ encontrará esse atributo na cadeia de protótipo e o executará.