Atributos de objeto em js-configurável, gravável, etc. (atributos de dados e atributos de acessador)

Outras notas relacionadas incluem o seguinte:

1. Tipo de atributo

Depois de usar literais de objeto ou construtores para instanciar objetos e adicionar propriedades e métodos a eles, essas propriedades têm alguns valores característicos quando são criadas, e JavaScript define o comportamento dessas propriedades por meio desses valores característicos . Os atributos no objeto podem ser divididos em duas categorias, ou seja, atributos de dados e atributos de acessador . As características desses dois tipos de atributos são um tanto diferentes.

Atributos de dados

O atributo de dados contém a localização de um valor de dados. Os valores podem ser lidos e escritos nesta posição. Este tipo de atributo possui 4 características que descrevem seu comportamento .

  • [[ Value ]]: Contém o valor dos dados deste atributo. Ao ler um atributo, leia a partir deste local; ao escrever um atributo, salve o novo valor neste local . O valor deste recurso é indefinido por padrão.
  • [[ Gravável ]]: Indica se o valor do atributo pode ser modificado, ou seja, se o valor é gravável ou somente leitura .
  • [[ Enumaerable ]]: se o atributo de destino pode ser enumerado (percorrido) .
  • [[ Configurável ]]: Indica se o atributo pode ser excluído por meio de exclusão , as características do atributo podem ser modificadas ou o atributo pode ser modificado como um atributo de acessador.

Quer seja um novo construtor para instanciar um objeto ou um objeto literalmente cria um objeto e adiciona propriedades a ele, as características [[Value]] dessas propriedades são definidas para o valor da propriedade e as alterações em seu valor refletirão todos Este recurso. E os valores das outras três propriedades do atributo serão verdadeiros por padrão .

Se precisar modificar as propriedades padrão de uma propriedade, você deve usar o método Object.defineProperty () do ES5 . Ele pode definir novos atributos e definir suas características ou alterar as características originais dos atributos . O uso é o seguinte

// 三个参数均为必需参数 
Object.defineProperty(obj, prop, attributeDesc);
  • obj: o objeto onde o atributo está localizado (objeto de destino)
  • prop: o nome da propriedade nova ou modificada definida
  • attributeDesc: objeto de descrição do atributo

Existem dois pontos principais a serem observados ao usar este método para criar ou modificar as propriedades do objeto:

  1. Se os atributos configuráveis, enumeráveis ​​e graváveis ​​do atributo não forem especificados ao criar um atributo, os valores padrão serão todos falsos.
  2. Depois que o atributo configurável de um atributo é definido como falso, ele não é configurável e o atributo não pode ser alterado de volta para configurável. Depois disso, chamar o método Object.defineProperty () para modificar recursos diferentes do recurso gravável causará um erro. (Programação avançada em JavaScript)
    // uname 属性的可配置性、可枚举性、可写性默认都为 true
    var obj = {
    
    
        uname: '扬尘'
    };
    // 更改 value 和 writable 特性
    Object.defineProperty(obj, 'uname', {
    
    
        value: 'TKOP_',
        writable: false
    });
    console.log(obj.uname); // ->'TKOP_'
    obj.uname = '试试你能改不?';
    console.log(obj.uname); // ->'TKOP_'
    // 测试uname的可枚举性
    console.log(Object.keys(obj)); // ->['uname']
    Object.defineProperty(obj, 'uname', {
    
    
        enumerable: false
    });
    console.log(Object.keys(obj)); // ->[]

    // age 属性的可枚举性、可写性默认都是 false 。可配置性为true
    Object.defineProperty(obj, 'age', {
    
    
        value: 23,
        configurable: true
    });
    console.log(Object.keys(obj)); // ->[]
    obj.age = 18;
    console.log(obj.age); // ->23 回不去的18岁

