EcmaScript5 소개
우선 ECMAScript가 마법의 말이라는 점을 이해해야 합니다. JavaScript 또는 LiveScript는 나중에 Netscape에서 만들어졌으며 ScriptEase도 자체 CENvi가 있으므로 세 가지가 있습니다. 브라우저 스크립트는 모두 고유한 작업을 수행하며 모든 사람이 이러한 혼란을 이해하므로 표준화 문제가 의제에 포함되었습니다. 1997년에 JavaScript 1.1을 기반으로 한 제안이 유럽 컴퓨터 제조업체 협회(European Computer Manufacturer Association)에 제출되었습니다. 결국 모두가 노래하고 춤을 추며 ECMAScript라는 새로운 스크립트 언어 표준을 생각해 냈습니다. 다음 해에는 ISO/IEC(국제표준화기구 및 국제전기기술위원회)도 ECMAScript를 표준으로 채택했습니다. 그 이후로 세계는 평화로워졌습니다. 물론, 주요 브라우저 제조업체는 ECMAScript를 각자의 JavaScript 구현의 기반으로 사용합니다. , 이는 단지 기초일 뿐이며 완전히 따르지 않습니다. 그렇지 않으면 브라우저 호환성 문제도 많이 발생하지 않습니다.
ECMAScript5란 무엇인가요? 이름에서 알 수 있듯이 iPhone5와 같은 이상한 것의 다섯 번째 버전입니다. 현재 우리가 일반적으로 사용하는 것은 ECMAScript3입니다. 처음 두 버전에 비해 이 버전은 장난감이 아닌 실제 프로그래밍 언어가 되었습니다. 인기 있는.
텍스트:
저는 get/set에 대한 이전 이해가 잘못되었다고 생각했습니다. get set은 객체 속성 방법입니다. 저도 다른 분들의 블로그를 보고 궁금한 점이 많았는데 오늘 시스템에 대해 많은 테스트를 해보고 드디어 알아냈습니다. (저는 책읽기와 데모작성으로 테스트를 통과했습니다. 틀린 부분이 있으면 비판과 정정을 환영합니다)
get/set 접근자는 객체의 속성이 아니라 속성의 특성입니다. 모두가 명확하게 구별해야 합니다. 속성은 내부적으로만 사용되므로 JavaScript에서 직접 액세스할 수 없습니다. 속성을 표시하기 위해 내부 값은 [[값]]과 같이 두 개의 대괄호로 묶입니다.
1. 속성의 특징을 간략히 소개하겠습니다. (여기서는 간단한 보증입니다.)
(1) 데이터 속성 - 데이터 값의 위치를 포함합니다. 이 위치에서 값을 읽고 쓸 수 있습니다.
데이터 속성에는 해당 동작을 설명하는 네 가지 특성이 있습니다.
[[구성 가능]]: 구성 가능 여부
[[Enumerable]]: 열거 가능한지 여부
[[Writable]] : 읽을 수 있는지 여부
[[값]]: 속성값
(2) 접근자 속성 속성 - 데이터 값을 포함하지 않으며 getter 및 setter 함수를 포함합니다(이 두 함수는 필요하지 않음)
접근자 속성에는 동작을 설명하는 네 가지 특성도 있습니다.
[[구성 가능]]: 구성 가능 여부
[[Enumerable]]: 열거 가능한지 여부
[[Get]]: 속성을 읽을 때 호출되는 함수, 기본값은 정의되지 않음
[[Set]] : 속성 작성 시 호출되는 함수, 기본값은 정의되지 않음
2. 여기서는 get/set 접근자라고 부르는 [[Get]]/[[Set]]에 중점을 둡니다.
먼저 책에 언급된 get/set 접근자의 동작 특성에 대해 이야기해 보겠습니다. get/set 접근자는 정의할 필요가 없으며, 정의하지 않고도 속성 값을 읽고 쓸 수 있습니다. 하나만 정의할 수도 있습니다. 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) 접근자 속성의 특성으로 접근자를 가져오거나 설정합니다.
다시 말하지만, 객체의 속성이 아니라 속성을 읽고 쓸 수 있는지 여부와 방법을 결정합니다. 설정하지 않아도 괜찮습니다. 평소 읽고 쓰는 것과 동일합니다. (속성은 읽을 수 있습니다
쓰기, 읽기, 쓰기 액세스는 속성 자체의 값입니다.)
속성의 가져오기/설정 속성을 변경하려면 두 가지 방법이 있습니다.
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 方法,因此陷入死循环,造成方法栈溢出。