ホームページ > 記事 > ウェブフロントエンド > JavaScriptのオブジェクトプロパティの詳しい説明
JavaScript におけるオブジェクトの概念は、確かにわかりにくい場合があります。次の例を見てください:
var strPrimitive = "I'm mamacat"; typeof strPrimitive; // "string" strPrimitive instanceof String; // false var strObject = new String("I'm mamacat"); typeof strObject; // "object" strObject instanceof String; // true strPrimitive.substr(8, 3); // "cat"
同じ文字列がオブジェクトに割り当てられています。文字列型である場合もあれば、オブジェクトである場合もあります。ただし、明らかにオブジェクト型ではない変数でもオブジェクト属性を使用できます。どうしてこれなの?
[関連コースの推奨事項: JavaScript ビデオ チュートリアル]
型と組み込みオブジェクト
主な型は 6 つありますJavaScript (言語) の型、つまり string、number、boolean、null、unknown、object のうち、最初の 5 つの基本型はオブジェクトではありません (typeofing null は、言語自体である「object」になります)バグ)。これ以外にも、配列、関数、組み込みオブジェクトなど、多くの特別なオブジェクト サブタイプがあります。
一部の組み込みオブジェクトの名前は、String、Boolean、Object などの単純な基本型と同じように見えます。表現という点では、これらの組み込みオブジェクトは他のオブジェクト指向言語の「クラス」の概念に似ていますが、前の記事で述べたように、実際には対応するオブジェクトを構築するために使用できる組み込み関数の一部にすぎません。サブタイプ (混同しないでください)、関数もオブジェクトです、ここに矛盾はありません)。元の例に戻ると、strObject は組み込み関数/組み込みオブジェクト String によって構築された変数であり、String サブタイプに対応するためオブジェクトであり、strPrimitive は単なるプリミティブ リテラル値です。
もちろん、上記の例の下部では、strPrimitive で substr() 関数を呼び出しているようです。これは、JavaScript エンジンが必要に応じて元のリテラルを対応するオブジェクトに変換するためです。変換 当然のことながら、属性を使用して対応するメソッドにアクセスできます。
オブジェクト プロパティ
したがって、上記の例に関する限り、String オブジェクト インスタンスには substr() 関数が利用可能ですが、前の記事によると、これらの「関数」自体はオブジェクトに属していないが、これらの関数は本質的に対応するオブジェクトの属性であることがわかります。もちろん、ある種のオブジェクト自体がさまざまな属性を持っていると言っても、実際にはそれらの属性は独立して存在していることがほとんどで、参照という形で相互に関連しているだけであり、これまでに学習したことと矛盾するものではありません。これらの関連するものは、オブジェクトのプロパティと呼ばれます。
オブジェクトのコピー
クイック レポートを挿入します。前の記事でも触れましたが、属性は、オブジェクト内で関連する独立したエンティティにすぎないことを繰り返し強調しました。はい、私たちは今でも属性がオブジェクトの一部であることを「当然のことと思っている」ことがありますが、最も問題が発生しやすい場所の 1 つはオブジェクトのコピーです。よく考えてみると、オブジェクトをコピーすると、その属性自体は参照の関連付けにすぎないため、「コピーされた」オブジェクトに含まれる属性参照は、実際には元のオブジェクトの属性参照と同じ場所を指すことがわかります。 :
var ori = { a : 1}; var ori_copy = ori; ori.a = 61; ori_copy.a; // 61
明らかに、これは私たちの期待とは異なる可能性があり、オブジェクトを本当にコピーしたい場合、完全に適用できる解決策はありません。多くの場合、一般的な方法は、オブジェクトをシリアル化してから逆シリアル化することです。 . オブジェクトをコピーするには、新しいオブジェクトを取得します (json を使用するなど)。 Object.assign()
は、オブジェクトの浅いコピーを実行するために ES6 に追加されました。このメソッドは、オブジェクトのすべての列挙可能なプロパティを新しいオブジェクトに等号を使用して割り当てます。ただし、等号の割り当てでは属性のメタ情報 (後述の属性記述子) が割り当てられるわけではないため、必要に応じて特に注意する必要があります。
属性アクセスと配列
オブジェクトに関連付けられたプロパティにアクセスする方法は、. または [] 演算子、obj.a および obj["a" を使用します。 ] アクセスされる属性は本質的に同じであり、これら 2 つのアクセス形式の唯一の違いは、アクセスされる属性の名前に奇妙な記号が含まれるかどうかです。 [] 演算子でスローされるのは文字列であり、実際、属性名は常に文字列です。もちろん、この概念で驚くべきことは、配列への添字アクセスも例外ではなく、数値は使用される前に文字列に変換されることです。
// 对象的属性访问: var tejilang = {1 : "Teji Wolf"}; tejilang instanceof Array; // false tejilang["1"]; // "Teji Wolf" tejilang[1]; // "Teji Wolf" // 这回保证它是 Array var macat = ["codingcat"]; macat instanceof Array; // true macat.length; // 1 macat[0]; // "codingcat" macat["0"]; // "codingcat" macat.length = 20; macat; // (20) ["codingcat", empty × 19]
数组下标既然不属例外情况,那数组对象必然有其它属性控制数组本身的行为,例如上例中,macat 数组的长度就是 length 属性所体现的,通过修改它的值也就改变了对象本身对外的表现形式。当然,由于数组本身就是对象,所以我们还是可以把数组当键值对来用,只是这种做法通常是没有意义且会让人感到困惑的。JavaScript 引擎通常都根据对象的类型做了不同程度的优化,故除了代码逻辑可读性外,合理的使用也是多少可以改善性能的。
能够通过字符访问属性还是存在一些别的好处的,比如 ES6 的可计算属性名。当然 ES6 不在本文的关注范围内,所以这里就不再讨论了。
属性描述符
有时我们可能不希望某个属性被随意修改,有时候我们需要额外配置一些属性的信息,自 ES5 起,所有的属性就都具备了“属性描述符”(Property Descriptor)来控制属性本身的这些元信息。
数据描述符
来看这个例子:
var chris = {}; Object.defineProperty(chris, "IQ", { value: 228, writable: false, configurable: true, enumerable: true }); chris.IQ = 61; // 静默失败了,如果是严格模式则会 TypeError chris.IQ; // 228
通过 defineProperty 可以对一个对象的属性配置其对应的属性描述符(元信息),而属性描述符则包含访问描述符和数据描述符,上面的例子中,defineProperty 的第三个参数就定义了数据的若干数据描述符,其中 writable 表示可写,configurable 表示属性是否可配置(注意,修改成不可配置是单向操作),enumerable 则表示属性是否应当出现在枚举中,比如 for..in 中。
显然我们可以通过属性描述符实现对属性的保护,而同时也存在一些方便函数来做近似的事。如 Object.preventExtensions() 会保留原有属性但禁止添加新属性,Object.seal() 会密封对象,在禁止添加新属性的基础上把原有属性标记为不可配置,Object.freeze() 会冻结对象,即在密封的基础上把数据访问属性标记为不可写。
[[Get]], [[Put]] 和访问描述符
在我们访问和赋值一个对象的属性时,实际上是通过 [[Get]] 和 [[Put]] 操作进行的,例如属性访问时,[[Get]] 会先找有没有这个属性,如果没有则会遍历对象的 [[Prototype]] 链(原型链,这次不谈这个概念)来找,实在找不到则返回 undefined 。而这个行为实际是允许我们通过设置 getter (get())和 setter (set())函数来改变的,它们被称为 访问描述符。
当我们提供访问描述符时,对应的访问操作就不再受到 value 和 writable 属性的影响了,另外需要注意的是,尽管它们也是属性描述符,但定义 getter 和 setter 并不要求一定要通过 defineProperty 设置:
var obj = { get a() { // 给 a 属性定义 getter return this._a_; }, set a(val) { // a 属性的 setter this._a_ = val * 2; } } obj.a = 2; obj.a; // 4
属性存在性
因为属性的值也可能是 undefined,不存在的属性直接访问得到的也是 undefined,所以直接通过简单的属性访问是无法区分是否存在的,这时我们即可通过 in 或者 hasOwnProperty() 检查属性是否存在对象中了:
var obj = {a : 2}; "a" in obj; // true obj.hasOwnProperty("a"); // true
尽管仍没有讲到原型链的概念,这里仍然应注意,in 操作符会检查原型链中是否存在属性,而 hasOwnProperty 则不会。另外在一些情况下,有的对象会没有 hasOwnProperty 这个属性(此处不提原因),这时可以用过 Object.prototype.hasOwnProperty.call(objName, propertyName) 来实现检查。
本文来自 js教程 栏目,欢迎学习!
以上がJavaScriptのオブジェクトプロパティの詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。