A descrição acima é a demonstração do código do primeiro ponto e, em seguida, do segundo ponto. Pode ser um pouco complicado, o processo de demonstração é complicado e o código geral é copiado. O resumo pessoal das características ao usar este método para configurar essas quatro características novamente após as propriedades serem definidas como não configuráveis ​​é o seguinte :

  • O recurso gravável só pode ser alterado de verdadeiro para falso novamente, mas não de falso para verdadeiro , o que é diferente da declaração de "Programação avançada de JavaScript".
  • Os recursos configuráveis ​​e enumeráveis ​​podem ser definidos com um valor constante novamente sem relatar um erro, o que não tem significado prático . Mas se quiser alterar esses dois recursos, você receberá um erro.
  • Se um erro é relatado quando a propriedade do valor muda novamente depende da propriedade gravável . Se gravável for verdadeiro, nenhum erro será relatado quando o atributo de valor for alterado para qualquer valor. Se gravável for falso, o mesmo recurso de valor só pode definir o valor inalterado novamente sem relatar um erro, o que não tem significado prático . Mas se você quiser alterar seu valor, um erro será relatado.

Se o resumo estiver errado, deixe uma mensagem na área de comentários.

      var obj = {
    
    
        status: '1'
    };
    Object.defineProperty(obj, 'status', {
    
    
        value: '2',
        configurable: false,
        // enumerable: false,
    });
    obj.status = '2__';
    console.log(obj.status); // ->'2__'
    console.log(Object.keys(obj)); // ->['status']

    Object.defineProperty(obj, 'status', {
    
    
        value: '3',
        // enumerable: true,
        // enumerable: false,
        // configurable: false,
        // configurable: true,
        writable: false
    });
    obj.status = '3__';
    console.log(obj.status); // ->'3'
    console.log(Object.keys(obj)); // ->['status']

    Object.defineProperty(obj, 'status', {
    
    
        // writable: true
    })

Propriedades do acessador

As propriedades do acessador não contêm valores de dados, elas contêm duas funções, getter e setter (nenhum deles é obrigatório). Ao ler uma propriedade do acessador, uma função getter é chamada, que é responsável por retornar um valor válido; ao escrever uma propriedade do acessador, uma função setter é chamada e um novo valor é passado. Esta função determina como processar os dados . Este tipo de atributo também possui as seguintes quatro características:

  • [[ Configurável ]]: Indica se o atributo pode ser excluído por meio de exclusão , a característica do atributo pode ser modificada ou o atributo pode ser modificado como um atributo de dados.
  • [[ Enumaerable ]]: se o atributo de destino pode ser enumerado (percorrido) .
  • [[Get]]: A função a ser chamada ao ler atributos. O valor padrão é indefinido.
  • [[Set]]: Uma função chamada ao escrever atributos. O valor padrão é indefinido.
    var book = {
    
    
        _year: 2004,
        edition: 1
    };
    Object.defineProperty(book, 'year', {
    
    
        get: function() {
    
    
            return this._year;
        },
        set: function(newValue) {
    
    

            if (newValue > 2004) {
    
    
                this._year = newValue;
                this.edition += newValue - 2004;
            }
        }

    });
    book.year = 2010; // 写入属性
    console.log(book.edition, book.year); // -> 7  2010

O exemplo acima é o código de amostra do livro. O objeto do livro no código tem dois atributos padrão edição (versão) e atributo _ano. O sublinhado na frente do atributo _year é uma marca comumente usada, o que significa que o atributo é usado apenas para acesso de método interno do objeto . O outro atributo de ano é um atributo de acessador, e os recursos set e get desse atributo serão chamados respectivamente durante a gravação e leitura. O valor de retorno de chamar get durante a leitura é o valor do atributo acessador, chamar set durante a gravação faz com que _ano e a edição mudem de acordo, esta também é uma maneira comum de usar atributos de acessador, ou seja, definir um valor fará com que outros atributos sejam mudar .

