JavaScriptのプロパティと特徴を詳しく解説

黄舟
リリース: 2016-12-13 16:57:55
オリジナル
1100 人が閲覧しました

JavaScript の属性と特性は 2 つのまったく異なる概念です。ここでは、JavaScript の属性と特性を深く理解するために学んだことを使用します。

主な内容は以下の通りです:

JavaScriptにおけるオブジェクトの性質、オブジェクトとクラスの関係、オブジェクトと参照型の関係を理解する

オブジェクトの属性を分類する方法

属性の特徴を理解する

パート 1: JavaScript を理解するオブジェクトの本質、オブジェクトとクラスの関係、およびオブジェクトと参照型の関係

オブジェクトの本質: ECMA-262 ではオブジェクトを次のように定義しています: 順序付けされていない属性のコレクション。その属性は次のように定義されています。基本的な値、オブジェクト、または関数が含まれます。つまり、オブジェクトは、特定の順序ではない値のセットであり、オブジェクトの各プロパティまたはメソッドには名前があり、この名前が値にマップされます。したがって、オブジェクトの本質はハッシュ テーブルです。これは名前と値のペアのセットであり、値はデータまたは関数になります。

オブジェクトとクラスの関係: JavaScript では、オブジェクトとクラスには関係がありません。これは、ECMAScript にはクラスの概念がまったくなく、オブジェクトが他のクラスベース言語とは異なるためです。

オブジェクトと参照型の関係: 各オブジェクトは参照型に基づいて作成されるため、オブジェクトと参照型は同等ではありません。

パート 2: オブジェクトのプロパティを分類する方法

コンストラクターまたはオブジェクト リテラル メソッドによって作成されたオブジェクトには、プロパティとメソッドがあります (プロパティとメソッドが言及されている限り、それらはオブジェクトに属している必要があります。オブジェクトが言及されている限り、それはオブジェクトに属している必要があります)属性とメソッド (カスタマイズを除く) が必要です)。属性はデータ属性とアクセサー属性に分類できます。その違いは次のとおりです:

データ属性は通常、データ値を格納するために使用され、アクセサー属性にはデータは含まれません。

アクセサー属性は主に get/set 操作に使用されます

パート 3: 属性の特性を理解する

ECMAScript は、オブジェクト属性 (プロパティ) のさまざまな特性を記述するために属性の概念を定義します。つまり、特性は属性を説明するために使用されます。以下、それぞれ説明します:

Data プロパティとその特性

Accessor プロパティとその特性

Object.defineProperties() メソッドを使用して複数のプロパティを定義する方法

Object.getOwnPropertyDescripter() メソッドを使用してプロパティの読み取り 属性の特性を読み取るための記述子

1. データ属性とその特性

先ほど、データ属性はデータ値を格納するために使用されると述べました。そのため、データ属性にはデータ値の位置があり、この位置で読み取られて値を書き込みます。 data 属性には、その動作を説明する 4 つの特性があります。ECMAScript では、属性の特性に JavaScript で直接アクセスできないと規定しているため (注: アクセスできないわけではありません)、2 つの角括弧で囲みます。以下のように:

[[Configurable]]: デフォルト値は true、a. 属性を削除することで属性を再定義できるかどうかを示します。 b. 属性の特性を変更できるかどうかを示します。 c. 属性をデータ属性からアクセサー属性に変更する機能

[[Enumerable]]: デフォルト値は true で、for-in ループを通じて属性を返すことができるかどうかを示します (つまり、false の場合、for は-in ループは、配置されているプロパティを列挙するメソッドではありません)

[[Writable]]: デフォルト値は true で、プロパティの値を変更できるかどうかを示します。これは [[Configurable]] とは異なります。 。

[[値]]: デフォルト値は未定義です。この値は、この位置で属性値を読み取り、この位置で属性値を書き込むことができます。

注: 上記のデフォルトは、以下で紹介する Object.defineProperty() メソッドではなく、コンストラクターまたはオブジェクト リテラルを通じて作成されたオブジェクトが所有するプロパティを指します

