I'm taking some JavaScript/jQuery lessons at codecademy.com. Normally the lessons provide answers or hints, but for this one it doesn't give any help and I'm a little confused by the instructions.
It says to make the function makeGamePlayer return an object with three keys.
//First, the object creator
function makeGamePlayer(name,totalScore,gamesPlayed) {
//should return an object with three keys:
// name
// totalScore
// gamesPlayed
}
I'm not sure if i should be doing this
//First, the object creator
function makeGamePlayer(name,totalScore,gamesPlayed) {
//should return an object with three keys:
// name
// totalScore
// gamesPlayed
this.name = name;
this.totalScore = totalScore;
this.gamesPlayed = gamesPlayed;
}
or something like this
//First, the object creator
function makeGamePlayer(name,totalScore,gamesPlayed) {
//should return an object with three keys:
// name
// totalScore
// gamesPlayed
var obj = {
this.name = name;
this.totalScore = totalScore;
this.gamesPlayed = gamesPlayed;
}
}
I have to be able to modify the properties of the object after its created.
In JavaScript, most functions are both callable and instantiable: they have both a [[Call]] and [[Construct]] internal methods.
As callable objects, you can use parentheses to call them, optionally passing some arguments. As a result of the call, the function can return a value.
var player = makeGamePlayer("John Smith", 15, 3);
The code above calls function makeGamePlayer and stores the returned value in the variable player. In this case, you may want to define the function like this:
function makeGamePlayer(name, totalScore, gamesPlayed) {
// Define desired object
var obj = {
name: name,
totalScore: totalScore,
gamesPlayed: gamesPlayed
};
// Return it
return obj;
}
Additionally, when you call a function you are also passing an additional argument under the hood, which determines the value of this inside the function. In the case above, since makeGamePlayer is not called as a method, the this value will be the global object in sloppy mode, or undefined in strict mode.
As constructors, you can use the new operator to instantiate them. This operator uses the [[Construct]] internal method (only available in constructors), which does something like this:
Creates a new object which inherits from the .prototype of the constructor
Calls the constructor passing this object as the this value
It returns the value returned by the constructor if it's an object, or the object created at step 1 otherwise.
var player = new GamePlayer("John Smith", 15, 3);
The code above creates an instance of GamePlayer and stores the returned value in the variable player. In this case, you may want to define the function like this:
function GamePlayer(name,totalScore,gamesPlayed) {
// `this` is the instance which is currently being created
this.name = name;
this.totalScore = totalScore;
this.gamesPlayed = gamesPlayed;
// No need to return, but you can use `return this;` if you want
}
By convention, constructor names begin with an uppercase letter.
The advantage of using constructors is that the instances inherit from GamePlayer.prototype. Then, you can define properties there and make them available in all instances
You can simply do it like this with an object literal:
function makeGamePlayer(name,totalScore,gamesPlayed) {
return {
name: name,
totalscore: totalScore,
gamesPlayed: gamesPlayed
};
}
The latest way to do this with ES2016 JavaScript
let makeGamePlayer = (name, totalScore, gamesPlayed) => ({
name,
totalScore,
gamesPlayed
})
Both styles, with a touch of tweaking, would work.
The first method uses a Javascript Constructor, which like most things has pros and cons.
// By convention, constructors start with an upper case letter
function MakePerson(name,age) {
// The magic variable 'this' is set by the Javascript engine and points to a newly created object that is ours.
this.name = name;
this.age = age;
this.occupation = "Hobo";
}
var jeremy = new MakePerson("Jeremy", 800);
On the other hand, your other method is called the 'Revealing Closure Pattern' if I recall correctly.
function makePerson(name2, age2) {
var name = name2;
var age = age2;
return {
name: name,
age: age
};
}
I would take those directions to mean:
function makeGamePlayer(name,totalScore,gamesPlayed) {
//should return an object with three keys:
// name
// totalScore
// gamesPlayed
var obj = { //note you don't use = in an object definition
"name": name,
"totalScore": totalScore,
"gamesPlayed": gamesPlayed
}
return obj;
}
Related
I'm having trouble achieving something in Javascript, and also having trouble explaining it. I'm writing an API and I want the developer to be able to write the following code:
dashboard('name1').createPanel('name2');
The problem is I can't figure out a way to create a function called "dashboard" (which accepts an argument 'name1') while also providing a prototype called createPanel.
You have functions and object. An example:
// A normal function
function dashboard(name) {
}
dashboard("name1");
You can also prototype this function if you do a new you will have to object of class dashboard. So the example:
function dashboard( name ) {
// As class
this.name = name;
}
dashboard.Prototype.createPanel = function(name) {
this.name = name;
return this; // return the reference
}
var x = new dashboard("name1"); // create object
x.createPanel( "Name2" );
// x.name will be "Name2"
What you want is chaining functions. All you need to do is return the object where you want to call the next function from. If you return this every time you can chain functions of that object like:
// extending the class with addProperty for chainging example
dashboard.Prototype.addProperty = function(key, value){
this[key] = value;
return this; // To enable chaining, return reference
}
var x = new dashboard("name1");
x.createPanel("Niels").addProperty("A", "B").addProperty("B", "C");
We can chain on and on. All you need to do is return the reference where you want to continue chaining from (normally the this object). But can be every object you want.
my question here is about functions and objects in javascript. I have three questions that stems from one to other. In the below example, I try to access the value of 'a' in test, but I get undefined. but I create a new object of test, then I am able to access the 'a' value and change it.
//create a function called test
var test=function() {
this.a=2
this.b=3 };
test.a//undefined
//create a object called test1 using 'new'
test1 = new test();
test1.a//2
//change the value of a in test1
test1.a=4
test1 //Object { a=4, b=3}
while trying to find why this happens, I came across this javascript functions are objects? and another question popped out of this.
The accepted solution for that SO question is below
var addn = function func(a) {
return func.n + a;
};
addn['n'] = 3;
addn(3);
I changed the 'func.n' to 'this' and it no longer works
var addn=function func(a) {
return this.n+a;
};
addn['n']=3;
addn(3); //NaN
making anonymous function with 'this' also did not help
//anonymous function
var addn=function(a) {
return this.n+a;
};
addn['n']=3;
addn(3); //NaN
why using 'this' did not work?
one final question, what is the difference in using keyword 'new' and 'createObject'. Douglas Crokford suggests using 'CreateObject' in his book, but I fail to understand why. Thanks all for your comments
1. Functions are constructors for new objects
When you call new FuncName, the function acts as a constructor, and the value of this inside points to the object being constructed (not the function itself). When you remove new, this becomes undefined, falling back to the global object (unless you're in strict mode).
2. Functions are also objects
Every function is an instance of Function, so the functions themselves are objects and can have have their own properties. Those properties cannot be accessed with this.propName inside the function body, only with funcName.propName. That's because this inside a function is never the function object itself (unless you forced it to be, with bind, call, or apply).
I hope both topics above help you understand how functions work. As for your final question: Crockford's createObject is a different way to implement inheritance, doing basically what Object.create does in ES5-compliant browsers. It allows an object to inherit straight from another object, without requiring you to manually create a new constructor, set its prototype property (which is an example of a property on a function object), and create an instance with new. Crockford prefers that, and said he stopped using new in favor of this approach.
In response to the questions you asked in chat, here is an attempt to explain what functions are and what they do, with examples.
Functions can be just... functions
You call them, they do something:
function alertThis(what) {
alert(what)
}
alertThis("alerting something");
You can also pass them values, and have them return values
function timesTwo(num) {
return num * 2;
}
timesTwo(2); // 4
They can be passed and return anything, including objects...
function createPerson(firstName, lastName) {
return {
firstName : firstName,
lastName : lastName
}
}
var john = createPerson('John', 'Doe');
john.lastName; // "Doe"
...and other functions:
function timesN(n) {
return function(num) {
return n * num;
}
}
var timesThree = timesN(3);
timesThree(5); // 15
Functions are objects
Functions can be passed around and returned like any ordinary object. That's because they are objects. Like any object, they can have properties:
function countCalls() {
countCalls.timesCalled++;
}
countCalls.timesCalled = 0;
countCalls();
countCalls();
countCalls.timesCalled; // 2
One very important default property of functions is prototype. It's a special property, and we'll see why.
Functions can act as constructors for new objects
Functions can behave like class constructors do in regular OO languages. When called with new, they create a new object of a certain "class". This new object is called this inside the function, and is automatically returned:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
var john = new Person('John', 'Doe');
john.firstName; // "John"
john instanceof Person; // true
... unless you deliberately return something else:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
var fakePerson = {
firstName : firstName,
lastName : lastName
};
return fakePerson;
}
var notPerson = new Person('John', 'Doe');
notPerson.firstName; // "John"
notPerson instanceof Person; // false
// Note: the object called 'this' inside the function is created, but
// after the function is called there is no outside reference to it.
Objects created by constructors know who created them, and can see their prototype property
Back to a real person:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// Add something to the Person prototype
Person.prototype.sayHi = function() {
return "hi, I'm " + this.firstName;
}
var john = new Person('John', 'Doe');
john.sayHi(); // "Hi, I'm John"
john.constructor; // Person
The object john can sayHi() because it has access to everything inside its constructor's prototype property. But it cannot see other properties of Person directly (only through their own constructor property):
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
Person.timesCalled++;
// There is no 'this.timesCalled', only Person.timesCalled
}
Person.timesCalled = 0;
var john = new Person('John', 'Doe');
john.timesCalled; // undefined - john cannot be called, Person can
john.constructor.timesCalled; // 1
1.
addn['n'] = 3; //Means you add static property n to the function(object) addn.
so addn.n also work.
2
this.n means property n of the instance.
this.n === undefined so it returns NaN.
3 var addn=function func(a) means you give a second name to func.
var addn=function(a) is better format in most case.
4 createObject is not a native javaScript code. 'New' is.
Suppose I have two constructor function:
var Person = function(xx,xx,xxx,xxxxxxx) {
//Person initialization
}
var Man = function(xx,xx,xxx,xxx) {
//Man initialization
}
And I want Man extends from Person.
The following is what I thought:
Given a created Man object:
var m=new Man("xx",....);
1) when a property of m is accessed,it will search it in Man.prototype.
2) If not find, It should find it in Man.prototype.__prop__.
So what I have do is make the Man.prototype.__prop__ linked to Person.prototype.
I know this is the common way:
function inherit(superClass) {
function F() {}
F.prototype = superClass.prototype;
return new F;
}
Man.prototype=inherit(Person);
But when I try this:
Man.prototype.prototype=Person.prototype.
Why it does not work?
It sounds like you actually want to link instances of Man to an instance of Person that retains any properties added in its constructor, in which case you might really want something like this:
function Person(a, b) {
this.a = a;
this.b = b;
}
function Man() {}
Man.prototype = new Person("val1", "val2");
var m = new Man();
console.log(m.a);
...which prints val1.
Additional Ramblings
The purpose of inherit is to create an object from a function whose prototype is that of the given super class (without explicitly using new), which is exactly what it does. Therefore, the following prints string:
function Person() {}
Person.prototype.test = "string";
function Man() {}
function inherit(superClass) {
function F() {}
F.prototype = superClass.prototype;
return new F;
}
var t = inherit(Person);
console.log(t.test);
But you generally want to assign the returned object to another function's prototype:
Man.prototype = inherit(Person);
var m = new Man();
console.log(m.test);
...so that m.test also prints string, which means that objects created using Man are linked to Person's prototype).
Note that Man.prototype.prototype is undefined and -- this is the important part -- also meaningless. Functions have prototypes. Other objects (such as Man.prototype) do not. The prototype property is not magical in any other context. Assigning a value to a random object's prototype property doesn't do anything special. It's just another property.
Note also that the thing we returned from inherit is linked to Person by way of its prototype and has no access to any properties added to instances of Person.
How I do it (in regards to your example):
var Person = function () {
}
// Define "Person" methods
var Man = function () {
}
Man.prototype = new Person();
// Define "Man" methods
UPDATE
Regarding constructors with parameters: just found this SO question that can really help you figure it out (second answer, first part): JavaScript inheritance: when constructor has arguments.
There are quite a few generic methods to do that. I will provide three of them:
1.) Using Function object as a constructor and as a prototype object for inherited new objects. The implementation should look like as the following:
var person = {
toString : function() {
return this.firstName + ' ' + this.lastName;
}
}
function extend(constructor, obj) {
var newObj = Object.create(constructor);
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
newObj[prop] = obj[prop];
}
}
return newObj;
}
var man = extend(person,
{
sex: "male",
age: "22"
});
var name = extend(man,
{
firstName: "Simo",
lastName: "Endre"
});
name.man;
name.toString();
2.) In this case we'll use the Function object as the constructor for simulating the classical inheritance in a language like C# or Java. The prototype property of an object will be used in the role of a constructor and the the newly created object will inherit all the properties from the object prototype root. In this case the object's prototype has only one kind of augmentation role, the effective implementation is done in the function method.
var Person = function(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.toString = function() {
return this.firstName + ' ' + this.lastName;
}
function inherit(func) {
// passing function arguments into an array except the first one which is the function object itself
var args = Array.prototype.slice.call(arguments, 1);
// invoke the constructor passing the new Object and the rest of the arguments
var obj = Object.create(func.prototype);
func.apply(obj, args);
//return the new object
return obj;
}
var man = inherit(Person, "Simo", "Endre");
man.toString();
3.) The well known inheritance model:
function extend(o) {
function F() {}
// We'll set the newly created function prototype property to the object.
//This act as a constructor.
F.prototype = o;
// Using the `new` operator we'll get a new object whose prototype is o.
return new F();
};
When we make an object like this
function myObject(){
Properties and methods here----
};
We write “function” keyword before name of object is it necessary? All objects are functions in real? Can we not write direct object name like this?
myObject(){
Properties and methods here----
};
No, not all objects are functions. (All functions are objects, though.)
Here, obj isn't a function:
var obj = {
foo: "bar"
};
Nor dt here:
var dt = new Date();
The function keyword is necessary in order to say "what follows is a function declaration or function expression." It's just part of the basic syntax of JavaScript.
in the first case, the function can be used as the constructor for an object. So you can have:
function Person(name) {
this.name = name
}
Person.prototype = {
// methods can go in here
}
person1 = new Person("bob");
alert(person1.name) // alerts "bob"
It is also true that you can use a function as an object. For example:
function myObject() {
return myObject.test;
}
myObject.test = "bob";
alert(myObject()) // would alert "bob"
but all objects are not functions.
var someObject = {
name: "bob",
moody: "sad"
}
alert(someObject.name); // alerts "bob"
try {
someObject();
} catch (er) {
alert(er); // alerts "TypeError: object is not a function"
}
I'd suggest you take a look at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function
One reason is obviously disambiguity;
function foo()
{
alert("cake")
}
foo()
{
alert("burb");
}
foo();
alerts cake, burb, cake as the 2nd foo() {...} is just a regular function call followed by a regular compound statement enclosed in {}.
function declares a function. Because of the way JavaScript works, a function can be used as a class, to make objects.
But if you really just want an object, use squiggly braces, like this:
var myObject = {
x : 30, // a property
getX : function() { // a method
return this.x;
}
}
But your understanding of JavaScript needs a lot of work: read a few books about it.
In Javascript we can create objects in various ways:
1) Literals
let employee = {"name": "tyrion","age":34}
2) Constructor functions(functions having this)
function employee(name, age) {
this.name = name;
this.age = age;
}
let specificEmployee = new employee("tyrion",34);
Constructor function always need to have a new operator to create a object
3) Using Object constructor
let employee = Object.create(null);
employee.name = "tyrion";
employee.age = 34
In javascript every thing other than primitive type is an instance inherited from Object constructor.
No it's not required. You can also have:
var myObject = {
Prop1: "Value1",
Prop2: "Value2",
Method1: function() {
alert("hello");
}
};
Live test case: http://jsfiddle.net/rKunx/
You can write:
myObject = {
Properties and methods here----
}
If you want to avoid the function keyword as much as possible in Java you could use classes:
class Person {
name;
setName(name) {
this.name = name;
this.doStuff();
}
doStuff() {
//...
}
}
The obvious disadvantage to using classes though is that any property or function has to be accessed with this. An advantage of this keyword is that it is clear to know that you are referring to a class property or function and not a local one within the function.
Some people use a var or let in the top:
setName(name) {
let t = this;
t.name = name;
t.doStuff();
}
Still, many prefer to use a function to define some kind of class instead since that does not need this in order to reach the properties which are just variables in the scope of the function. Put inside a module you will still be able to contain these in much the same way you would a class.
If I could make a wish for the future of Javascript it would be to find some way that this is implicitly referring to the class in some way to have a smaller code style with less tokens and easier readability.
I have this class where I have a private property and a public method for access:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) { //Get
return this.Name
} else {
this.Name = value; //Set
}
};
return _public;
};
I want to force the context in _public.Name for access a this.Name.
I know the technique of closure, but I want to see if I can force a context.
I found a technique to do it, extend object Function:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
f().apply(scope);
}
}
And my class becomes:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return this.Name
} else {
this.Name = value;
}
}.setScope(this);
return _public;
};
So I can force correctly the context, but I can not pass value and can not, however, return this.Name.
Not
f().apply(scope);
just
f.apply(scope);
(No () after f.) You want to use the apply function on the function f object, not call the function f and access apply on its return value.
To also pass on the arguments that your function in setScope receives, add this:
f.apply(scope, arguments);
arguments is an implicit argument to all functions, which is a pseudo-array of the actual arguments passed to the function at runtime. apply accepts any array-like thing as its second parameter to specify the arguments to use when calling the underlying function.
I'd also have it return the return value:
return f.apply(scope, arguments);
So setScope becomes:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
return f.apply(scope, arguments);
}
}
Live example
Note that the usual name for this function, and the name it has in the new ECMAScript5 standard, is bind (Section 15.3.4.5; ECMAScript5's bind also lets you curry arguments, which isn't done by this implementation). setScope is a particularly unfortunate name, because it doesn't set the scope, it sets the context.
Having said all that, there's no reason you need setScope in your Person constructor. You can just do this:
Person = function () {
var self = this;
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return self.Name;
} else {
self.Name = value;
}
};
return _public;
};
Live example
But using bind (aka setScope) can be useful in places where you don't want a new closure over the context in which you're doing it.
Off-topic: The way you're specifying Person will break certain things people might expect to work, such as:
var p = new Person();
alert(p instanceof Person); // Expect "true", but in your case will be "false"
...because you're replacing the object new created for you, but returning a different object out of your constructor (which overrides the default).
Rather than creating a new object and returning that in your constructor, allow the object constructed for you by new to be the object (and thus the Person relationship is maintained), but you can still get truly private variables and use accessors:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = function(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
};
}
Live example
As you can see, this is dramatically simpler, and it preserves the instanceof relationship. Note that we're not qualifying our references to name within Name at all, and so we're using the local variable in the constructor call in which our Name function, which closes over it, was created.
I've also taken the liberty there of giving the constructor function a name, because I'm not a fan of anonymous functions. I should have given the accessor a name as well:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = Person_Name;
function Person_Name(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
}
}
Off-topic 2: The overwhelming convention in JavaScript code is to use initial caps on function names only for constructor functions (like Person), and not on other kinds of functions (like Name). You're free to do whatever you like, of course, but I thought I'd mention the convention, as it makes it easier for other people to read your code.
Worth noting: All of these techniques result in every single Person object having its own copy of the accessor function. If there are going to be a lot of these objects, that could be a memory issue. If there are only going to be a few, that's fine.
First thing, I think the correct way to go about this is the "closure" method, as the syntax is easier and simpler to understand and makes more sense and most object oriented code written in Javascript is written that way. Another thing to note is that in your method, the "private" member can be accessed from outside by accessing Person.Name (instead of (new Person()).Name).
That being said, it seems that you want something like Prototype.JS's bind method, which allows you to bind a function reference as a method call to a specific object, and also passes all the arguments correctly (including allowing preloaded arguments).
Look at Prototype.JS source for the complete implementation, but a simple implementation of this semantic might look like this:
Function.prototype.bind = function(context) {
var callee = this;
var args = Array.prototype.slice.call(arguments,1);
return function() {
var newargs = args.concat(Array.prototype.slice.call(arguments,0));
return callee.apply(context, newargs);
};
};
It is difficult to understand what you are trying to achieve. But if I guess that you are trying to create a Person class with a name method to get/set the person's name, here is my suggestion:
function Person() {
this._name = undefined; // not required but is better than assigning a fake name
return this;
}
Person.prototype.name = function( _name ) {
if ( _name === undefined ) return this._name; // get
return this._name = _name; // set
}
Note that I have defined the name function with a lower case first letter. This is standard practice in JavaScript where only constructors are usually capitalized. To use this class you do:
person = new Person();
person.name( "Ermes Enea Colella" );
alert( person.name ); // displays "Ermes Enea Colella"
There is no need to bind any context with this method, so you may be looking for something else. If you can clarify your need, I'll be happy to edit my answer.
I hope this helps.