モジュールパターンの場合、次のようなことをしています。
_(function(namespace) {
// tons of code
// blabla
})(window.myGlobalNamespace);
_
コードを分割するにはどうすればよいですか?名前空間の階層を使用したり、window.myGlobalNamespace.additionalFunc = function () {//blabla}
によってオブジェクトを外部に展開したりするなど、いくつかの方法を考えることができます。他の方法は何ですか?長所と短所は何ですか?どちらがより良い習慣と考えられていますか?
2つの答えはどちらもRequireJSを示唆しています。 RequireJSがこれらの問題をどのように解決できるか説明していただけますか?
first.js:
_(function(context) {
var parentPrivate = 'parentPrivate';
})(window.myGlobalNamespace);
_
second.js:
_(function(context) {
this.childFunction = console.log('trying to access parent private field: ' + parentPriavte);
}(window.myGlobalNamespace.subNamspace);
_
main.js:
_window.myGlobalNamespace.subNamspace.childFunction(); // doesn't work
_
そして人々はできる
_window.myGlobalNamespace.subNamspace.childFunction = function() {alert("a new function");}
_
私のコードの振る舞いを変えるために!
ここでは、2つの問題があります。
子供がアクセスできるが、外部の人はアクセスできない(つまり保護されている)フィールドを作成することはできません。それを達成する方法はありますか?
そうでない場合、つまり、eparentPrivateにアクセスできるようにする場合は、公開する必要があります。その後、ユーザーはそれを変更できるようになります!
さらに、すべてのパブリック関数を変更および置換できます。私はそれが起こらないようにしたい。
RequireJSがこれらの問題をどのように解決するのかわかりません。誰かが光を当てることはできますか?
JavaScriptをHTMLに取り込む方法は2つしかありません。
<script> some JavaScript </script>
<script src='main.js'></script>
これは明らかですが、次に来るものには共通の基盤が必要です。 ;)
JavaScriptには、他のJavaScriptファイルを自分自身に「インポート」する機能はありません。すべての「インポート」はHTMLで行われます。これはいくつかの方法で実行できます。
JavaScriptを介して動的にリンク
var script = document.createElement("script");
script.src = "all.js";
document.documentElement.firstChild.appendChild(script);
Librarylike RequireJS 。 RequireJSは 非同期モジュール定義(AMD)API を使用します。これは、モジュールとその依存関係を非同期にロードできるようにモジュールを定義するためのJavaScriptメカニズムです。
JavaScriptを別々のファイルに分割する理由を検討することは重要です。
個別のJavaScriptファイルしないでください物事を作成しますプライベート、クロージャは物事をプライベートにします。
さて、一日の終わりにすべてが本番環境の準備ができたら、あなたができる最善のことは 最適化 JavaScriptをすべて1つのファイルに結合して、ユーザーがダウンロードできるファイルが1つだけになるようにすることです。
JavaScriptでプライベート変数を扱うとき、ある時点でそれらにアクセスしたくなるでしょう。
いくつかのコードで説明しましょう。
module-test.htmlおよびmain.js(テストを容易にするためにfirst.js、second.js、およびmain.jsをマージ)
var MODULE = (function () {
//Private variables
var privateParent,
app;
privateParent = 'parentPrivate';
return app = {
//Privileged method
getPrivateParent: function() {
return privateParent;
}
};
}());
MODULE.sub = (function (parentApp) {
//Private variables
var childMessage,
Constr;
childMessage = ' - trying to access parent private field: ' + parentApp.getPrivateParent(); //prints parentPrivate
Constr = function () {
this.childF = this.childFunction();
};
//Constructor
Constr.prototype = {
constructor: MODULE.sub,
version: "1.0",
childFunction: function () {
$("#testing-div").append(childMessage + "</br>");
}
};
return Constr;
}(MODULE));
//We could just as easily print to the console, but the 'append' allows us to display the results on the page.
$("#testing-div").append("This first part shows what <b>does not work</b>; everything is 'undefined'. " + "</br>");
$("#testing-div").append("You are unable to access the var or func directly. " + "</br>");
$("#testing-div").append("MODULE.privateParent = " + MODULE.privateParent + "</br>");
$("#testing-div").append("MODULE.app = " + MODULE.app + "</br>");
$("#testing-div").append("MODULE.sub.childMessage = " + MODULE.sub.childMessage + "</br>");
$("#testing-div").append("MODULE.sub.Constr = " + MODULE.sub.Constr + "</br>");
$("#testing-div").append("MODULE.sub.childFunction = " + MODULE.sub.childFunction + "</br>");
$("#testing-div").append("END lesson. You must access childFunction() through the <b>new</b> operator." + "</br>");
$("#testing-div").append("----------------------------------------------------" + "</br>");
$("#testing-div").append("Let's see if making an instance of the Object works" + "</br>");
var test = new MODULE.sub();
test.childFunction(); //run the method
$("#testing-div").append("Looks like it did!!!!" + "</br>");
$("#testing-div").append("----------------------------------------------------" + "</br>");
$("#testing-div").append("Now let's try to change the childFunction() ?" + "</br>");
test.childFunction = function() {$("#testing-div").append(" - This is a new function." + "</br>");}
test.childFunction(); // altered version
$("#testing-div").append("Looks like it was changed. :(" + "</br>");
$("#testing-div").append("----------------------------------------------------" + "</br>");
$("#testing-div").append("Does it stay changed?" + "</br>");
var test2 = new MODULE.sub();
test2.childFunction(); // doesn't work
$("#testing-div").append("NO, it was only Overriden in the 'test' Object. It did not effect all the other new objects. :)" + "</br>");
$("#testing-div").append("----------------------------------------------------" + "</br>");
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Module Test</title>
<!-- <script data-main="scripts/main" src="scripts/require.js"></script> -->
</head>
<body>
<h1>This is a test for separate Modules and Private variables.</h1>
<div id="testing-div">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="main.js"></script>
</body>
</html>
RequireJSを使用して上記を実行する場合は、それが可能です。 RequireJSは、あなたと私がすでに使用しているモジュールパターンを使用します。ファイルを分離したい場合は、これを行うには2つの方法があります。
注:これら2つのオプションを比較する機会はまだありませんが、完全を期すためにそれらを含めたいと思いました。
次の参考資料が役立つ場合があります。
あなたが求めているのはRequireJSのようです。現在、ほとんどすべてのビルドでこれを使用しています。あるいは、明らかになるモジュールパターンをフォールバックとして見ることもできますが、その後の目的には、Requireの方がはるかに適しているように聞こえます。
良い読み物: http://net.tutsplus.com/tutorials/javascript-ajax/principles-of-maintainable-javascript/
Javascriptの保護変数は、保護変数を渡すことで実現できます 依存関係として 。サブクラスは、保護された変数にアクセスできるのは親内にあるため、親内に作成する必要があります。 jsFiddleの例
App = window.App || {};
App.ParentClass = (function(){
var protectedState = {
protectedVar: 'wow such protection'
}
return{
SubClassInstance: App.SubClass(protectedState), //make the subclass accessible from outside
}
})(); //closure gives us privacy
SubClass.js
App = window.App || {};
App.SubClass = function(protectedState){
return {
logProtectedVar : function(){
//can access protectedState of parent
console.log(protectedState.protectedVar);
}
}
}// I require protected state to work
main.js
// protected variable is accessible from parent and subclass and nowhere else
App.ParentClass.SubClassInstance.logProtectedVar();
// 'wow such protection'
注:Charles W.が述べたように、このパターンはprotectedState
がオブジェクトである場合にのみ機能します。それがstring/intの場合、値によって渡され、サブクラスで行われた変更は親のコピーからは見えません。
モジュール化(コードの分割)は、データ保護(データの非表示)と同じではありません。
RequireJSは、データ保護の問題ではなく、モジュール化の問題を解決します。言い換えれば...データを保護しようとする際に存在する問題やデータを保護するために存在する解決策は何でもこれらの問題と解決策はRequireJSの有無にかかわらず同じです。
RequireJSは、モジュール間の依存関係を指定し、必要に応じてこれらの依存関係onlyをロードし、すでにロードされているものを再ロードしないようにし、不要なものをロードしないようにするためのすべてのメカニズムを実装します、モジュールの場所をすばやく変更したり、冗長性を持たせたりします。
デプロイ後、RequireJSがどういうわけか重すぎると感じた場合は、代わりに使用できる アーモンド ライブラリがあります。
子供がアクセスできるが、外部の人はアクセスできない(つまり保護されている)フィールドを作成することはできません。それを達成する方法はありますか?
モジュール化が必要な場合(つまり、子を親とは別にコーディングしたい場合)、JavaScriptではこれが可能であるとは思いません。子と親を同じクロージャで動作させることは可能ですが、これはモジュラーではありません。これは、RequireJSの有無にかかわらず当てはまります。
そうでない場合、つまり、eparentPrivateにアクセスできるようにする場合は、公開する必要があります。その後、ユーザーはそれを変更できるようになります!
parentPrivate
への割り当てを防ぎたい場合は、parentPrivate
を含む名前空間で Object.freeze()
を使用できます。
しかし、それがさまざまなブラウザでどれだけうまくサポートされているかはわかりません。また、parentPrivate
にあるもの自体がプリミティブ値ではなくオブジェクトである場合、コードのクライアントによって変更されたくない場合は、フリーズする必要もあります。また、オブジェクトがフリーズされると、すべてのユーザーに対してフリーズされるため、オブジェクトを所有するモジュールは、オブジェクトを変更するための特別な処理を受けません。そして、フリーズは何も隠しません。
または、次のRequireJSの例のようにセッターとゲッターを使用できます。
define(function () {
'use strict';
var writable = "initial value";
var namespace = {
get unwritable() { return writable; },
doSomething: function () { writable = "changed value"; }
};
return namespace;
});
モジュールがparent
としてインポートされた場合、parent.unwritable
に書き込むことはできませんが、モジュール自体はwritable
に書き込むことによって返される値を変更できます。ゲッターによって返される戻り値がプリミティブ値ではなくオブジェクトである場合、このオブジェクトは呼び出し元によって変更できることに注意してください。
繰り返しますが、これはRequireJSを使用するかどうかに関係なく当てはまります。解決策は同じ、問題は同じなどです。