JavaScript でゲッターとセッターを使用するのはなぜ悪いのでしょうか?

黄舟
リリース: 2017-07-18 16:08:01
オリジナル
1516 人が閲覧しました

ご存知のとおり、ゲッターとセッターは JavaScript の一部になりました。これらは、IE8 を含むすべての主要なブラウザを幅広くサポートしています。

この考えは一般的に間違っているとは思いませんが、JavaScriptにはあまり適していないと思います。ゲッターとセッターはコードを簡素化し、時間を節約するように見えるかもしれませんが、実際には、一見しただけではわからない隠れたエラーが発生します。

ゲッターとセッターはどのように機能しますか?

まず、これらの概要を簡単に説明します。

動的に計算された値を返すプロパティへのアクセスを許可したい場合や、明示的なメソッド転送を使用せずに内部変数の状態を反映したい場合があります。

それらがどのように機能するかを説明するために、firstName と lastName という 2 つのプロパティと、fullName という計算値を持つ person オブジェクトを見てみましょう。

var obj = {
  firstName: "Maks",
  lastName: "Nemisj"
}
ログイン後にコピー

計算された値 fullName は、firstName と lastName を連結したものを返します。

Object.defineProperty(person, 'fullName', {
  get: function () {
    return this.firstName + ' ' + this.lastName;
  }
});
ログイン後にコピー

fullName の計算値を取得するには、person.fullName() のような恐ろしい括弧は必要なく、単純な var fullName = person.fullName を使用するだけです。

同じことがセッターにも当てはまり、関数を使用して値を設定できます:

Object.defineProperty(person, 'fullName', {
  set: function (value) {
    var names = value.split(' ');
    this.firstName = names[0];
    this.lastName = names[1];
  }
});
ログイン後にコピー

使い方はゲッターと同じくらい簡単です: person.fullName = 'Boris Gorbachev'。これにより、上記で定義された関数が呼び出され、ボリス ゴルバチョフが firstName と lastName に分離されます。

何が問題ですか?

「ゲッター メソッドとセッター メソッドが好きです。JSON のように自然な感じがします。その通りです。しかし、一歩下がって、fullName がどのようにゲッターとセッター メソッドを実行するのかを見てみましょう。」セッターは以前に働いていました。

値を取得するには getFullName() のようなものを使用し、値を設定するには person.setFullName(‘Maks Nemisj’) を使用します。

関数名のスペルが間違っていて、person.getFullName() が person.getFulName() と書かれている場合はどうなりますか?

JavaScript でエラーが発生します:

person.getFulName();
       ^
TypeError: undefined is not a function
ログイン後にコピー

このエラーは、適切なタイミングで適切な場所でトリガーされます。関数が存在しないオブジェクトにアクセスするとエラーが発生しますが、これは問題ありません。

それでは、間違った名前のセッターを使用すると何が起こるか見てみましょう?

うーん

何もない。オブジェクトは拡張可能であり、キーと値を動的に割り当てることができるため、実行時にエラーがスローされません。

このような動作は、タイプミスではなく、ユーザー インターフェイスのどこかにエラーが表示されるか、間違った値に対して何らかの操作が実行された場合にエラーが表示される可能性があることを意味します。

過去に発生したはずなのに将来のコード フローに現れるバグを追跡するのはとても興味深いです。

シールは可能ですか?

この問題は、sealAPI を使用することで部分的に解決できます。オブジェクトがシールされている限り、オブジェクトを変更することはできません。つまり、fulName は person オブジェクトに新しいキーを割り当てようとしますが、失敗します。

何らかの理由で、これを Node.js V4.0 でテストしたところ、期待どおりに動作しませんでした。したがって、この解決策を保証することはできません。

そしてさらにイライラするのは、セッターについてはまったく解決策がないことです。前に述べたように、オブジェクトは拡張可能でフェイルセーフです。つまり、存在しないキーにアクセスしてもエラーは発生しません。

この状況がオブジェクト リテラルにのみ当てはまるのであれば、この記事をわざわざ書く必要はありませんが、ECMAScript 2015 (ES6) とクラスを使用してゲッターとセッターを定義する機能が登場した後、潜在的な落とし穴について書くことにしました。ブログ。