これらのプロパティにはすべてデフォルト値がありますが、これらのデフォルト値がは私たちが望んでいることではありません。どうすればよいでしょうか?もちろん改造ですよ! Object.defineProperty() メソッドを通じてプロパティのデフォルトのプロパティを変更できます。英語のdefinePropertyはプロパティを定義することを意味します。このメソッドは、プロパティが存在するオブジェクト、プロパティの名前、および記述子オブジェクトの 3 つのパラメーターを受け取ります。 3番目のパラメータ記述子オブジェクトはオブジェクトリテラルメソッドによって作成され、内部の属性と属性値には実際に変更される特性と属性値が格納されます。

より深く理解するために、いくつかの例を使用してみましょう。

a

var person={};
Object.defineProperty(person,"name",{
  writable:false,
  value:"zhuzhenwei"
});
console.log(person.name);//zhuzhenwei
person.name="heting";
console.log(person.name);//zhuzhenwei
ログイン後にコピー

ここでは、オブジェクトリテラルメソッドを使用してオブジェクトを作成しましたが、メソッドとプロパティを同時に作成しませんでした。代わりに、Object.defineProperty() メソッドを使用してプロパティを作成し、デフォルト値を変更します。ここではwritableがfalseに設定されているため、後でperson.nameを変更しようとすると無効になります。


b

var person={};
Object.defineProperty(person,"name",{
  value:"zhuzhenwei"
});
console.log(person.name);//zhuzhenwei
person.name="heting";
console.log(person.name);//zhuzhenwei
ログイン後にコピー

この例では、writable:false を削除したのですが、なぜ変更できないのでしょうか。これは、以前に機能を紹介したときに、最初の 3 つがデフォルトで true に設定されていたためです。これは、オブジェクトの作成時とプロパティの作成時に取得されました。 Object.defineProperty() メソッドを呼び出して作成されたプロパティの場合、最初の 3 つのプロパティのデフォルト値は false であることに注意してください。


c

var person={};
Object.defineProperty(person,"name",{
  value:"zhuzhenwei",
  configurable:false
});
console.log(person.name);//zhuzhenwei
delete person.name;
console.log(person.name);//zhuzhenwei
ログイン後にコピー

ここでは、新しく作成した属性名のプロパティを configurable:false に設定します。したがって、属性を削除する次の操作は無効です。 b によれば、設定可能であり、デフォルトは false で、削除しても変更できないことがわかります。


d

var person={};
Object.defineProperty(person,"name",{
  value:"zhuzhenwei",
  configurable:true
});
console.log(person.name);//zhuzhenwei
delete person.name;
console.log(person.name);//undefined 
ログイン後にコピー

在这里我将默认的configurable的值由默认的false修改为了true,于是变成了可配置的,那么最后就成功删除了。

e

var person={};
Object.defineProperty(person,"name",{
  value:"zhuzhenwei",
  configurable:false
});
console.log(person.name);//zhuzhenwei
Object.defineProperty(person,"name",{
  value:"zhuzhenwei",
  configurable:true
});
console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)
ログイン後にコピー

如果之前已经设置成为了false,那么后面再改成true也是徒劳的,即:一旦把属性设置成为不可配置的,就不能再把它变回可配置了。


f

console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)
var person={};
Object.defineProperty(person,"name",{
  value:"zhuzhenwei",
});
console.log(person.name);//zhuzhenwei
Object.defineProperty(person,"name",{
  value:"zhuzhenwei",
  configurable:true
});
console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)
ログイン後にコピー

这里可以说明,即使前一步我们不管默认的configurable:false,后面得到的仍是不可配置。于是,可以得出结论,为了可配置,必须在第一次调用Object.defineProperty()函数时就将默认的值修改为true。

2.访问器属性及其特性  

之前提到,访问器属性不包含数据值,他们包含一对getter函数和setter函数(这两个函数不是必须的)。在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性是,会调用setter函数并传入新值,这个函数负责决定如何处理数据。同样,由于不能通过JavaScript来直接访问得到访问器属性的特性,所以下面列出的特性将由[[]]括起来以作区分。

[[Configurable]]:默认值为true,a、表示能否通过delete删除属性从而重新定义属性 b、能否修改属性的特性 c、能够把属性由访问器属性修改为数据属性

[[Enumerable]]:默认值为true,表示能否通过for-in循环返回该属性(所以:如果为false,那么for-in循环没法枚举它所在的属性)

[[Get]]:在读取属性时调用的函数。默认值为undefined 关键:特性可以是一个函数

