あなたは10のJavaScriptの難しさを知る必要があります.

8968 ワード

このブログを読むことができるJavaScript開発者は、運が悪くない…
1.すぐに関数を実行する
すぐに関数を実行します.すなわち、Immediately Invoked Function Expression(IIIIIIIIIIIIFSE)は、その名前の通り、関数を作成しながらすぐ実行します.イベントは結合されていません.非同期の操作を待つ必要もありません.

(function() {
 //   
 // ...
})();
function(){…}は匿名関数であり、それを囲む一対の括弧が式に変換され、その後の一対の括弧がこの関数を呼び出した.即座に実行される関数は、匿名関数を即座に呼び出すものとしても理解され得る.直ちに関数を実行する最も一般的な応用シーンは、var変数の作用領域をあなた達の関数内に制限して、このようにネーミング衝突を避けることができます.
2.クローズド
クローズド(closure)に対しては、外部関数が戻った後も内部関数は外部関数の変数にアクセスすることができます.

function f1()
{
 var N = 0; // N f1       
 function f2() // f2 f1       ,   
 {
 N += 1; //     f2        f1    N
 console.log(N);
 }
 return f2;
}
var result = f1();
result(); //   1
result(); //   2
result(); //   3
コードでは、外部関数f 1は一回だけ実行され、変数Nは0に設定され、内部関数f 2は変数reultに割り当てられます.外部関数f 1はすでに実行済みなので、その内部変数Nはメモリから消去されるべきですが、実際にはそうではありません.私たちは毎回リセットを呼び出すたびに変数Nがメモリにあり、蓄積されていることが分かります.なぜですか?これは閉包の不思議なところです.
3.クローズドパッケージを使ってプライベート変数を定義する
通常、JavaScript開発者はプライベート変数のプレフィックスとして下線を使用する.しかし、実際には、これらの変数はまだアクセスされて変更されてもよく、本当にプライベート変数ではない.このとき、クローズドパケットを使用すると、本当にプライベート変数が定義されます.

function Product() {
 var name;
 this.setName = function(value) {
 name = value;
 };
 this.getName = function() {
 return name;
 };
}
var p = new Product();
p.setName("Fundebug");
console.log(p.name); //   undefined
console.log(p.getName()); //   Fundebug
コードの中で、オブジェクトpのname属性はプライベート属性です.p.nameを使って直接アクセスできません.
4.prototype
各JavaScript構造関数には、すべてのインスタンスオブジェクトを共有する属性と方法が設定されています.prototype属性は列挙できません.JavaScriptはprototype属性による継承属性と方法のみをサポートします.

function Rectangle(x, y)
{
 this._length = x;
 this._breadth = y;
}
Rectangle.prototype.getDimensions = function()
{
 return {
 length: this._length,
 breadth: this._breadth
 };
};
var x = new Rectangle(3, 4);
var y = new Rectangle(4, 3);
console.log(x.getDimensions()); // { length: 3, breadth: 4 }
console.log(y.getDimensions()); // { length: 4, breadth: 3 }
コードでは、xとyはいずれも構造関数Rectangleによって作成されたオブジェクトの例であり、それらはプロtypeによってget Dimensions法を継承している.
5.モジュール化
JavaScriptはモジュール化プログラミング言語ではなく、少なくともES 6が着地するまではそうではない.しかし、複雑なWebアプリケーションに対しては、モジュールプログラミングは最も基本的な要求である.この時、すぐ実行関数を使ってモジュール化ができます.jQueryやFunebugなど多くのJSライブラリがこのように実現されています.

var module = (function() {
 var N = 5;
 function print(x) {
 console.log("The result is: " + x);
 }
 function add(a) {
 var x = a + N;
 print(x);
 }
 return {
 description: "This is description",
 add: add
 };
})();
console.log(module.description); //   "this is description" 
module.add(5); //   “The result is: 10”
モジュール化とは、必要に応じてモジュール内の属性と方法のアクセス可能性、すなわちプライベートまたは公開を制御することである.コードでは、moduleは独立したモジュールであり、Nはそのプライベート属性であり、printはそのプライベート方法であり、decriptionはその共有属性であり、addはその共有方法である.
6.変数の昇格
JavaScriptは、すべての変数と関数宣言をそのスコープの先頭に移動します.これはいわゆる変数アップグレードです.つまり、変数と関数をどこで宣言しても、インタプリタはそれらを作用領域の先頭に移動します.したがって、まず変数と関数を使って、それを宣言することができます.
しかし、変数宣言だけが向上しました.変数の割当値は上昇しません.それが分からないと、エラーが発生する場合があります.

console.log(y); //   undefined
y = 2; //    y
上のコードは下のコードと同じです.

var y; //   y
console.log(y); //   undefined
y = 2; //    y
バグを避けるために、開発者は各スコープの開始時に変数と関数を宣言するべきです.
7.コリ化
カリー化、すなわちCurryingは、関数がより柔軟になることができる.一度に複数のパラメータに入ることができます.一部のパラメータだけが入ってきて、残りのパラメータを処理する関数を返してもいいです.

