質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.39%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

486閲覧

JavaScript ではどんな処理のときに prototype を使って拡張すべきなのか

munekun

総合スコア64

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2024/07/25 02:57

編集2024/07/25 03:00

拡張とフツーの関数

これまではフツーの関数でしか処理を宣言したことがありませんでしたが、Array.prototype.●● = 処理 という記述によって、Arrayオブジェクトに●●という処理を根本的に登録する、いわゆる拡張なる機能があるらしいと知りました。

でもそれじゃ一体、いつ拡張を登録すべきで、いつフツーの関数を宣言すべきなのでしょうか?

考えた例

例えば以下の例 (insertAndTrimという拡張と insertAndTrimArrayというフツーの関数) を考えてみたのですが、どちらがいつ便利なのかよく分かりません。

拡張

登録

JavaScript

1/*---------------------------------------- 2 arrayExtensions.js 3----------------------------------------*/ 4 5(function () { 6 'use strict'; 7 8 Array.prototype.insertAndTrim = function(value, { index = 0, maxCount = null } = {}) { 9 this.splice(index, 0, value); 10 if (maxCount) { 11 return this.slice(0, maxCount); 12 } 13 return this; 14 }; 15 16})();

利用

JavaScript

1/*---------------------------------------- 2 test.js 3----------------------------------------*/ 4 5let arr = [1, 2, 3]; 6arr.insertAndTrim(4, { index: 1, maxCount: 4 }); 7console.log(arr); // [1, 4, 2, 3]

フツーの関数

宣言

JavaScript

1/*---------------------------------------- 2 arrayUtils.js 3----------------------------------------*/ 4export function insertAndTrimArray(arr, value, { index = 0, maxCount = null } = {}) { 5 arr.splice(index, 0, value); 6 if (maxCount) { 7 arr = arr.slice(0, maxCount); 8 } 9 return arr; 10}

利用

JavaScript

1/*---------------------------------------- 2 test.js 3----------------------------------------*/ 4 5import { insertAndTrimArray } from './arrayUtils.js'; 6 7let arr = [1, 2, 3]; 8arr = insertAndTrimArray(arr, 4, { index: 1, maxCount: 4 }); 9console.log(arr); // [1, 4, 2, 3]

補足

・ES2015(ES6) の利用です。
・拡張も関数の一種なのかもしれませんが区別する正しい呼称を知らないので、当質問では「フツーの関数を宣言する」と「拡張を登録する」とさせて頂きました。
・どうやら Object は拡張すべきでないらしい のですが、それ以外 (上記のような Array や Storage や String などなど) についてはいつ拡張での登録を利用すべきなのか知りたいです。

よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

prototypeで継承するのは、prototype汚染と呼ばれ、自分が作成したオブジェクトなど以外には、使用しない方がよいです。
一時期、「prototype汚染」が問題になったことがあり、その時からJavaScriptプログラマーだった人は、みな使ってはいけないテクニックだ、ということを学んでいます。

なので、Object であろうと Array であろうと、prototype継承というか、prototypeで拡張させる、ということは、できるけど、やってはいけないテクニックというものになります。

また、さらに言えば、継承というもの自体が「やってはいけない」というまでのことではないですが、使う必要のない不要なテクニックなので、prototypeなどはそもそも使わなくてよくて、使わない方がより腕が良いプログラマーになれると思います。

投稿2024/07/25 03:28

sa-yama

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2024/07/25 04:17

prototypeに書き込む使い方が悪影響しないような例外としては、「Ecmaの標準で後から追加されたけど、環境にはない関数を補う場合」程度です。
munekun

2024/07/25 08:08

ありがとうございます。そういう問題があったというのは知っておかないとまずかったですね。共通認識を教えていただきありがとうございます。使わないように気を付けます。
guest

0

ベストアンサー

prototypeをいじった場合、複数のプロジェクトで競合する可能性が高いので既存の要素には原則使わないに越したことはありません。ユーザーが作成したクラスにもprototype設定はできるので場合によっては対応してもよいですが、普通にコンストラクタで指定する方が効率的でしょう

javascript

1class myClass{ 2 constructor(n=null){ 3 this.a=1; 4 if(n)this.b=n; 5 } 6} 7const test1=new myClass; 8const test2=new myClass(100); 9console.log([test1.a,test1.b,test1.c]); //この時点ではb,cは未設定 10console.log([test2.a,test2.b,test2.c]); //この時点ではcは未設定 11myClass.prototype.b=2; 12myClass.prototype.c=3; 13console.log([test1.a,test1.b,test1.c]); //prototypeを変更する前のインスタンスにも反映されb,cが設定 14console.log([test2.a,test2.b,test2.c]); //prototypeを変更する前のインスタンスにも反映されcが設定 15const test3=new myClass; 16const test4=new myClass(100); 17console.log([test3.a,test3.b,test3.c]); //test1と同値 18console.log([test4.a,test4.b,test4.c]); //test2と同値

※ちょっと意図が伝わりづらかったのでコメントをつけておきます

投稿2024/07/25 03:15

編集2024/07/25 03:32
yambejp

総合スコア116220

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

munekun

2024/07/25 08:07

ありがとうございます。突然クラスが出てきて一瞬なんのことかわからず焦りましたが、クラス、コンストラクタ、prototype、の関係などまったく理解しておりませんでしたので、良い機会になりました。
guest

0

いろいろな考え方がありますが、いわゆるビルトインオブジェクトのプロトタイプを拡張するのは、可能なかぎり避けるべきです。

どうしても、ということであれば、Symbolを使えば多少はマシになるかもしれません。Symbol("Symbol") === Symbol("Symbol")が真にならないという特徴があるため、プロパティ名の衝突が起きないのです。
(意図的に衝突しようと思えばできないこともないですが)

投稿2024/07/25 04:39

Lhankor_Mhy

総合スコア36791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

munekun

2024/07/25 08:09

ありがとうございます。やはりみなさん使わない派なのですね。Symbolなど初耳テクで勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.39%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問