[[Set]]: 在写入属性时调用的函数。默认值为undefined 关键:特性可以是一个函数 由于get和set函数也属于属性的特性,那么他们就有可能(说有可能是因为这两个函数也不是必须的)出现在Object.defineproperty的第三个参数描述符对象的属性中。

注意:1.相对于数据属性,我们发现访问器属性中没有writable特性和value特性。这是因为访问器属性不包含数据值,那么我们怎么当然就不可修改属性的值(用不到writable特性),更不用考虑value了。

   2.访问器属性不能直接定义,必须是用Object.defineProperty()来定义。(通过这个规定我们就能准确地判断出访问器属性和数据属性了)

通过下面这个例子来深入理解:

var book={
  _year:2004,
  edition:1
};
Object.defineProperty(book,"year",{
  get:function(){<br>            return this._year;
  },
  set:function(newValue){
    if(newValue>2004){
      this._year=newValue;
      this.edition+=newValue-2004;
    }
  }
});
book.year=2005;
console.log(book.edition);//2
ログイン後にコピー

几个需要深入理解的地方:

1.访问器属性不能直接定义,必须使用Object.defineProperty()来定义,且该属性具有set和ger特性,于是可以判断,_year和edition是数据属性,而year是访问器属性。

2.我们看到_year这个数据属性前面是以_(下划线)开头的,这个一种常用的记号,用于表示只能通过对象方法访问的属性。从上面的例子中可以看到get相当于描述符对象的一个方法,而_year正是在这个对象方法访问的属性。而edition既可以通过对象方法访问,也可以由对象直接访问。

3.book.year表示正在读取访问器属性,这时会调用get函数,并返回了2004这个有效的值。

4.book.year=2005表示写入访问器属性,这时会调用set函数并传入新值,即将2005传给newValue,这个函数决定如何处理数据。

5.这时使用访问器属性的常见方法-即设置一个属性的值会导致其他属性发生变化。


3.如何利用Object.defineProperties()方法定义多个特性

显然,一个对象不可能只具有一个属性,因此,定义多个属性的可能性很大,于是JavaScript提供了Object.defineProperties()方法解决这个问题。这个方法接收两个参数,第一个是要定义属性所在的对象,第二个是一个对象字面量方法创建的对象,对象的属性名即为要定义的特姓名,对象的属性值又是一个对象,这个对象里的属性名和属性值分别是特性名和特性值(这里不是很好理解,看例子即可)。

var book={};
Object.defineProperties(book,{
  _year:{
    writable:true,
    value:2004
  },
  edition:{
    writable:true,
    value:1
  },
  year:{
    get:function(){
      return this._year;
    },
    set:function(){
      if(newValue>2004){
        this._year=newValue;
        this.edition+=newValue-2004;
      }
    }
  }
}); 
ログイン後にコピー

4.如何利用Object.getOwnPropertyDescripter()方法读取属性的描述符以读取属性的特性

  我们可以使用Object.getOwnPropertyDescripter()方法来取得给定属性的描述符。getOwnPropertyDescripter即为取得自身属性描述符的意思。这个方法接收两个参数:属性所在的对象要要读取其描述符的属性名称。返回一个对象。

  对于访问器属性而言,这个对象的属性有configurable、enumerable、get和set;

  对于数据属性而言,这个对象的属性有configurable、enumerable、writable和value。

var book={};
Object.defineProperties(book,{
  _year:{
    value:2004
  },
  edition:{
    value:1
  },
  year:{
    get:function(){
      return this._year;
    },
    set:function(){
      if(newValue>2004){
        this._year=newValue;
        this.edition+=newValue-2004;
      }
    }
  }
});
var descriptor=Object.getOwnPropertyDescriptor(book,"_year");
console.log(descriptor.value);//2004
console.log(descriptor.configurable);//false 因为通过Object.defineProperties()方法创建的属性的特性configurable enumerable都是false
console.log(typeof descriptor.get);//undefined 注意:这是数据属性,是不具有get特性的
var descriptor=Object.getOwnPropertyDescriptor(book,"year");
console.log(descriptor.value);//undefined
console.log(descriptor.enumerable);//false
console.log(typeof descriptor.get);//function get虽然是属性的一个特性,但是它也是函数
ログイン後にコピー

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,同时想要关注更多的相关内容请关注PHP中文网(www.php.cn)!


関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート