I'm quite confused by the revealing module pattern, when return a "private field" to outside world.
Here is the code,
var vm2 = (function(){
var
name = 'sean',
changename = function(v){
this.name=v;
};
return {
name: name,
foo: name,
changename:changename
};
}());
vm2.changename('jasper');
console.log(vm2.name);
console.log(vm2.foo);
I was confused by the result, that vm2.name is 'jasper' while vm2.foo is still 'sean',
can someone help me understand it?
The "changename" function only updates the "name" property of the object; it doesn't mess with the local variable called "name" that's present in the closure, and it doesn't mess with "foo". Thus the "foo" property of the object retains it's initial value no matter what you pass to "changename".
So step by step:
The variable "vm2" is initialized by that anonymous function. It's value is an object with three properties.
The call to the "changename" function is made via the property reference on "vm2". That will cause this to be bound to that object while "changename" executes.
Inside "changename", the "name" property of the object referenced by this (which is the "vm2" object) is updated to whatever value is passed as the parameter.
Note that once "vm2" is initialized, nothing in that code touches "foo".
How about this case? why the person is still the private one?
var vm = (function () {
var person = { name: "jasper" };
var changename = function (v) {
//person.name = v;
person = { };
};
return {
person: person,
changename: changename
};
})();
vm.changename("sean");
alert(vm.person.name);
Related
please help solve the problem.
i make 3 objects:
level:
var Level = function() {
self = this;
this.cellsObserver = new CellsObserver();
console.log('co from level ' + this.cellsObserver);
this.fieldObj = new Field();
}
field:
var Field = function() {
self = this;
this.init();
};
Field.prototype = Object.create(Level.prototype);
Field.prototype = {
init: function() {
console.log('co from field ' + self.cellsObserver);
}
}
observer:
var CellsObserver = function(){
.............
}
in result console output follow:
co from level [object Object] co from field undefined
I do not understand why in the second case output 'undefined'. because I have appointed a parent:
Field.prototype = Object.create(Level.prototype);
tl;dr: there is no field cellsObserver neither in Field or Level.prototype object. And there is no such thing as a classical 'self' in Javascript.
The long story.
When you're trying to fetch object.property, the Javascript will look at the object trying to find property, then to the object.prototype (which is another object) and so on until it get to the null prototype in the Object.prototype reference.
So, when you're calling second time the this.cellsObserver in Level constructor function, it goes like this:
this is a just new constructed object (if it called with the new keyword), and there is cellsObserver in the property list, so it'll be fetched without any deep lookup.
Then,
Field.prototype = Object.create(Level.prototype);
This only means that Field.prototype now will refer to a new object, which properties are the same as in Level.prototype in that moment.
From your code, there are no non-standard properties in Level.prototype object (you didn't provide any).
Then,
self = this;
Here you just assigning a global variable called self a reference to the just created object or window object (it depends). If you wish to store a reference to the this object, you should var: var self = this. But you should remember that this self variable could be accessed only in the scope where is was declared or in a closure.
Then,
Field.prototype = {
init: function() {
console.log('co from field ' + self.cellsObserver);
}
}
First of all, here you just override the previos instruction (Field.prototype = Object.create(Level.prototype);). If you want to extend the Field.prototype object, you could do in the Object.create call in second argument, or just by accessing a property like that: Field.prototype.init = function(){...}.
Second. The self variable could contain anything when the init function will be executed. Just use this for the current object here.
Third. Let's try to guess what will happen when this.cellsObserver get evaluated inside this init function.
The this object is referring to the Field instance, and there is no cellsObserver property there, so we move to the Field.prototype object, which is defined above ({ init: function () {...}}), there is no cellsObserver either, so we move to the Object.prototype object, which is null. Ok, our lookup is failed, this.cellsObserver is undefined.
What would be it look like if the Field.prototype = Object.create(Level.prototype) wasn't been overridden by the following code? The this object will refer to the Field instance as early. The Field.prototype is referring to the object which is copy of the Level.prototype object, and there is no cellsObserver here either. So, we look to the Object.prototype, and that's it. There is no cellsObserver in any objects except in the instances on Level class, which isn't referenced in any way in the Field instances.
You can play with that here: http://www.objectplayground.com/ by pasting this code:
var Level = function() {
this.cellsObserver = new CellsObserver();
this.fieldObj = new Field();
}
var Field = function() {
this.init();
};
Field.prototype = Object.create(Level.prototype);
Field.prototype.init = function() {};
this.field = new Field();
You are overriding the Field.prototype. Just assign to Field.prototype.init.
After reading a piece of "Essential JS Design Patterns" book, I can't understand the behavior of private variables in this code:
var SingletonTester = (function () {
// options: an object containing configuration options for the singleton
// e.g var options = { name: "test", pointX: 5};
function Singleton( options ) {
// set options to the options supplied
// or an empty object if none are provided
options = options || {};
// set some properties for our singleton
this.name = "SingletonTester";
this.pointX = options.pointX || 6;
this.pointY = options.pointY || 10;
}
// our instance holder
var instance;
// an emulation of static variables and methods
var _static = {
name: "SingletonTester",
// Method for getting an instance. It returns
// a singleton instance of a singleton object
getInstance: function( options ) {
if( instance === undefined ) {
instance = new Singleton( options );
}
return instance;
}
};
return _static;
})();
var singletonTest = SingletonTester.getInstance({
pointX: 5
});
// Log the output of pointX just to verify it is correct
// Outputs: 5
console.log( singletonTest.pointX );
This is an example given by the book about the Singleton pattern.
There is a anonymous function, which return an object containing the "name" member and the "getInstance" method for returning the instance of "Singleton" function.
My troumble is understand how the object stored in SingletonTester can access to the "instance" private var. I mean, after the anonymous function has done its job, the SingletonTester variable should hold only the object:
{
name: "SingletonTester",
// Method for getting an instance. It returns
// a singleton instance of a singleton object
getInstance: function( options ) {
if( instance === undefined ) {
instance = new Singleton( options );
}
and this object does not know what instance is. Same thing for the instantiation of "Singleton" function. How does it know what function is "Singleton", which was defined in the scope of the anonymous function?
What you're experiencing is lexical scoping in JavaScript. Basically, whenever you execute a function, you have access to that function's scope. In addition to that though, you also have access to the lexical scope in which the function was defined.
Let's take a look at an example:
var someObject = (function () {
var privateVariable = 18;
var getValue = function () {
return privateVariable;
};
return {
getValue: getValue
};
})();
The object 'someObject' has a method 'getValue' which when executed returns the value 18. But how is this possible? Here's how the JavaScript engine works when you try executing someObject.getValue():
The JavaScript engine performs a property lookup on the someObject object and sees that it has its own getValue property.
Once it's located the function object (getValue), it executes the function.
When the function gets executed, the JavaScript engine tries to lookup the value for privateVariable.
However, within the scope of the 'getValue' function, privateVariable doesn't exist.
Therefore, the JavaScript engine looks to the PARENT scope (i.e. the scope in which the getValue function was declared).
This scope corresponds to the scope from the anonymous function. And within this scope, privateVariable has a value of 18.
That's lexical scoping in JavaScript. Regarding your example, this is why the instance of SingletonTester has access to the "instance" variable.
I HIGHLY recommend this book to learn more: Scope and Closures
I tried to create this syntax for JavaScript:
var user = new Class({
name: 'No name',
sayHello: function () {
console.log(self.name);
}
});
user.sayHello(); // will print "undefined" because "self" isn't visible
And I created this implementation of Class:
function Class (_properties) {
var self = this;
// copy all properties and methods to this class
for (var _property_name in _properties) {
self[_property_name] = _properties[_property_name];
}
}
But the problem is in self that I wish to use in each class. The self.name will be undefined because self is a [Window object].
Question: how to modify my code to use self inside all functions in class instances? The self is needed to not drop context if the function will be called from external context.
Expected result (I mean that code above should be executed as code below):
function Class (_properties) {
var self = this;
// properties
self.name = 'No name';
// methods
self.sayHello = function sayHello () {
console.log(self.name);
};
}
var user = new Class();
user.sayHello();
The goal of my experiment is to use self that always is reference to current object. Because sometimes when we use calls like this $.get('...', function () { console.log(this); }) - this is set to function local scope. But I wish to use self (magic property) that always be a reference to object of current class (scope of current class).
So I finally figured out that you are talking about the self variable in the sayHello method that is giving you problems.
You need to google JavaScript scope this tutorial - it's not the most intuitive concept, but once you get it, everything will make sense.
In the mean time, it's worth pointing out that self is not a reserved word in JavaScript and doesn't do anything special, but this is.
So what you want, is something like this:
function Class (_properties) {
// copy all properties and methods to this class
for (var _property_name in _properties) {
this[_property_name] = _properties[_property_name];
}
}
var User = new Class({
name: 'No name',
sayHello: function () {
console.log(this.name);
}
});
var user1 = new User();
var user2 = new User();
The keyword new in front of the Class() function causes it to be executed as a constructor function meaning that, inside of the constructor function this will reference it's own scope.
Also, because the property sayHello is a function to be executed inside the scope that you created, you can use this.name - as this will refer to the scope that you created when you instantiated a new Class.
And just because this scope thing is no doubt confusing (don't worry, it probably will be for a while) - if you haven't created a scope (by using a constructor or object literal) you're working inside of the global scope which, in the case of the browser, is the Window object.
That's because you never created an object:
var options = {
name: 'No name',
sayHello: function () {
console.log(self.name);
}
}
var user1 = new Class(options);
var user2 = new Class(options);
"this" refers to the object owner of the current function. In this case would be windows object. At least you construct an object from the function Class.
If you want to avoid someone overwrite a property of Class.prototype is necessary to use hasOwnProperty in your for in
If I create multiple objects using Object.create() on an object literal, I get multiple unique objects that don't share property values. However, when I use Object.create() on an object returned from a module, it looks like they share the same reference? Why is that?
#1 Module:
var objModule = (function () {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
}());
var objModule2 = Object.create(objModule);
objModule2.setName("module 2");
console.log(objModule.getName()); // WRONG prints "module 2"
console.log(objModule2.getName()); // prints "module 2"
#2 Literal:
var objLiteral = {
name : "literal 1"
};
var objLiteral2 = Object.create(objLiteral);
objLiteral2.name = "literal 2";
console.log(objLiteral.name); // prints "literal 1"
console.log(objLiteral2.name); // prints "literal 2"
EDIT
#3 Module "Constructor":
var module = function () {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
};
var objModule1 = module();
var objModule2 = module();
objModule2.setName("module 2");
console.log(objModule1.getName()); // prints "module 1"
console.log(objModule2.getName()); // prints "module 2"
EDIT
If I use the module like a constructor (as suggested by #Matt Browne) and create 2 objects, the result is like using an object literal. What I'd like to understand is why does module example #1 behave differently than module example #3?
EDIT 2
As #ben336 explained, the code:
var objModule2 = Object.create(objModule);
will set the objModule2's prototype to objModule. That doesn't happen in example #3, so those two objects don't share the same closure property.
Example 1
The first argument of Object.create specifies the prototype object for the new object being created. Since in your first example you're setting your existing object to be the prototype of your new object, when you call the functions they're modifying the variable you've stored in a closure, which is then accessed by both your existing object and the new one.
The 2 key things to understand here are:
This code
var objModule = function () {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
}();
creates a closure with the functions getName and setName holding access to the name variable.
those functions are properties of objModule, and when you call Object.create you set objModule to be the prototype of objModule2, and it gains access to those functions as well.
Since the 2 objects share those functions, and they have access to the closure created by the module rather than storing the name property locally on either object, when you call the set function with one object, it will update the closure and thus update both objects.
Example 2
In the second example you're also setting the object to be the prototype of the new object, but you're declaring a property on the local object which overrides the property on the prototype.
objModule2.setName refers to the same function as objModule.setName, but with a different this. (Object.create doesn't copy anything)
Calling it will set the same local variable.
objLiteral2.name = "literal 2" creates a new property on objLiteral2, which shadows the inherited objLiteral.name.
I think what you're going for here would be better accomplished by removing the parentheses () at the end of the objModule function, and renaming it to something that makes it clear it's a constructor, i.e. do this instead:
var makeObjModule = function() {
var name = "module 1";
var setName = function( strName ) {
name = strName;
};
var getName = function() {
return name;
};
return {
setName: setName,
getName: getName
};
}; //removed parentheses here
(Personally I'd use the function objModule() syntax too while I was at it, but that's a separate point and a matter of personal preference.)
Then you can create your instances:
var objModule = makeObjModule();
var objModule2 = makeObjModule();
The Object.create approach is of course a valid way of going about this as well; for more details on making that work, see #ben336's answer.
Personally I find Object.create to be more useful when doing inheritance than when doing simple construction like this. (Some people also prefer it to using the new keyword when using prototypal inheritance, but since you're using the module pattern I think it's easier to just use a "maker"/constructor function as I showed above.)
Typically, calling this would work; but I am calling the method in another context, so this refers to that context rather than the 'parent' object.
Here's the code:
var someConfig = {
things: [
{
attr1: 'foo',
attr2: 'bar',
action: function() {
console.log(this);
}
}
]
}
function Constructor(config) {
var self = this;
self.name = 'test';
self.things = config.things;
$.each(self.things, function(i, thing) {
thing.action();
});
}
var obj = new Constructor(someConfig);
console.log(obj);
Here's a jsfiddle. The goal is to have both objects that are in the console to be the same, but this in the context of the action method returns the original object to which action belongs, rather than the constructor.
The only thing I can think of is to pass self into action, but I think there's a better way.
Firstly, a couple of points about your code. your config property is uniqueAction yet later you refer to it as config.action. When you call obj.action you need to call it as a function like: obj.action();
With that in mind, the following seems to do what you require...
var config = {
action: function() {
console.log(this.name);//<- IMPORTANT PART
}
}
function Constructor(config) {
var self = this;
self.name = 'test';
self.action = config.action;
}
var obj = new Constructor(config)
obj.action();
Notice that the console.log call now uses this.name instead of self.name.
Here is a working example
The only way I see is to tack the 'constructor' onto the config thing before calling the action.
Check out this Fiddle, which was forked off yours.
I've changed two things:
First, the action function no longer references this, but rather the property parent of this.
action: function() {
console.log(this.parent);
// ^^^^^^^
}
Second, each thing object receives a parent property, which references self.
$.each(self.things, function(i, thing) {
thing.parent = self;
thing.action();
});
Can functions passed into constructors have access to the constructor's other properties?
Yes, but only if you pass that object to the function (or implicitly use the this keyword).
What you did try was accessing the local self variable from a function that was declared outside the constructor, which is just impossible.
So just use
{
action: function() {
console.log(this.name);
// ^^^^
}
}
And when calling obj.action() the this will point to the instance.