Javascript This Change Value - javascript

How could I correct this behavior so this inside is.green refers to the new book(). Because I'm convinced there isn't a way.
function book(){}
book.prototype.is = function(){};
book.prototype.is.green = function(){
alert(this);
// this should refer to 'new book' not `is` function
return this;
};
var Book = new book();
Book.is.green();
TLDR
Is there a way to construct an new prototype object for each new book that could hold the correct reference? Are there any other potential techniques?
No wrapper functions/altering the book function

book.prototype.is = function(){ return this; }
Book.is().green();
or (I know you said you didn't want to alter the constructor, but):
function book(){ this.is = this; }
Book.is.green();
or (non-cross-browser):
book.prototype = {
get is(){ return this; }
};
Book.is.green();
What's the point of this? Just to have the word "is" needlessly placed somewhere? What's wrong with Book.isGreen()?

I think if you have each method on your object return the base object then this will be what you want.
A bit like how jQuery methods always return a reference to the jQuery object.

Related

Using Object.create() the correct way

Learning Javascript I am finding different ways for creating objects. Seems that the way forward is using Object.create()
It's pretty hard to find a solid answer on best practises for using Object.create() as even the specific Object.create() articles seem to do things slightly different.
What I want to do is create multiple objects with their own encapsulated data.
I like to use encapsulation and what seems to work for me is something like
function Foo() {
var message = "Hello";
return {
bar:bar
}
function bar(){
return message;
}
}
World = (function(){
var obj = Foo();
var tank = Object.create(obj);
return {
baz:baz
}
function baz(){
alert(tank.bar());
}
})();
Running World.baz() works as expected but I am still not sure if I am doing this right.
All answers will be appreciated, thanks.
Generally in javascript you want to create objects like so:
var obj = {};
obj.someProperty = 'someValue';
obj.someOtherProperty = 'someOtherValue';
Or, you could use object literal notation, like this:
var obj = {
someProperty: 'someValue',
someOtherProperty: 'someOtherValue'
};
The Object.create function is an interesting one. Yes, it does create an empty object, but it isn't like the objects defined above. Instantiating and object with Object.create will give the new empty object inheritance up to the parameter you give the Object.create function. For instance, if we define an object as:
var actions = {
shout: function(message){
console.log(message.toUpperCase() + '!');
}
}
And then create a new object with Object.create():
var newObject = Object.create(actions); // creates a new object: newObject = {};
newObject will not contain any of it's own properties, but it will be able to access the properties of the parent actions object. After defining those object, try this out:
newObject.hasOwnProperty('shout'); // returns false
newObject.shout('Hello!'); // logs 'HELLO!!'
This example just goes to show how inheritance works from the newly created object to it's parent. This can be extremely useful, but make sure you specifically want that behavior before creating objects with Object.create-- otherwise, better be safe and use one of the two other methods above.
Hope that helps!
Edit:
Alternatively, if you're just trying to create many separate instances of the same object, you can create a constructor and invoke it with the new keyword, like this:
var Tank = function(speed, durability){
this.speed = speed;
this.durability = durability;
this.location = 0;
this.shoot = function(){
console.log('Pew pew');
};
this.move = function(){
this.location += speed;
};
}
var myTank = new Tank(5, 15); // creates new tank with speed 5 and durability 15,
// that also has all the default properties and methods,
// like location, shoot, and move.
var yourTank = new Tank(7, 12); // instantiates a different tank that myTank, with it's
// own speed and durability properties, but also has the
// default location, shoot, and move properties/ methods
var enemyTank = new Tank(10, 25);// instantiates yet another, unique tank with it's own
// unique values for speed and durability, but again with
// the default location, shoot, and move properties/methods
Try this approach for creating javaScript objects that encapsulating data. As you can see each instance of Foo has its own properties and state.
var Foo = function() {
var Foo = function Foo(customMessage) {
this.message = customMessage || "Hello";
}
Foo.prototype.message;
Foo.prototype.bar = function(){
return this.message;
}
return Foo;
}();
var tank1 = new Foo();
var tank2 = new Foo("Goodbye");
alert(tank1.bar());
alert(tank2.bar());
I would suggest using constructors to encapsulate data. If you really need to use Object.create(), you need to create a constructor-prototype system with Object.create(). However, in any case, you're just calling .bar() from the result of Foo() in the .baz() method of World. That does not mean World should point to the result of Foo().
Object.prototype.__construct = function() {
//This is the default constructor from any new object. We change it to change the constructor of objects as we go along. We could make no __construct method on Object.prototype because it doesn't do anything, so we're not going to call it, but we're going to define it anyway since we want all objects to have a __construct method, even if they don't define a new one on top of the default.
};
//Object.prototype is our default object. We add methods to object to change the prototype of objects as we go along.
var Foo = {}; //Any object that doesn't inherit from anything must inherit from Object.prototype. We do this by just setting it to {} (or new Object()).
//If we're going to define a new constructor, we need to call it _after_ we've defined it.
Foo.__construct = function() {
var message = "Hello!";
this.bar = function() {
return message;
}
};
Foo.__construct();
Foo.bar() //returns "Hello!"
//Note that message is encapsulated and _cannot_ be accessed through Foo itself.
var World = {}; //World _does not_ point to Foo. It simply calls a method of Foo in one of its methods.
World.__construct = function() {
//Now, if the method of Foo we're going to call in the method of World is going to alter Foo, then we should make a copy of Foo using Object.create(). The method we're going to call isn't _actually_ going to alter Foo, but it's good practice to make a copy because it _could_ if we made it so.
var obj = Object.create(Foo);
//Because Foo has been constructed and obj is a copy of Foo, we don't need to construct obj. We only need to construct an object if we define a new constructor property.
this.baz = function() {
alert(obj.bar());
};
};
World.__construct();
World.baz() //alerts "Hello!"
//Note that obj is encapsulated within World. obj points to Foo, but again, World _does not_ point to Foo.

How to extend Object in JavaScript without losing the original functionality

I have a JavaScript object defined like so:
var Object = (function () {
function Object() {
this.id = RandomNumber();
}
// Custom Object.prototype / Object impementations here...
return Object;
})();
The problem is that once this has been constructed, it loses original functionality like Object.defineProperty etc.
The idea is that I want to extend the basic functionality of Object, not re-write or overwrite the existing prototype.
How can this be achieved?
EDIT: Just to be clear, I know I can do this without affecting the original functionality:
Object.prototype.foo = function() { }
but I need to specifically add functionality to Object's constructor, i.e.
function Object() { this.id = 0; }
The new functionality must not overwrite the original Functionality.
Use the .prototype to add a property:
Object.prototype.specialMethod = function () {
// Your method's code
};
And you'd use it like:
var a = {};
a.specialMethod();
Although I would discourage adding a property to the Object's prototype, because it is enumerable and will mess up looping, and will be inherited by all objects, and objects that inherit from Object, which is basically everything.
You could actually use the Object.defineProperty method you mention:
Object.defineProperty(Object.prototype, "specialMethod", {
enumerable: false, // The important one, to avoid looping problems
configurable: false,
writable: false,
value: function () {
// Your method's code
}
});
Do as Ian wrote. If you also want to check it the method already exists use
if (Object.prototype.specialMethod == null) Object.prototype.specialMethod = function() { ... };
In order to extend this object you should create another object that has its prototype assigned a new instance of Object.
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/
If you want to stick with the self executing functions here is the example rewrote:
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
var ExtendsObject = (function(){
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
return ExtendsObject;
})();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/1/
I do question the use of self executing functions in this situation. They are usually used to encapsulate and shield internals, however in the code example they are being exposed by returning the object from the SEF. Returning the object and storing it in a global variable just re-exposes the object, allowing its prototype and properties to be manipulated. Maybe there are private variables you have not mentioned, but as stated I find the SEFs unnecessary.

How to pass an object method to an array method in javascript

This is my first stab at OOP, so please bear with me:
(function(){
var Ship = function(){
this.passengers = [];
this.hasAliens = function() {
return this.passengers.some(function(passenger){
return passenger.isAlien()
});
}
};
var Passenger = function(){};
Passenger.prototype.isAlien = function(){
return this instanceof Alien;
};
Passenger.prototype.board = function(ship) {
ship.passengers.push(this)
}
var Alien = function() { Passenger.call(this); }
var Human = function() { Passenger.call(this); }
Alien.prototype = Object.create(Passenger.prototype);
Human.prototype = Object.create(Passenger.prototype);
Alien.prototype.constructor = Alien.constructor;
Human.prototype.constructor = Human.constructor;
var ship = new Ship();
var john = new Human();
var zorg = new Alien();
//simple testing
john.board(ship);
console.log("Ship does not have aliens ", ship.hasAliens()===false);
zorg.board(ship);
console.log("Ship has aliens ", ship.hasAliens()===true);
})();
​
This works fine. However, I'd like to know how to pass the Passenger.isAlien() method to save me that nasty nested anonymous function. I'm trying to do it like this:
var Ship = function(){
this.passengers = [];
this.hasAliens = function(){
return this.passengers.some(Passenger.isAlien);
};
};
But that gives me "undefined is not a function"
http://jsfiddle.net/WYyxY/
As I said, isAlien is a property of the prototype, i.e. an instance of the constructor function, and not the constructor function itself. Passenger.isAlien is indeed undefined (nowhere in your code is Passenger.isAlien = function....).
There is not really a more concise way to do this. Think about what a callback passed to .some is doing: It has to take an element of the array as argument and then do something with it. In your case you want to execute a method of that element.
One way to call a method and pass the object it should be called on as parameter is to use .call [MDN]. Unfortunately, as with all functions in JavaScript, you cannot just get a reference to Passenger.prototype.isAlien.call, because .call looses its context (it does not know which function it refers to). You'd have to bind it to Passenger.prototype.isAlien first
this.passengers.some(
Passenger.prototype.isAlien.call.bind(Passenger.prototype.isAlien)
);
and personally I find that not more readable.
Stick with the anonymous function, your intend is much clearer. Or if you want to, you can let another function create that function:
function callOn(funcName) {
return function(obj) {
return obj[funcName]();
};
}
this.passengers.some(callOn('isAlien'));
For doing OOP with javascript, I strongly recommend checking out prototypeJS. Your code becomes much more readable, and it also supports inheritance!
Here's a quick look at it

Pattern needed: create new object that returns an executeable function and inherits from a prototype

Scenario 1 - everything works:
var AwesomeObject = function()
{
var self = this;
self.whatstuff = 'really awesome';
}
AwesomeObject.prototype.doStuff = function()
{
var self = this;
console.log('i did '+self.whatstuff+' stuff');
return self;
}
var awesome = new AwesomeObject(); //returns a new AwesomeObject
awesome.doStuff(); // prints 'i did really awesome stuff' on the console
Now i want it even awesomer:
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
return self;
}
AwesomeObject.prototype.doStuff = function()
{
var self = this;
console.log('i did '+self.whatstuff+' stuff');
return self;
}
var awesome = new AwesomeObject(); //returns the interal f object
awesome(); // prints 'i am awesome'
awesome.doStuff(); // throws an error
new AwesomeObject should return an executable function itself, so that i can say 'awesome();'
but i want it to inherit the AwesomeObject.prototype, too.
adding self.prototype = AwesomeObject.prototype; does not help.
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
self.prototype = AwesomeObject.prototype;
return self;
}
ok i can copy the AwesomeObject.prototype functions - one after the other - into the scope of f
var AwesomeObject = function()
{
var f = function() { console.log('i am awesome'); }
var self = f;
self.whatstuff = 'really awesome';
self.doStuff = function() { AwesomeObject.prototype.doStuff.apply(self,arguments); }
return self;
}
but i think there must be a better way, a better pattern, what is it?
this issue drives me crazy, help would be really appreciated.
in general: how to create a function object that
can be created with new
returns a function object that can be executed
inherits all properties and methods of a given prototype
?
is there a way?
thx
Franz
A very simple pattern is a factory.
var AwesomeObject = (function() {
var AwesomeObject = function() {
this.whatstuff = 'really awesome';
};
AwesomeObject.prototype.doStuff = function() {
console.log('i did ' + this.whatstuff + ' stuff');
return this;
};
return function() {
var o = new AwesomeObject();
var f = function() { console.log("I am awesome"); };
for (var k in o) {
f[k] = o[k];
}
return f;
};
})();
var foo = AwesomeObject();
foo();
foo.doStuff();
Live Example.
The idea is that you seperate your function and your object into two things. Your object exists in the local scope of your function and the function can use the object.
The object itself inherits completely through the prototype.
The key is do forward all properties/methods of the object onto the function.
This is the cleanest solution.
When a property is resolved the prototype chain is traversed as you probably know.
But if you have an object awesome and try to evaluate awesome.doStuff, then awesome.prototype will never be queried for the property. You can verify this in your example, "doStuff" in awesome => false but "doStuff" in awesome.prototype => true.
So what you're doing is not changing the implicit properties of awesome, you are changing its prototype, meaning any objects created by doing new awesome will have that property. Verification: "doStuff" in new awesome() => true. And this makes sense, since there is no way to distinguish between a constructor or a regular function when using f/awesome.
The procedure when resolving a property p on an object o is roughly as follows:
Check whether p is defined on o
Check whether p is defined on o.__proto__ (usage of __proto__ is non-standard but widely implemented, except for jscript last time i checked and it has now been deprecated in SpiderMonkey)
Check whether p is defined on o.constructor.prototype
Check whether p is defined on o.constructor.prototype.prototype
etc
So one solution would be to simply set o.__proto__ = AwesomeClass.prototype. Think of __proto__ as a hidden intermediary object between an object and its prototype. Each instance receives its own unique __proto__ object. But this is deprecated and non-standard like I said.
We could also set the values in Function.prototype but that would override other Function properties and affect all Function instances. We don't want that.
So what's left? Not much it turns out. There is no way to set the complete prototype of an object while retaining it's inherited prototype. You will need to iterate through your prototype and copy all properties. Fortunately this will allow instanceof to behave as expected when working with chains of constructors, as well as allowing inheritance/overriding of properties properly.
The problem is really that there is no built-in way to copy the properties of an object into another one, and that there is no standard way to change an object's prototype chain ad-hoc (__proto__).
So use __proto__, or iterate through the prototype.
I don't think there is a good way to do this. I would redesign your program to avoid it.
However, here is a bad, platform-dependent solution (works on V8 using non-standard __proto__ property):
var PrototypeToBeInherited = {'inheritedProperty': 'inheritedPropertyValue'};
f = function() {
return "result";
};
f.__proto__ = PrototypeToBeInherited;
f()
=> "result";
f.inheritedProperty
=> "inheritedPropertyValue"
For your requirement that it must be created with "new", just wrap it in function:
F = function() {
return f;
}
var instance = new F();

