ホームページ  >  記事  >  ウェブフロントエンド  >  JS がゲッター + セッターの概要を追加

JS がゲッター + セッターの概要を追加

php中世界最好的语言
php中世界最好的语言オリジナル
2018-06-12 09:36:221973ブラウズ

今回はJSにgetter+setterを追加する際の注意点をまとめてお届けします。実際の事例を見てみましょう。

ゲッターとセッターを定義する

1. オブジェクト初期化子を通じてオブジェクトを作成するときに指定します (リテラル値を通じてオブジェクトを作成するときに宣言することもできます)

(function () {
  var o = {
    a : 7,
    get b(){return this.a +1;},//通过 get,set的 b,c方法间接性修改 a 属性
    set c(x){this.a = x/2}
  };
  console.log(o.a);
  console.log(o.b);
  o.c = 50;
  console.log(o.a);
})();

Chrome でのデバッグ ビューは次のとおりです:

JS がゲッター + セッターの概要を追加

はい。オブジェクトの下にさらに get 属性と set 属性があることを確認します。出力結果は次のとおりです。 get 属性以及 set 属性
输出结果如下:

JS がゲッター + セッターの概要を追加

当然 get 语句与 set 语句可以声明多次用来对应多个 gettersetter<br>使用这种方法的好处是可以在声明属性的时候同时声明对应的 gettersetter<br>

画像の説明

もちろん get ステートメントです set ステートメントを使用できます。宣言は複数の gettersetter<p></p> に対応するために複数回使用されます。このメソッドを使用する利点は次のとおりです。対応する getter は、プロパティを宣言するときに同時に宣言できます。 > および setter<img title="JS がゲッター + セッターの概要を追加" alt="JS がゲッター + セッターの概要を追加" src="https://img.php.cn/upload/article/000/000/002/293b54b05b8f0f10949affc2fe15a19b-2.png"> ここで、o オブジェクトの get メソッドと set メソッドのメソッド名を使用できるかどうかを尋ねた人がいます。を「a」に変更すると、直接操作するために「.」を通じてメソッドに直接アクセスできるようになります。

Chrome を開いて、作成されたビューを表示します。

JS がゲッター + セッターの概要を追加

この時点では上記とは異なりますが、それらは本当に機能しますか? 答えは「いいえ」です。o.a を渡すと、 get ステートメントで宣言された a メソッドが呼び出されます。このメソッドに入ると、 this.a メソッドが見つかります。メソッドが呼び出され続けて無限ループが形成され、最終的には無限ループとメモリ オーバーフロー エラーが発生します。

新しい構文 (ES6): 現在、Firefox でのみサポートされており、他のブラウザではエラーが報告されます

(function () {
  var o = {
    a : 7,
    get a(){return this.a +1;},//死循环
    set a(x){this.a = x/2}
  };
  console.log(o.a);
  console.log(o.b);
  o.c = 50;
  console.log(o.a);
})();
JS がゲッター + セッターの概要を追加 Firefox を開いてデバッグを表示します:

出力結果は次のとおりです:


2. Object.create メソッド


MDN からの引用:


概要
Object.create() メソッドは、指定されたプロトタイプといくつかの指定されたプロパティを持つオブジェクトを作成します。

構文

Object.create(proto, [propertiesObject ])

JS がゲッター + セッターの概要を追加

Object.create メソッドを使用してパラメーターを渡す場合、そのパラメーターをプロトタイプとして使用してオブジェクトを作成できることは誰もが知っています。 JS でオブジェクトを作成する 8 つのモード

2 番目のパラメータはオプションであり、パラメータ オブジェクトは属性と値のセットであり、新しく作成されるオブジェクトの属性名になります。属性記述子 (拡張データ記述子を含む) です。属性記述子の詳細については、次のコンテンツを参照してください)。
プロパティ記述子を通じて、新しく作成されたオブジェクトに get メソッドと set メソッドを追加できます

(function () {
  var b = "bb";
  var c = "cc";
  var o = {
    a : 7,
    get [b](){return this.a +1;},
    set [c](x){this.a = x/2},
  };
  console.log(o.a);
  console.log(o[b]);
  o["cc"] = 50;
  console.log(o.a);
})();

Chrome でのデバッグ試行は次のとおりです: JS がゲッター + セッターの概要を追加

新しく作成されたオブジェクトには、より一般的な get 属性と set 属性があることがわかります

出力結果は次のようになります

JS がゲッター + セッターの概要を追加

上記の例は、get メソッドと set メソッドで使用される属性には使用されません

(function () {
  var o = null;
  o = Object.create(Object.prototype,//指定原型为 Object.prototype
      {
        bar:{
          get :function(){
            return 10;
          },
          set : function (val) {
            console.log("Setting `o.bar` to ",val);
          }
        }
      }//第二个参数
    );
  console.log(o.bar);
  o.bar = 12;
})();

または:

(function () {
  var o = null;
  o = Object.create(Object.prototype,//指定原型为 Object.prototype
      {
        bar:{
          get :function(){
            return this.a;
          },
          set : function (val) {
            console.log("Setting `o.bar` to ",val);
            this.a = val;
          },
          configurable :true
        }
      }//第二个参数
    );
  o.a = 10;
  console.log(o.bar);
  o.bar = 12;
  console.log(o.bar);
})();
出力結果は次のとおりです:

このメソッドを使用する利点構成可能で高性能ですが、初心者は混乱しやすいという点です。



3. Object.defineProperty メソッドを使用する


MDN の引用:


概要
Object.defineProperty() メソッドは、オブジェクトの新しいプロパティを直接定義するか、既存のプロパティを変更して、オブジェクトを返します。
構文

Object.defineProperty(obj, prop, descriptor)
パラメータ

obj

プロパティを定義する必要があるオブジェクト。

prop

定義または変更する必要があるプロパティ名。

descriptor 定義または変更する必要がある属性の記述子。

(function () {
  var o = {a:10};
  o = Object.create(o,//指定原型为 o 这里实际可以理解为继承
      {
        bar:{
          get :function(){
            return this.a;
          },
          set : function (val) {
            console.log("Setting `o.bar` to ",val);
            this.a = val;
          },
          configurable :true
        }
      }//第二个参数
    );
  console.log(o.bar);
  o.bar = 12;
  console.log(o.bar);
})();

このメソッドと前の 2 つのメソッドの違いは、前の 2 つのメソッドを使用すると、定義を宣言するときにのみゲッターとセッターを指定できることです。このメソッドを使用すると、それらをいつでも追加または変更できます。

🎜ゲッターとセッターを一度に追加する必要がある場合は、次のメソッドを使用しても問題ありません: 🎜🎜🎜4. Object.defineProperties メソッドを使用します🎜🎜🎜MDN: 🎜

概述
Object.defineProperties() 方法在一个对象上添加或修改一个或者多个自有属性,并返回该对象。
语法
Object.defineProperties(obj, props)
参数
obj
将要被添加属性或修改属性的对象
props
该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置

不难看出用法与 Object.defineProperty 方法类似

(function () {
  var obj = {a:1,b:"string"};
  Object.defineProperties(obj,{
    "A":{
      get:function(){return this.a+1;},
      set:function(val){this.a = val;}
    },
    "B":{
      get:function(){return this.b+2;},
      set:function(val){this.b = val}
    }
  });

  console.log(obj.A);
  console.log(obj.B);
  obj.A = 3;
  obj.B = "hello";
  console.log(obj.A);
  console.log(obj.B);
})();

输出结果如下:

JS がゲッター + セッターの概要を追加

5.使用 Object.prototype.__defineGetter__ 以及 Object.prototype.__defineSetter__ 方法

(function () {
  var o = {a:1};
  o.__defineGetter__("giveMeA", function () {
    return this.a;
  });
  o.__defineSetter__("setMeNew", function (val) {
    this.a = val;
  })
  console.log(o.giveMeA);
  o.setMeNew = 2;
  console.log(o.giveMeA);
})();

输出结果为1和2
查看 MDN 有如下说明:

JS がゲッター + セッターの概要を追加

什么是属性描述符

MDN:

对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。

  1. 数据描述符是一个拥有可写或不可写值的属性。

  2. 存取描述符是由一对 getter-setter 函数功能来描述的属性。

  3. 描述符必须是两种形式之一;不能同时是两者。

数据描述符和存取描述符均具有以下可选键值:

configurable
当且仅当这个属性描述符值为 true 时,该属性可能会改变,也可能会被从相应的对象删除。默认为 false。
enumerable
true 当且仅当该属性出现在相应的对象枚举属性中。默认为 false。

数据描述符同时具有以下可选键值:

value
与属性相关的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。
writable
true 当且仅当可能用 赋值运算符 改变与属性相关的值。默认为 false。

存取描述符同时具有以下可选键值:

get
一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。方法将返回用作属性的值。默认为 undefined。
set
一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将收到作为唯一参数的新值分配给属性。默认为 undefined。

以上是摘自MDN的解释,看起来是很晦涩的,具体什么意思呢:
首先我们从以上解释知道该匿名参数对象有个很好听的名字叫属性描述符,属性描述符又分成两大块:数据描述符以及存取描述符(其实只是一个外号,给指定的属性集合起个外号)。

数据描述符包括两个属性 : value 属性以及 writable 属性,第一个属性用来声明当前欲修饰的属性的值,第二个属性用来声明当前对象是否可写即是否可以修改

存取描述符就包括 get 与 set 属性用来声明欲修饰的象属性的 getter 及 setter

属性描述符内部,数据描述符与存取描述符只能存在其中之一,但是不论使用哪个描述符都可以同时设置 configurable 属性以及enumerable 属性。
configurable属性用来声明欲修饰的属性是否能够配置,仅有当其值为 true 时,被修饰的属性才有可能能够被删除,或者重新配置。
enumerable 属性用来声明欲修饰属性是否可以被枚举。

知道了什么是属性描述符,我们就可以开始着手创建一些对象并开始配置其属性

创建属性不可配置不可枚举的对象

