探讨:JavaScript ECAMScript5 新特性之get/set访问器


Posted in Javascript onMay 05, 2016

EcmaScript5简介

首先得先搞清楚ECMAScript是神马,我们知道JavaScript或者说LiveScript最开始是Netscape搞出来的,后来微软也跟进搞出了Jscript,ScriptEase也有自己的CENvi,这样就有了三个版本的浏览器Script各行其是,大家懂这个混乱的,于是乎标准化的问题被提上议事日程。1997年以JavaScript1.1为蓝本的建议被提交到欧洲计算机制造商协会( E uropean C omputer M anufacturers A ssociation),最后大家载歌载舞搞出了ECMA-262——一种名为ECMAScript的新脚本语言标准。第二年,ISO/IEC(国际标准化组织和国际电工委员会)也采用ECMAScript作为标准,此后天下太平,各大浏览器厂商以ECMAScript作为各自实现JavaScript的基础,当然只是基础,没完全按照来,否则我们也不会有那么多浏览器兼容性问题。

ECMAScript5是什么呢?顾名思义跟iPhone5一样是这个奇怪东东的第五个版本,我们现在常用的时ECMAScript3,相比前两个版本这个版本算是一门正真的编程语言而不是玩具了,变得很流行。

正文:

之前对get/set的理解一直有误,觉得get set 是对象属性方法。看了别人的博客也有很多疑问,今天系统的做了很多测试终于弄明白了。(自己通过看书和写demo测试的,如有不对欢迎大家批评指正)

get/set访问器不是对象的属性,而是属性的特性。大家一定要分清楚。特性只有内部才用,因此在javaScript中不能直接访问他们。为了表示特性是内部值用两队中括号括起来表示如[[Value]]。

1.先简单介绍一下属性的这些特性(这里是简单的背书)

(1)数据属性——包含一个数据值的位置。这个位置可以读入和写入值。

数据属性有描述其行为的四个特性:

[[Configurable]]:是否可配置

[[Enumerable]]:是否可枚举

 [[Writable]]:是否可读

[[Value]]: 属性值

(2)访问器属性属性——不包含数据值,包含一个getter和setter函数(这两个函数不是必须的)

访问器属性也有描述其行为的四个特性:

[[Configurable]]:是否可配置

[[Enumerable]]:是否可枚举

[[Get]]:在读取属性时调用的函数,默认是undefined

[[Set]]:在写入属性时调用的函数,默认是undefined

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 方法,注意是方法即实例对象的属性方法,不是属性特性。如果不定义,将无法访问value值

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访问器。

再说一遍不是对象的属性,他们 决定属性能否、怎么读写。如果不设置也行,就和平时的读写一样(属性可读可

写,读写访问的都是属性本身的值)

要改变属性的get /set 特性,有两种方式:

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(无初始值),通过浏览器控制台可以看到

探讨:JavaScript ECAMScript5 新特性之get/set访问器

那么这个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. 后面的属性一样,不然会报下面的错误:(具体我也不知道为什么,好像是自身调用引起的栈溢出)

探讨:JavaScript ECAMScript5 新特性之get/set访问器

探讨:JavaScript ECAMScript5 新特性之get/set访问器

经大神指正,明白为什么这里报错:在get value(){}方法里返回 this.value,就会又去调用value的get 方法,因此陷入死循环,造成方法栈溢出。

Javascript 相关文章推荐
firefox浏览器下javascript 拖动层效果与原理分析代码
Dec 04 Javascript
js创建子窗口并且回传值示例代码
Jul 02 Javascript
js操作输入框提示信息且响应鼠标事件
Mar 25 Javascript
ECMAScript 6即将带给我们新的数组操作方法前瞻
Jan 06 Javascript
jquery结合CSS使用validate实现漂亮的验证
Jan 29 Javascript
JavaScript实现SHA-1加密算法的方法
Mar 11 Javascript
js实现头像图片切割缩放及无刷新上传图片的方法
Jul 17 Javascript
JavaScript判断浏览器及其版本信息
Jan 20 Javascript
Ajax和Comet技术总结
Feb 19 Javascript
JS jQuery使用正则表达式去空字符的简单实现代码
May 20 jQuery
ionic中的$ionicPlatform.ready事件中的通用设置
Jun 11 Javascript
JS前端可扩展的低代码UI框架Sunmao使用详解
Jul 23 Javascript
浅析JS异步加载进度条
May 05 #Javascript
AngularJS入门(用ng-repeat指令实现循环输出
May 05 #Javascript
图文详解Heap Sort堆排序算法及JavaScript的代码实现
May 04 #Javascript
一分钟理解js闭包
May 04 #Javascript
学JavaScript七大注意事项【必看】
May 04 #Javascript
Jquery ui datepicker设置日期范围,如只能隔3天【实现代码】
May 04 #Javascript
开启BootStrap学习之旅
May 04 #Javascript
You might like
php数据库连接
2006/10/09 PHP
模仿OSO的论坛(一)
2006/10/09 PHP
php 模拟POST|GET操作实现代码
2010/07/20 PHP
DEDE采集大师官方留后门的删除办法
2011/01/08 PHP
php实现构建排除当前元素的乘积数组方法
2018/10/06 PHP
解决laravel 出现ajax请求419(unknown status)的问题
2019/09/03 PHP
删除select中所有option选项jquery代码
2013/08/12 Javascript
javascript中实现兼容JAVA的hashCode算法代码分享
2020/08/11 Javascript
javascript实现带节日和农历的日历特效
2015/02/01 Javascript
jQuery操作表单常用控件方法小结
2015/03/23 Javascript
AngularJs $parse、$eval和$observe、$watch详解
2016/09/21 Javascript
AngularJS ng-repeat数组有重复值的解决方法
2016/10/23 Javascript
浅谈jQuery hover(over, out)事件函数
2016/12/03 Javascript
微信小程序 Toast自定义实例详解
2017/01/20 Javascript
利用Three.js如何实现阴影效果实例代码
2017/09/26 Javascript
对angularJs中$sce服务安全显示html文本的实例
2018/09/30 Javascript
微信小程序如何实现精确的日期时间选择器
2020/01/21 Javascript
详解小程序横屏方案对比
2020/06/28 Javascript
微信小程序对图片进行canvas压缩的方法示例详解
2020/11/12 Javascript
python爬虫框架scrapy实战之爬取京东商城进阶篇
2017/04/24 Python
python使用正则表达式的search()函数实现指定位置搜索功能
2017/11/10 Python
selenium + python 获取table数据的示例讲解
2018/10/13 Python
python tkinter组件使用详解
2019/09/16 Python
python 实现检验33品种数据是否是正态分布
2019/12/09 Python
Python实现非正太分布的异常值检测方式
2019/12/09 Python
传播学毕业生求职信
2013/10/11 职场文书
八一建军节活动方案
2014/02/10 职场文书
新闻学专业大学生职业生涯规划范文
2014/03/02 职场文书
党校个人自我鉴定范文
2014/03/28 职场文书
文明演讲稿范文
2014/05/12 职场文书
公司员工活动策划方案
2014/08/20 职场文书
乡镇党的群众路线对照检查材料
2014/09/24 职场文书
机关干部个人对照检查材料思想汇报
2014/09/28 职场文书
物业客服专员岗位职责
2015/04/07 职场文书
使用python向MongoDB插入时间字段的操作
2021/05/18 Python
Java GUI编程菜单组件实例详解
2022/04/07 Java/Android