javascript : make a new safe class constructor

sometimes we loss the new keyword when define new object,
obj = new Clazz(); //correct
obj = Clazz(); //wrong, but no syntax error, hard to debug.
I want to write a function to help me create Class and make it new safe.
var Class = function(){
var constructor = arguments[0];
var superClasses = arguments[1..n];
function clazz(){
if(! this instanceof clazz){
return new clazz()//pass clazz arguments,not Class arguments
}
constructor();//pass clazz arguments
}
//clazz inherit from superClasses
return clazz;
}
var MyClazz = Class(function(name){
this.name = name
}, SuperClazz1, SuperClass2 )
MyClazz.extend({
show: function(){console.log(this.name)}
})
obj1 = new MyClazz("name1");
obj2 = MyClazz("name2");
// obj1 should same as obj2
Is it possible, any exists module?
sometimes we loss the new keyword...
All about coding discipline and testing... anyways, moving on to your question.
To find out whether your function was called as a constructor use instanceof:
function Foo() {
console.log(this instanceof Foo);
}
Foo(); // false
new Foo(); // true
When calling a function as a constructor this refers to the newly created object, otherwise this refers to the object the function was called on, in case it wasn't called on anything this will refer to the global object.
Update
Passing variable arguments to a constructor is not possible. new clas.call(....) will yield an error that call is not an constructor.
You can do two things:
Instead of returning the Class function itself from your class factory method, return a function that creates a new instance, sets up all the needed stuff and then returns that instance (this will make inheritance waaaay more complicated)
Just use the new keyword.
I've written my own Class thingy, and I've tried to support both new and () syntax for creating instances. The whole inheritance stuff etc. is complicated enough, making it even more magic just to save 4 more characters... not worth the effort. Use new and write tests.
Another Update
OK I couldn't resist to hack around more and I made it work:
function is(type, obj) {
return Object.prototype.toString.call(obj).slice(8, -1) === type;
}
function clas(args) {
if (is('Object', this)) {
ctor.apply(this, is('Arguments', args) ? args : arguments);
} else {
return new clas(arguments);
}
}
This will do the magic, at least in my case.
Sorry for the late submission on this answer but I believe it directly answers your question. My solution is to check the type of the constructed object and act accordingly.
You can see my solution here:
http://mikepackdev.com/blog_posts/9-new-scope-safe-constructors-in-oo-javascript
I hope this helps!

Categories