JavaScript ECAMScript5 新特性——get/set访问器
之前对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(无初始值),通过浏览器控制台可以看到

那么这个name属性实在什么时候定义的呢?我们知道Object.defineProperty(object,pro,{})可以给对象定义一个新属性pro,既然get pro(){}/set pro(){}和Object.defineProperty(object,pro,{})等效,则也会定义一个新属性pro .这就是为什么object里面有两个属性的原因。
   (3)学习博客http://kb.cnblogs.com/page/75072/中关于标准标准的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(){}属性 可读不可写;
在prototype里面定义的value属性,定义了get 特性。依然可以控制value属性的读写 。也就是说obj.value访问属性时,会调用get方法,先在对象本身寻找,如果没有,再到prototype寻找,如果都没有才算没有定义,默认的既可读又可写。
补充:


经大神指正,明白为什么这里报错:在get value(){}方法里返回 this.value,就会又去调用value的get 方法,因此陷入死循环,造成方法栈溢出。
JavaScript ECAMScript5 新特性——get/set访问器的更多相关文章
- JavaScript中的Get和Set访问器
		今天要和大家分享的是JavaScript中的Get和Set访问器,和C#中的访问器非常相似. 标准的Get和Set访问器的实现 function Field(val){ this.va ... 
- 【SharePoint学习笔记】第3章 SharePoint列表新特性以及数据访问
		第3章 SharePoint列表新特性以及数据访问 使用CAML查询语言 CAML:协作应用程序标记语言 Collaboration Application Markup Language ... 
- JavaScript 属性类型(数据属性和访问器属性)
		数据属性 数据属性包含一个数据值的位置.在这个位置可以读取和写入值.数据属性有 4 个描述其行为的特性. [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修 ... 
- ES6新特性:Proxy代理器
		ES6新特性:Proxy: 要使用的话, 直接在浏览器中执行即可, node和babel目前还没有Proxy的polyfill;,要使用的话,直接在浏览器中运行就好了, 浏览器的兼容性为:chrome ... 
- javascript ES6 新特性之 扩展运算符 三个点 ...
		对于 ES6 新特性中的 ... 可以简单的理解为下面一句话就可以了: 对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中. 作用类似于 Object.assign() ... 
- JavaScript ES6 新特性详解
		JavaScript ES6 带来了新的语法和新的强大功能,使您的代码更现代,更易读 const , let and var 的区别: const , let 是 ES6 中用于声明变量的新关键字. ... 
- javascript ES6 新特性之 let
		let的作用是声明变量,和var差不多. let是ES6提出的,在了解let之前,最好先熟悉var的原理. JavaScript有一个机制叫“预解析”,也可以叫“提升(Hoisting)机制”.很多刚 ... 
- JavaScript 的新特性:类的 #private 字段
		这是什么,如何使用,为什么需要? 一边听“Noise Pollution” —— Portugal. The Man,一边阅读本文简直就是享受 JavaScript 标准的第二阶段(Stage 2)加 ... 
- JavaScript ES6新特性介绍
		介绍 ES6:ECMScript6 首先,一个常见的问题是,ECMAScript 和 JavaScript 到底是什么关系? ECMAScript是一个国际通过的标准化脚本语言: JavaScript ... 
随机推荐
- win32 sdk显示一个载入的位图的方法
			注:整理自网络文档 (1)加载位图 HANDLE LoadImage(HINSTANCE 来源实体,LPCTSTR 名称,UINT 位图类型, int 加载宽度,int 加载高度,UINT 加载方式) ... 
- 宣讲ppt的技巧
			这是一个L运营商的项目,项目规模比较大,中兴的客户群体定位主要是电信运营商,运营商的项目做起来非常累,不是一般的小公司能玩的,一般项目要经过这几个过程,前期信息获得——技术交流引导——实验局测试——投 ... 
- java无符号移位(>>>)和有符号移位(>>)
			java中>>(<<)表示有符号的移位.<<<(>>>)表示无符号移位 如: int num = 22; 二进制是0001 0110, nu ... 
- Session invalidate
			会清空所有已定义的session 而不是清空全部session的值也就是说 定义了一个名为 user 的session 调用invalidate()方法后使用Session.getValue(“use ... 
- Java下Web MVC的领跑者:SpringMVC
			比较常用的MVC框架有Struts 和 SpringMVC. Struts 是Java Web MVC框架中曾经不争的王者.经过长达九年的发展,Struts占有了MVC框架中最大的市场份额.但是Str ... 
- 提取html中的src 路径
			/// <summary> /// 替换body中的img src属性 附加上域名 /// </summary> /// <param name="str&qu ... 
- 学习Linux第三天
			1.常用的命令: reset 清屏 leave +hhmm 建立离开提醒 sudo apt-get yum 安装yum程序 sudo su 切换root身份 see test.c 可以直接查看文件,神 ... 
- mailx 乱码,sendmail发html邮件,脚本开机启动
			echo "yes"|mailx -s "我" -S ttycharset=utf-8 -S sendcharsets=utf-8 -S encoding=ut ... 
- 在线最优化求解(Online Optimization)之五:FTRL
			在线最优化求解(Online Optimization)之五:FTRL 在上一篇博文中中我们从原理上定性比较了L1-FOBOS和L1-RDA在稀疏性上的表现.有实验证明,L1-FOBOS这一类基于梯度 ... 
- Metasploit命令大全
			Metasploit是一款开源的安全漏洞检测工具,可以帮助安全和IT专业人士识别安全性问题,验证漏洞的缓解措施,并管理专家驱动的安全性进行评估,提供真正的安全风险情报.这些功能包括智能开发,密码审计, ... 
