Вот что вам нужно понять о JavaScript:
var obj = { A: a, B: b, C: c };
вы создаете (и присваиваете obj
) объект со свойствами, именуемыми A
, B
и C
, сопоставляя значения a
, b
и c
соответственно. Эти значения вполне могут быть функциями, поэтому, когда у вас есть
var obj = { A: function(){...} };
вы создаете объект со свойством «A», которое является функцией. Вы можете обратиться к нему с помощью obj.A
и позвонить с помощью obj.A()
.
- Когда вы вызываете
obj.A()
, ключевое слово this
внутри тела функции A
будет ссылаться на obj
. Вы можете использовать его для назначения новых свойств obj
:
var obj = {
A: function() { this.prop = "Hello!"; }
};
obj.A();
alert( obj.prop ); // alerts "Hello!"
Итак, внутри namespaced.A.j()
ключевое слово this
будет указывать на namespace.A
(это то, что слева от последней точки).
Вы можете применить функцию к объекту примерно так: func.apply(obj)
или примерно так: func.call(obj)
. В этом случае ключевое слово this
будет ссылаться на obj
. Это не относится к вашему случаю, но если func
принимает параметры (скажем, param1
и param2
), вы можете применить функцию следующим образом: func.apply(obj, [val1, val2])
или примерно так: func.call(obj, val1, val2)
.
Все переменные, объявленные внутри функции, живут только внутри этой функции. Они не видны снаружи. И когда вы пишете function doStuff(){}
, это (я упрощаю здесь) так же хорошо, как если бы вы написали var doStuff = function(){};
Таким образом, вложенные функции живут и могут использоваться только внутри окружающей функции; то есть, если вы не назначите их для чего-то доступного извне.
Когда вы вызываете что-то вроде new Cons()
, происходит создание нового пустого объекта с последующим применением Cons()
к этому объекту. Другими словами, это так же, как
var obj = {};
Cons.apply(obj);
или, если вы предпочитаете:
var obj = {};
obj.Cons = Cons;
obj.Cons();
// obj's Cons property then mysteriously disappears
// unless it was explicitly set inside Cons() (oh my, how confusing! :)
Так что вы можете иметь это:
function Duck(name){
this.myName = name;
this.quack = function(){
alert(this.myName + " quacks!");
}
};
donald = new Duck('Donald');
donald.quack();
<ч />
Учитывая все вышесказанное, способ написания кода с пространством имен выглядит следующим образом:
// The following syntax, confusing to someone who hasn't seen it before,
// is defining a new anonymous function and immediately using it
// as a constructor applied to a new empty object.
//
// Alternatively, you can use this syntax:
// var namespaced = {};
// (function(){
// ....
// }).apply(namespaced);
//
var namespaced = new (function(){
// This creates a new variable named "namespaced"
// which is visible only inside this anonymous function.
// This variable points to the still-empty object created by
// 'new'. This object will, once we're done with this anonymous function,
// be assigned to a variable, outside, which by "coincidence" is
// also named "namespaced".
var namespaced = this;
// You could alternatively not create the variable "namespaced"
// and use 'this' directly inside this anonymous function. But,
// the 'this' keyword may point to different objects inside the
// nested functions that follow, so we create it to avoid confusion.
// This assigns a new object to variable 'A', which isn't visible outside.
// Use a constructor function defined inline.
var A = new (function(){
var A = this; // 'this' now refers to the empty object created just above
this.someProperty = 5; // Two different ways of
A.anotherProperty = 7; // doing mostly the same thing
this.j = function(){
//do some more stuff
// 'this' will point to j, here
return something;
}
// Function r isn't visible outside of A's constructor like this!
function r(){
//do some stuff
return something;
}
// Make 'r' visible outside by assigning it to a property of 'A'.
// Look, it's also called "r". What fun!
A.r = r;
})();
// Make the object in variable 'A' visible outside of
// 'namespaced's constructor, by making it a property of 'namespaced'
namespaced.A = A;
// Create a new object as before.
// This time we won't make it visible outside
// of "namespaced"'s constructor.
var C = new (function(){
this.d = function (){
//do stuff we like
}
})();
// Give "namespaced" a property 'B'.
// This time it's a function instead of a nested object.
namespaced.B = function(){
// It's cool to make these function calls here, because
// (a) nested functions can see the variables ('A' & 'C')
// of surrounding functions, even if they terminate in the meantime;
// and (b) 'r' & 'd' are properties of 'A' and 'C'.
A.r();
C.d();
};
// You could return 'this' or 'namespaced' from this constructor,
// but the 'new' keyword will make sure the "namespaced" variable
// outside will get the no-longer-empty object it created,
// so you can just not return anything.
})();
// Now you can do
five = namespaced.A.someProperty;
seven = namespaced.A.anotherProperty;
something = namespaced.A.j();
namespaced.B(); // Calls A.r() and C.d()
// But you can't do
namespaced.C.d(); // WRONG: "namespaced" doesn't have a property named "C"
Надеюсь, это поможет больше, чем запутает.