//使用默认值配置
(function () {
  var obj = {};//声明一个空对象
  Object.defineProperty(obj,"key",{
    value:"static"
            //没有设置 enumerable 使用默认值 false
            //没有 configurable 使用默认值 false
            //没有 writable 使用默认值 false
  });

  console.log(obj.key);      //输出 “static”
  obj.key = "new"         //尝试修改其值,修改将失败,因为 writable 为 false
  console.log(obj.key);      //输出 “static”
  obj.a = 1;//动态添加一个属性
  for(var item in obj){ //遍历所有 obj 的可枚举属性
     console.log(item);
  }//只输出一个 “a” 因为 “key”的 enumerable为 false
})();
//显示配置 等价于上面
(function () {
  var obj = {};
  Object.defineProperty(obj,"key",{
    enumerable : false,
    configurable : false,
    writable : false,
    value : "static"
  })
})();
//等价配置
(function () {
  var o = {};
  o.a = 1;
  //等价于
  Object.defineProperty(o,"a",{value : 1,
                writable : true,
                configurable : true,
                enumerable : true});
  
  Object.defineProperty(o,"a",{value :1});
  //等价于
  Object.defineProperty(o,"a",{value : 1,
                writable : false,
                configurable : false,
                enumerable : false});
})();

Enumerable 特性
属性特性 enumerable 决定属性是否能被 for...in 循环或 Object.keys 方法遍历得到

(function () {
  var o = {};
  Object.defineProperty(o,"a",{value :1,enumerable :true});
  Object.defineProperty(o,"b",{value :2,enumerable :false});
  Object.defineProperty(o,"c",{value :2});//enumerable default to false
  o.d = 4;//如果直接赋值的方式创建对象的属性,则这个属性的 enumerable 为 true

  for(var item in o){ //遍历所有可枚举属性包括继承的属性
    console.log(item);
  }

  console.log(Object.keys(o));//获取 o 对象的所有可遍历属性不包括继承的属性

  console.log(o.propertyIsEnumerable(&#39;a&#39;));//true
  console.log(o.propertyIsEnumerable(&#39;b&#39;));//false
  console.log(o.propertyIsEnumerable(&#39;c&#39;));//false
})();

输出结果如下:

JS がゲッター + セッターの概要を追加

Configurable 特性

(function () {
  var o = {};
  Object.defineProperty(o,"a",{get: function () {return 1;},
                configurable : false} );
                //enumerable 默认为 false,
                //value 默认为 undefined,
                //writable 默认为 false,
                //set 默认为 undefined
                 
  //抛出异常,因为最开始定义了 configurable 为 false,故后期无法对其进行再配置
  Object.defineProperty(o,"a",{configurable : true} );
  //抛出异常,因为最开始定义了 configurable 为 false,故后期无法对其进行再配置,enumerable 的原值为 false
  Object.defineProperty(o,"a",{enumerable : true} );
  //抛出异常,因为最开始定义了 configurable 为 false,set的原值为 undefined
  Object.defineProperty(o,"a",{set : function(val){}} );
  //抛出异常,因为最开始定义了 configurable 为 false,故无法进行覆盖,尽管想用一样的来覆盖
  Object.defineProperty(o,"a",{get : function(){return 1}});
  //抛出异常,因为最开始定义了 configurable 为 false,故无法将其进行重新配置把属性描述符从存取描述符改为数据描述符
  Object.defineProperty(o,"a",{value : 12});

  console.log(o.a);//输出1
  delete o.a;   //想要删除属性,将失败
  console.log(o.a);//输出1
  
})();

提高及扩展
1.属性描述符中容易被误导的地方之 writable 与 configurable

(function () {
  var o = {};
  Object.defineProperties(o,{
    "a": {
      value:1,
      writable:true,//可写
      configurable:false//不可配置
      //enumerable 默认为 false 不可枚举
    },
    "b":{
      get :function(){
        return this.a;
      },
      configurable:false
    }
  });
  console.log(o.a);  //1
  o.a = 2;      //修改值成功,writable 为 true
  console.log(o.a);  //2
  Object.defineProperty(o,"a",{value:3});//同样为修改值成功
  console.log(o.a);  //3

  //将其属性 b 的属性描述符从存取描述符重新配置为数据描述符
  Object.defineProperty(o,"b",{value:3});//抛出异常,因为 configurable 为 false
})();

2.通过上面的学习,我们都知道传递属性描述符参数时,是定义一个匿名的对象,里面包含属性描述符内容,若每定义一次便要创建一个匿名对象传入,将会造成内存浪费。故优化如下:

(function () {
  var obj = {};

  //回收同一对象,即减少内存浪费
  function withValue(value){
    var d = withValue.d ||(
      withValue.d = {
        enumerable : false,
        configurable : false,
        writable : false,
        value :null
      }
      );
    d.value = value;
    return d;
  }
  Object.defineProperty(obj,"key",withValue("static"))
})();

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

FileReader API的使用

vue内置指令方法与事件

以上がJS がゲッター + セッターの概要を追加の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。