ホームページ > 記事 > ウェブフロントエンド > ディスカッション: JavaScript ECAMScript5 の新機能 accessor_javascript スキルの取得/設定
EcmaScript5 の概要
まず、ECMAScript は魔法の馬であることを理解する必要があります。JavaScript または LiveScript が最初に作成されたのは Netscape であり、その後、Microsoft も独自の CENvi を作成しました。ブラウザ スクリプトはすべて独自の動作を行うため、この混乱を誰もが理解しているため、標準化の問題が議題に上ることになりました。 1997 年に、JavaScript 1.1 に基づく提案が欧州コンピュータ製造者協会 (欧州コンピュータ製造者協会) に提出され、最終的には ECMAScript と呼ばれる新しいスクリプト言語標準である ECMA-262 が全員で歌い踊りました。翌年、ISO/IEC (国際標準化機構および国際電気標準会議) も ECMAScript を標準として採用し、それ以来、主要なブラウザ メーカーがそれぞれの JavaScript 実装の基礎として ECMAScript を使用するようになりました。それ以外の場合は、ブラウザの互換性の問題もそれほど多く発生しません。
ECMAScript5 とは何ですか?名前が示すように、iPhone5 のようなこの奇妙なものの 5 番目のバージョンで、現在私たちがよく使用しているのは ECMAScript3 です。最初の 2 つのバージョンと比較すると、このバージョンはおもちゃではなく本物のプログラミング言語になっています。人気のある。
テキスト:
get/set についての私のこれまでの理解は間違っていました。get set はオブジェクトのプロパティ メソッドだと思っていました。他の人のブログを読んだ後、私もたくさんの質問をしましたが、今日私はシステムで多くのテストを行い、最終的にそれを理解しました。 (私は本を読んでデモを書いてテストに合格しました。間違いがあれば、批判して修正してください)
get/set アクセサーはオブジェクトのプロパティではなく、プロパティの特性です。誰もが明確に区別する必要があります。プロパティは内部でのみ使用されるため、JavaScript から直接アクセスすることはできません。属性を示すために、内部値は [[Value]] のように 2 組の大括弧で囲まれます。
1. これらの属性の特徴を簡単に紹介します (簡単な裏書きです)
(1) データ属性 - データ値の場所が含まれます。この場所に値を読み書きできます。
データ属性には、その動作を説明する 4 つの特性があります。
[[Configurable]]: 構成可能かどうか
[[Enumerable]]: 列挙可能かどうか
[[Writable]]: 読み取り可能かどうか
[[Value]]: 属性値
(2) アクセサ属性属性 - データ値は含まず、ゲッター関数とセッター関数が含まれます (これら 2 つの関数は必要ありません)
アクセサ プロパティには、その動作を説明する 4 つの特性もあります。
[[Configurable]]: 構成可能かどうか
[[Enumerable]]: 列挙可能かどうか
[[Get]]: プロパティの読み取り時に呼び出される関数、デフォルトは未定義です
[[Set]]: 属性を書き込むときに呼び出される関数、デフォルトは未定義です。
2. ここでは、get/set アクセサー
と呼ばれるものである [[Get]]/[[Set]] に焦点を当てます。
まず、本書で言及されている get/set アクセサーの動作特性について説明します。get/set アクセサーは定義する必要がなく、定義せずに属性値の読み取りと書き込みが可能です。 1 つだけ定義することもできます。 get のみが定義されている場合、記述された属性は読み取りのみ可能であり、書き込みはできません。 set のみが定義されている場合、記述された属性は書き込みのみ可能であり、読み取りはできません。
(1) オリジナルの get set メソッドは次のようなものです:
function Foo(val){ var value=val; this.getValue=function(){ return value; }; this.setValue=function (val){ value=val; }; } var obj=new Foo("hello"); alert(obj.getValue());//"hello" obj.setValue("hi"); alert(obj.getValue());//"hi"
上記のコードは、クロージャ スコープを使用して実装された get set メソッドにすぎません。このメソッドは、属性の特性ではなく、インスタンス オブジェクトの属性メソッドであることに注意してください。定義されていない場合、値
にはアクセスできません。
function Foo(val){ var value=val; /* this.getValue=function(){ return value; }; this.setValue=function (val){ value=val; }; */ } var obj=new Foo("hello"); alert( obj.value);//undefined
次の例もオブジェクトのプロパティ メソッドであり、プロパティ特性ではありません。
var obj={ name:"john", get:function (){ return this.age; }//只定义了get ,没有定义set,但是仍然可以读,写,name属性,即使这里是age //这里这样定义的方法不会影响属性的get,set 特性。只是普通的对象属性 }; alert(obj.name);//john 可读 obj.name="jack";//可写 alert(obj.name);//jack
(2) アクセサ属性の特性としてアクセサを取得/設定します。
繰り返しますが、これらはオブジェクトのプロパティではなく、プロパティを読み書きできるかどうか、またその方法を決定します。設定しなくても通常の読み書きと同じで大丈夫です(属性は読み込めます
)書き込み、読み取り、および書き込みアクセスは属性自体の値です)
属性の get/set プロパティを変更するには、次の 2 つの方法があります:
a. Object.defineProperty()
を使用するだけです。var object={ _name:"Daisy" }; Object.defineProperty(object,"name",{//这里的方法名name,就表示定义了一个name属性(因此才能通过object.name访问),只定义了getter访问器,没有定义[[value]]值 get:function (){//只定义了get 特性,因此只能读不能写 return this._name; } }); alert(object.name);//"Daisy" object.name="jack";//只定义了getter访问器,因此写入失效 alert(object.name);//"Daisy"
Object.defineProperty(object, pro, {}) のプロパティ名は、object.pro によってアクセスされるプロパティに対応する必要があることに注意してください
b. get set キーワードを使用します:
var object={ _name:"Daisy", get name(){//这里的方法名name ,就表示定义了一个name属性(因此才能通过object.name访问),只定义了getter访问器,没有定义[[value]]值 return this._name; }//get,set方法只是属性的特性 ,不是对象方法,决定属性能否、怎么读写 }; alert(object.name);// Daisy这里去掉下划线 方法就是Daisy ;加上就是undefined object.name="jack";//只定义了getter访问器,因此只能读不能写 alert(object.name);//Daisy
以上两种方法等效。注意的是以上两种方法object对象当中都将有有两个属性:_name(有初始值) name(无初始值),通过浏览器控制台可以看到
那么这个name属性实在什么时候定义的呢?我们知道Object.defineProperty(object,pro,{})可以给对象定义一个新属性pro,既然get pro(){}/set pro(){}和Object.defineProperty(object,pro,{})等效,则也会定义一个新属性pro .这就是为什么object里面有两个属性的原因。
(3)在此篇文章中网络之美 JavaScript中Get和Set访问器的实现代码关于标准标准的Get和Set访问器的实现:引发的思考
我自己也写了一个一样的例子
function Foo(val){ this.value=val;//定义了value属性 并没有定义_value } Foo.prototype={ set value(val){//注意方法名和属性名相同,在prototype里定义了value属性 this._value=val; }, get value(){//方法名和属性名相同,在prototype里面定义了value属性和它的get 特性 return this._value; } }; //访问器返回和设置的都是_name,这里并没有定义_name属性为什么也可以读可以写???? var obj=new Foo("hello"); alert(obj.value);//"hello" obj.value="yehoo"; alert(obj.value);//"yehoo"
为了解决以上这个疑问,做了很多测试,我们一一来看:
先看这个例子,在prototype里面只定义get 特性,在obj.value读value属性时,在实例里面寻找没有,然后在原型里面找到,调用的是原型的get方法,只能读不能写
function Foo(val){ this._value=val;//这里 的属性是带下划线的,初始化实例对象的_value属性,_value属性可读可写 } Foo.prototype={ // set value(val){//注意方法名和属性名相同,在prototype里定义了value属性 // this._value=val; // }, get value(){//方法名和属性名相同,在prototype里面定义了value属性和它的get 特性 return this._value; } }; var obj=new Foo("hello"); alert(obj.value);//hello 访问的是prototype里面的value 属性 obj.value="yehoo";//只定义了name 属性的get 特性,因此只能读不能写,写入失效 alert(obj.value);//hello
如果构造函数里面this._value 去掉下划线,在prototype里面定义的value属性,定义了get 特性。依然可以控制value属性的读写 。也就是说obj.value访问属性时,会调用get方法,先在对象本身寻找,如果没有,再到prototype寻找,如果都没有才算没有定义,默认的既可读又可写
function Foo(val){ this.value=val;//在原型里面只定义了value的get特性,因此这里写入失效 } Foo.prototype={ // set value(val){//注意方法名和属性名相同,在prototype里定义了value属性的set特性 // this._value=val; //}, //value:"hah",//即使手动写入value值,由于get方法返回的是this._value,因此也不能正确读取value:"hah" //只要声明了get pro (){}和set pro (){}属性就都能读能写,但是如果函数定义错误,依然不能按要求访问到正确的属性值 get value(){//方法名和属性名相同,在prototype里面定义了value属性和它的get 特性 return this._value; } }; var obj=new Foo("hello");//"hello"没有写入成功 alert(obj.value);//undefined obj.value="yehoo";//只定义了get 特性,因此只能读不能写,写入失效 alert(obj.value);//undefined
为了证明上面例子是可读不可写的:手动写入_value:"hah",就可以读取value 但不能写入。
function Foo(val){ this.value=val;//在原型里面只定义了value的get特性,因此这里写入失效 } Foo.prototype={ // set value(val){//注意方法名和属性名相同,在prototype里定义了value属性的set特性 // this._value=val; //}, _value:"hah",//即使手动写入value值,由于get方法返回的是this._value,因此也不能正确读取value:"hah" //只要声明了get pro (){}和set pro (){}属性就都能读能写,但是如果函数定义错误,依然不能按要求访问到正确的属性值 get value(){//方法名和属性名相同,在prototype里面定义了value属性和它的get 特性 return this._value; } }; var obj=new Foo("hello");//"hello"没有写入成功 alert(obj.value);//"hah" obj.value="yehoo";//只定义了get 特性,因此只能读不能写,写入失效 alert(obj.value);//"hah"
如果手动写入的是value:"hah",那么可以争取读取value的值吗?由于get方法返回的this._value并没有定义,obj.value读取value值调用get value(){}方法失效,但是value仍然不能写入。
function Foo(val){ this.value=val;//在原型里面只定义了value的get特性,因此这里写入失效 } Foo.prototype={ // set value(val){//注意方法名和属性名相同,在prototype里定义了value属性的set特性 // this._value=val; //}, value:"hah",//即使手动写入value值,由于get方法返回的是this._value,因此也不能正确读取value:"hah" //只要声明了get pro (){}和set pro (){}属性就都能读能写,但是如果函数定义错误,依然不能按要求访问到正确的属性值 get value(){//方法名和属性名相同,在prototype里面定义了value属性和它的get 特性 return this._value; } }; var obj=new Foo("hello");//"hello"没有写入成功 alert(obj.value);//undefined 读取失效 因为只要obj.value就会调用get ,而get返回的是this._value,没有这个值,因此undefined obj.value="yehoo";//只定义了get 特性,因此只能读不能写,写入失效 alert(obj.value);//undefined
再看这个例子,get set 都定义了,但是返回没有定义的this._value。可以发现value既可读又可写。去掉原型里面的get set方法,依然可读可写
function Foo(val){ this.value=val; } Foo.prototype={ set value(val){ this._value=val; }, get value(){ return this._value; } }; var obj=new Foo("hello"); alert(obj.value);//hello obj.value="yehoo"; alert(obj.value);//yehoo function Foo(val){ this.value=val; } //和平时的操作是一样的了,就是回到了不定义get /set访问器特性的默认状态 var obj=new Foo("hello"); alert(obj.value);//hello obj.value="yehoo"; alert(obj.value);//yehoo
总结
只声明了get pro(){}属性 可读不可写;
只声明 set pro(){}属性可写不可读。
如果都不声明,属性可读可写;
如果都声明就按照,get set 定义的方法,读写;
如果都声明了,但是定义的读写方法不能正确读写,get/set失效。变成默认的可读可写
在prototype里面定义的value属性,定义了get 特性。依然可以控制value属性的读写 。也就是说obj.value访问属性时,会调用get方法,先在对象本身寻找,如果没有,再到prototype寻找,如果都没有才算没有定义,默认的既可读又可写。
补充:
不管是用get pro(){}/set pro (){} 还是用Object.defineProperty(object,pro,{ get:function (){ return this._name; } });
pro不能和 return this. 后面的属性一样,不然会报下面的错误:(具体我也不知道为什么,好像是自身调用引起的栈溢出)
经大神指正,明白为什么这里报错:在get value(){}方法里返回 this.value,就会又去调用value的get 方法,因此陷入死循环,造成方法栈溢出。