クラスの登場

現在、一部の JavaScript コミュニティではクラスがあまり人気がないことは承知しています。 JavaScript などの関数型/プロトタイプベースの言語でそれらが必要かどうかについては、人々が議論しています。ただし、実際には、クラスは ECMAScript 2015 (ES6) 仕様に含まれており、しばらくの間は存在する予定です。

私にとって、クラスは、クラスの外部世界 (コンシューマ) とアプリケーションの内部世界との間で明確に定義された API を指定する方法です。これはルールを白黒はっきりさせる抽象的なものであり、これらのルールはすぐには変更されないと考えられます。

人物オブジェクトを改良し、実際のクラスを作成します。 Person は、fullName を取得および設定するためのインターフェイスを定義します。

person.fulName = 'Boris Gorbachev';
ログイン後にコピー

このクラスは厳密なインターフェイス記述を定義していますが、ゲッター メソッドとセッター メソッドによって厳密さが緩和されます。私たちは、オブジェクト リテラルを扱う際の肥大化したエラーや、JSON を扱う際のキーのスペルミスに慣れています。少なくともクラスをもっと厳密にして、その意味で開発者により良いフィードバックを提供できるといいのですが。

ただし、この状況はクラスでゲッターとセッターを定義する場合も変わりません。しかし、誰かがスペルを間違えるのを止めることはできません。

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  getFullName() {
    return this.firstName + ' ' + this.lastName;
  }
  setFullName(value) {
    var names = value.split(' ');
    this.firstName = names[0];
    this.lastName = names[1];
  }
}
ログイン後にコピー

タイプミスのある実行ではエラーは発生しません:

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  get fullName() {
    return this.firstName + ' ' + this.lastName;
  }
  set fullName(value) {
    var names = value.split(' ');
    this.firstName = names[0];
    this.lastName = names[1];
  }
}
ログイン後にコピー

同じ緩慢で冗長で追跡不可能な動作がエラーを引き起こす可能性があります。

在我发现这一点后,我有一个问题:在使用getter和setter的时候,有没有什么可以做的,以便于使得类更严格?我发现:有是肯定有,但是这值得吗?增加额外层次的复杂性到代码就只是为了使用数量更少的括号?对于API定义,也可以不使用getter和setter,而这样一来就能解决这个问题。除非你是一个铁杆开发人员,并愿意继续进行,不然还有另一种解决方案,如下所述。

proxy来帮助?

除了getter和setter方法,ECMAScript 2015(ES6)还自带proxy对象。proxy可以帮助你确定委托方法,这些委托方法可以在实际访问键执行之前,用来执行各种操作。事实上,它看起来像动态getter / setter方法。

proxy对象可以用来捕捉任何到类的实例的访问,并且如果在类中没有找到预先定义的getter或setter就会抛出错误。

为了做到这一点,必须执行下面两个操作:

  • 创建基于Person原型的getter和setter清单。

  • 创建将测试这些清单的Proxy对象。

让我们来实现它。

首先,为了找出什么样的getter和setter方法可以用在类Person上,可以使用getOwnPropertyNames和getOwnPropertyDescriptor:

var names = Object.getOwnPropertyNames(Person.prototype);
var getters = names.filter((name) => {
  var result =  Object.getOwnPropertyDescriptor(Person.prototype, name);
  return !!result.get;
});
var setters = names.filter((name) => {
  var result =  Object.getOwnPropertyDescriptor(Person.prototype, name);
  return !!result.set;
});
ログイン後にコピー

在此之后,创建一个Proxy对象:

var handler = {
  get(target, name) {
    if (getters.indexOf(name) != -1) {
      return target[name];
    }
    throw new Error('Getter "' + name + '" not found in "Person"');
  },
  set(target, name) {
    if (setters.indexOf(name) != -1) {
      return target[name];
    }
    throw new Error('Setter "' + name + '" not found in "Person"');
  }
};
person = new Proxy(person, handler);
ログイン後にコピー

现在,只要你尝试访问person.fulName,就会显示Error: Getter “fulName” not found in “Person”的消息。

以上がJavaScript でゲッターとセッターを使用するのはなぜ悪いのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!