var add = function(x) {
 return function(y) {
 return x + y;
 };
};
console.log(add(1)(1)); //   2
var add1 = add(1);
console.log(add1(1)); //   2
var add10 = add(10);
console.log(add10(1)); //   11
コードには、2つの1つをパラメータadd(1)(1)として一度に導入しても良いし、1つのパラメータを導入した後にadd 1とadd 10関数を取得しても良いので、非常に柔軟に使用できます.
8.appy、callとbindの方法
JavaScript開発者は、applyとcallとbindの方法の違いを理解する必要があります.それらの共通点は、最初のパラメータがthisであり、関数が動作するときに依存するコンテキストである.
三者のうち、コール方法は最も簡単で、指定されたthis値の呼び出し関数と等価である.

var user = {
 name: "Rahul Mhatre",
 whatIsYourName: function() {
 console.log(this.name);
 }
};
user.whatIsYourName(); //   "Rahul Mhatre",
var user2 = {
 name: "Neha Sampat"
};
user.whatIsYourName.call(user2); //   "Neha Sampat"
アプリ方法はコール方法と似ています.両者の唯一の相違点は、apply方法は配列指定パラメータを使用し、call方法は各パラメータごとに個別に指定する必要があることである.

apply(thisArg, [argsArray])
call(thisArg, arg1, arg2, …)
var user = {
 greet: "Hello!",
 greetUser: function(userName) {
 console.log(this.greet + " " + userName);
 }
};
var greet1 = {
 greet: "Hola"
};
user.greetUser.call(greet1, "Rahul"); //   "Hola Rahul"
user.greetUser.apply(greet1, ["Rahul"]); //   "Hola Rahul"
bind法を使用して、関数としてthis値を結合し、新しい関数として返します.

var user = {
 greet: "Hello!",
 greetUser: function(userName) {
 console.log(this.greet + " " + userName);
 }
};
var greetHola = user.greetUser.bind({greet: "Hola"});
var greetBonjour = user.greetUser.bind({greet: "Bonjour"});
greetHola("Rahul") //   "Hola Rahul"
greetBonjour("Rahul") //   "Bonjour Rahul"
9.Memoization
Memoizationは、比較的時間がかかる計算を最適化するために、計算結果をメモリにキャッシュすることにより、同じ入力値に対して、次回は中メモリで結果を読み取るだけです.

function memoizeFunction(func)
{
 var cache = {};
 return function()
 {
 var key = arguments[0];
 if (cache[key])
 {
  return cache[key];
 }
 else
 {
  var val = func.apply(this, arguments);
  cache[key] = val;
  return val;
 }
 };
}
var fibonacci = memoizeFunction(function(n)
{
 return (n === 0 || n === 1) ? n : fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(100)); //   354224848179262000000
console.log(fibonacci(100)); //   354224848179262000000
コードの中で、2回目の計算では、fibonacci(100)はメモリで直接結果を読み取る必要があります.
10.関数の再ロード
関数の再ロードとは、関数名が同じですが、入出力が異なります.あるいは、ある関数に様々な入力があることを許可し、異なる入力によって異なる結果を返します.直感によって、関数の重荷重はif...elseまたはswitchで実現できます.これは構いません.jQueryの父John Reigは非常に巧妙な方法を提案しました.
効果的には、peopleオブジェクトのfindメソッドは、3つの異なる入力を許可します.0つのパラメータの場合、すべての人名を返します.1つのパラメータの場合、firstNameによって人名を探して返します.2つのパラメータの場合は、フルネームから人名を検索して返します.
難しい点は、people.findは一つの関数だけを結びつけることができます.なぜ3つの異なる入力を処理できますか?3つの関数find 0とfind 1とfind 2を同時に結びつけることは不可能です.ここの鍵はold属性です.
addMethod関数の呼び出し順序から、people.findの最終的なバインディングはfind 2関数であることがわかった.しかし、find 2を結合するとき、oldはfind 1である.同じ理屈で、find 1を結び付ける時、oldはfind 0です.3つの関数find 0、find 1とfind 2はこのようにして閉じていることを通じてリンクし始めました.
addMethodの論理によれば、f.lengthがargments.lengthと一致しない場合、一致するまでoldを呼び出します.

function addMethod(object, name, f)
{  
 var old = object[name];  
 object[name] = function()
 {
 // f.length           
 // arguments.length               
 if (f.length === arguments.length)
 {  
  return f.apply(this, arguments);    
 }
 else if (typeof old === "function")
 {
  return old.apply(this, arguments);    
 }  
 };
}
//      ,    name
function find0()
{  
 return this.names;
}
//       ,  firstName   name
function find1(firstName)
{  
 var result = [];  
 for (var i = 0; i < this.names.length; i++)
 {    
 if (this.names[i].indexOf(firstName) === 0)
 {      
  result.push(this.names[i]);    
 }  
 }  
 return result;
}
//       ,  firstName lastName    name
function find2(firstName, lastName)
{ 
 var result = [];  
 for (var i = 0; i < this.names.length; i++)
 {    
 if (this.names[i] === (firstName + " " + lastName))
 {      
  result.push(this.names[i]);    
 }  
 }  
 return result;
}
var people = {  
 names: ["Dean Edwards", "Alex Russell", "Dean Tom"]
};
addMethod(people, "find", find0);
addMethod(people, "find", find1);
addMethod(people, "find", find2);
console.log(people.find()); //   ["Dean Edwards", "Alex Russell", "Dean Tom"]
console.log(people.find("Dean")); //   ["Dean Edwards", "Dean Tom"]
console.log(people.find("Dean", "Edwards")); //   ["Dean Edwards"]
原文:http://www.infoworld.com/article/3196070/node-js/10-javascript-concepts-nodejs-programmers-must-master.html
Funebug