Para entender melhor essas duas características das propriedades do acessador, fiz algumas alterações no exemplo. A seguir, _ano representa o ano de publicação e não será alterado. Supondo que uma nova versão seja lançada a cada ano no futuro, ou seja, o atributo de edição mudará a cada ano. Adicione um ano de propriedade do acessador ao objeto de livro. O valor de retorno dessa propriedade é o ano atual e a edição é atualizada de acordo .

    var book = {
    
    
        _year: 2004,
        edition: 1
    };
    Object.defineProperty(book, 'year', {
    
    
        get: function() {
    
    
            return (new Date()).getFullYear();
        },
        set: function() {
    
    
            this.edition += this.year - this._year;
        }

    });
    book.year = 2010;
    console.log(book.edition, book.year); // -> 18 2021

Há outro recurso do atributo acessador que não é refletido, ou seja, "o atributo acessador não contém um valor de dados " no livro . O atributo ano acima não inclui o ano? Depois de ter essa ideia, o seguinte código de exemplo apareceu.

    var book = {
    
    
        _year: 2004,
        edition: 1
    };
    Object.defineProperty(book, 'year', {
    
    
        set: function() {
    
    
            this.edition += (new Date()).getFullYear() - this._year;
        }
    });
    book.year = 2010;
    console.log(book.edition, book.year); // -> 18 udefined

No código acima, apenas o recurso [[Set]] da propriedade year é definido, e undefined é retornado quando a propriedade year é acessada. Especifique apenas as propriedades da função setter que não pode ser lida, caso contrário retornará indefinido (o livro diz que relatará um erro em modo estrito, mas depois de tentar com suas próprias mãos, parece que ainda retorna indefinido). Se apenas o recurso [[Getter]] for especificado, significa que a propriedade é somente leitura e não pode ser gravada e será ignorada ao tentar gravar, e um erro será relatado no modo estrito .

    "use strict";
    /*
    * 其他代码
    */
    book.year = 2010; // Uncaught TypeError: Cannot set property year of #<Object> which has only a getter

Nem todos os navegadores suportam o método Object.defineProperty (), portanto, antes disso, dois métodos não padrão foram usados ​​para adicionar propriedades do acessador. __defineGetter __ () e __defineSetter __ () podem ser usados ​​para criar propriedades de acessador e definir propriedades [[Get]] e [[Set]], mas se o navegador não suportar o método Object.defineProperty (), as outras duas propriedades não podem ser mudou.

    var book = {
    
    
        _year: 2004,
        edition: 1
    };
    book.__defineGetter__('year', function() {
    
    
        return this._year;
    });

    book.__defineSetter__('year', function(newValue) {
    
    

        if (newValue > 2004) {
    
    
            this._year = newValue;
            this.edition += newValue - 2004;
        }
    })
    book.year = 2010; // 写入属性
    console.log(book.edition, book.year); // -> 7  2010

2. Defina várias propriedades ao mesmo tempo (defineProperties ())

    var book = {
    
    };
    Object.defineProperties(book, {
    
    
        // 数据属性的定义
        _year: {
    
    
            writable: false,
            value: 2004
        },
        edition: {
    
    
            writable: true,
            value: 1
        },
        // 访问器属性
        year: {
    
    
            get: function() {
    
    
                return (new Date()).getFullYear();
            },
            set: function() {
    
    
                this.edition += (new Date()).getFullYear() - this._year;
            }
        }
    })

Este método tem a mesma compatibilidade com Object.defineProperty ().

3. Object.getOwnPropertyDescriptor ()

Este método é usado para ler as quatro características de um determinado atributo do objeto. Receba dois parâmetros, o primeiro parâmetro é o objeto onde o atributo está localizado e o segundo parâmetro é o nome do atributo que precisa ser lido. O valor de retorno é um objeto que contém as quatro características do atributo.

    var attributes = Object.getOwnPropertyDescriptor(book, 'year');
    console.log(attributes.set); 
    var attributes = Object.getOwnPropertyDescriptor(book, '_year');
    console.log(attributes);

Insira a descrição da imagem aqui

Acho que você gosta

Origin blog.csdn.net/TKOP_/article/details/115018189
Recomendado
Clasificación