How to create class using object literal notation in javascript? - javascript

I want to create a class in Java Script. I can use basic functions coupled with prototypes but I want to use Object Literal Notation. Is is possible to create classes using Object Literal Notations?

You cannot create an instance of an object (and yes, you could even see functions as objects in Javascript, but I'm talking about literal defined objects), you must use a function to define a reusable class.

Cannot be done....well, depends on how you define the params of the requirements. Should be done? Up for debate.
The following is from an idea a coworker of mine had.
http://bit.ly/18xGdKi [JSBin with console example]
if (typeof (makeClass) === "undefined") {
makeClass = function(o) {
var F = function () {};
if (typeof (o) === "object" && o !== null) {
if (typeof (o.constructor) === "function") {
F = o.constructor;
}
F.prototype = o;
}
return F;
};
}
var MyClass = makeClass({
constructor: function (pName) {
var _myPrivateIdaho = 'Idaho ' + pName;
this.name = pName;
var _myPrivateFunc = function() {
console.log('You are in my ' +
_myPrivateIdaho +'.');
};
_myPrivateFunc();
},
getName: function() {
return this.name;
}
});
new MyClass('Bob');
new MyClass('Steve');

Related

Which logger architecture in javascript? [duplicate]

Is there a way to make any function output a console.log statement when it's called by registering a global hook somewhere (that is, without modifying the actual function itself) or via some other means?
Here's a way to augment all functions in the global namespace with the function of your choice:
function augment(withFn) {
var name, fn;
for (name in window) {
fn = window[name];
if (typeof fn === 'function') {
window[name] = (function(name, fn) {
var args = arguments;
return function() {
withFn.apply(this, args);
return fn.apply(this, arguments);
}
})(name, fn);
}
}
}
augment(function(name, fn) {
console.log("calling " + name);
});
One down side is that no functions created after calling augment will have the additional behavior.
As to me, this looks like the most elegant solution:
(function() {
var call = Function.prototype.call;
Function.prototype.call = function() {
console.log(this, arguments); // Here you can do whatever actions you want
return call.apply(this, arguments);
};
}());
Proxy Method to log Function calls
There is a new way using Proxy to achieve this functionality in JS.
assume that we want to have a console.log whenever a function of a specific class is called:
class TestClass {
a() {
this.aa = 1;
}
b() {
this.bb = 1;
}
}
const foo = new TestClass()
foo.a() // nothing get logged
we can replace our class instantiation with a Proxy that overrides each property of this class. so:
class TestClass {
a() {
this.aa = 1;
}
b() {
this.bb = 1;
}
}
const logger = className => {
return new Proxy(new className(), {
get: function(target, name, receiver) {
if (!target.hasOwnProperty(name)) {
if (typeof target[name] === "function") {
console.log(
"Calling Method : ",
name,
"|| on : ",
target.constructor.name
);
}
return new Proxy(target[name], this);
}
return Reflect.get(target, name, receiver);
}
});
};
const instance = logger(TestClass)
instance.a() // output: "Calling Method : a || on : TestClass"
check that this actually works in Codepen
Remember that using Proxy gives you a lot more functionality than to just logging console names.
Also this method works in Node.js too.
If you want more targeted logging, the following code will log function calls for a particular object. You can even modify Object prototypes so that all new instances get logging too. I used Object.getOwnPropertyNames instead of for...in, so it works with ECMAScript 6 classes, which don't have enumerable methods.
function inject(obj, beforeFn) {
for (let propName of Object.getOwnPropertyNames(obj)) {
let prop = obj[propName];
if (Object.prototype.toString.call(prop) === '[object Function]') {
obj[propName] = (function(fnName) {
return function() {
beforeFn.call(this, fnName, arguments);
return prop.apply(this, arguments);
}
})(propName);
}
}
}
function logFnCall(name, args) {
let s = name + '(';
for (let i = 0; i < args.length; i++) {
if (i > 0)
s += ', ';
s += String(args[i]);
}
s += ')';
console.log(s);
}
inject(Foo.prototype, logFnCall);
Here's some Javascript which replaces adds console.log to every function in Javascript; Play with it on Regex101:
$re = "/function (.+)\\(.*\\)\\s*\\{/m";
$str = "function example(){}";
$subst = "$& console.log(\"$1()\");";
$result = preg_replace($re, $subst, $str);
It's a 'quick and dirty hack' but I find it useful for debugging. If you have a lot of functions, beware because this will add a lot of code. Also, the RegEx is simple and might not work for more complex function names/declaration.
You can actually attach your own function to console.log for everything that loads.
console.log = function(msg) {
// Add whatever you want here
alert(msg);
}

javascript's different extend methods

What is the difference between extend methods in JavaScript?
Let's say we have the following classes:
var BaseClass = function() {
this.class_name = 'BaseClass';
this.foo = function() {
return 'foo';
}
this.sub = {
moreStuff: 'weeee'
}
};
BaseClass.prototype.bar = function () {
return 'To be or not to be';
}
var SubClass = function() {
this.class_name = 'SubClass';
this.bar = function() {
return 'bar';
}
this.sub = {
moreStuff: 'wooohooo'
}
};
Method A:
SubClass.prototype = new BaseClass();
SubClass.prototype.constructor = SubClass;
Method B (from underscore.js):
_.extend = function(obj) {
each(slice.call(arguments, 1), function(source) {
if (source) {
for (var prop in source) {
obj[prop] = source[prop];
}
}
});
return obj;
};
Method C (from LiveScript):
function extend$(sub, sup){
function fun(){}
fun.prototype = (sub.superclass = sup).prototype;
(sub.prototype = new fun).constructor = sub;
if (typeof sup.extended == 'function') sup.extended(sub);
return sub;
}
Method A looks simpler. Why go through the trouble of copying the object, one property at a time?
Yes, Method A looks simpler but using it you can inherit only from one object. What if you want your SubClass to inherit from BaseClassOther as well. In this case you should go for the Method B ( to inherit from BaseClassOther as well).
You can not do
SubClass.prototype = new BaseClassOther();
again this will overwrite prototype property.
Please have a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
In Method A, in other circumstances, BaseClass() might be written to require an argument and to fail if it does not receive a valid one. The other two methods are not bothered by this. Perhaps the inherited constructors you are working with are not bothered by this either.

How do get the name of a calling function in Javascript?

Consider the following example.
var obj = function(){};
function apply(target, obj) {
if (target && obj && typeof obj == "object") {
for (var prop in obj) {
target[prop] = obj[prop];
}
}
return target;
}
apply(obj.prototype, {
firstFunction: function (){
this.secondFunction();
},
secondFunction: function (){
// how do I know what function called me here?
console.log("Callee Name: '" + arguments.callee.name + "'");
console.log("Caller Name: '" + arguments.callee.caller.name + "'");
}
});
var instance = new obj();
instance.firstFunction();
UPDATE
Both answers are really awesome. Thank you. I then looked into the problem of calling a recursive, or parent function within an object and found a solution here. This would allow me to retrieve the function name without using the arguments.callee/caller properties.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/function
A function's name is an immutable property of that function, set in the initial function expression.
var notTheName = function thisIsTheName() { ... }
someObj.stillNotTheName = function stillTheName() { ... }
If your function expression does not have a name, there is (unsurprisingly) no way to identify it by name. Assigning a function to a variable does not give it a name; if that were the case, you could not determine the name of an expression assigned to multiple variables.
You should set firstFunction's name property by expressing it as
firstFunction: function firstFunction(){
this.secondFunction();
}
Also, arguments.callee is deprecated. See Why was the arguments.callee.caller property deprecated in JavaScript? for a very good explanation of the history of arguments.callee.
Give name to the functions
like:
var obj = function(){};
function apply(target, obj) {
if (target && obj && typeof obj == "object") {
for (var prop in obj) {
target[prop] = obj[prop];
}
}
return target;
}
apply(obj.prototype, {
firstFunction: function firstFunction(){
this.secondFunction();
},
secondFunction: function secondFunction(){
// how do I know what function called me here?
console.log("Callee Name: '" + arguments.callee.name + "'");
console.log("Caller Name: '" + arguments.callee.caller.name + "'");
}
});
var instance = new obj();
instance.firstFunction();
take a look on this question

How to get to my ancestor’s overridden method using Crockfords's Object.create() (Javascript)

if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
var o1 = {};
o1.init = function(){
alert('o1');
};
var o2 = Object.create(o1);
o2.init = function(){
// how would I call my ancessors init()?
alert('o2');
};
o2.init();
JavaScript functions are objects and have two useful methods to invoke the function:
Function.call(scope, [arg1, ...])
Function.apply(scope, args)
You can use one of these to call the parent implementation, explicitely passing this as the scope parameter, so that in the parent implementation, this refers to the child object:
var o1 = {
name : "One",
init : function() {
alert("o1: " + this.name);
}
};
var o2 = Object.create(o1);
o2.name = "Two";
o2.init = function() {
o1.init.call(this);
alert("o2: " + this name);
};
This will alert: o1: Two and o2: Two.
Maybe this is oversimplifying what you’re trying to accomplish ... would placing o1.init() in the o2 init function work?
o2.init = function(){
// how would I call my ancessors init()?
alert('o2');
o1.init();
};
Out of curiosity, was "ancessors" a spelling error for "ancestor’s" or does "ancessors" mean something specific here? Did you mean o2’s "parent" object?
In browsers that support it, you could use the Object.getPrototypeOf function, like this:
o2.init = function(){
Object.getPrototypeOf(this).init.call(this);
alert('o2');
};
This would get the prototype of o2 (o1) and apply its init method to this (o2), just like a super.init() in other languages.
UPDATE:
The Object.getPrototypeOf function could be implemented like this:
if ( typeof Object.getPrototypeOf !== "function" )
{
if ( typeof ({}).__proto__ === "object" )
{
Object.getPrototypeOf = function(object)
{
return object.__proto__;
};
}
else
{
Object.getPrototypeOf = function(object)
{
// May break if the constructor has been tampered with
return object.constructor.prototype;
};
}
}
Found on this link: http://ejohn.org/blog/objectgetprototypeof/

How to determine if an object is an object literal in Javascript?

Is there any way to determine in Javascript if an object was created using object-literal notation or using a constructor method?
It seems to me that you just access it's parent object, but if the object you are passing in doesn't have a reference to it's parent, I don't think you can tell this, can you?
What you want is:
Object.getPrototypeOf(obj) === Object.prototype
This checks that the object is a plain object created with either new Object() or {...} and not some subclass of Object.
I just came across this question and thread during a sweet hackfest that involved a grail quest for evaluating whether an object was created with {} or new Object() (i still havent figured that out.)
Anyway, I was suprised to find the similarity between the isObjectLiteral() function posted here and my own isObjLiteral() function that I wrote for the Pollen.JS project. I believe this solution was posted prior to my Pollen.JS commit, so - hats off to you! The upside to mine is the length... less then half (when included your set up routine), but both produce the same results.
Take a look:
function isObjLiteral(_obj) {
var _test = _obj;
return ( typeof _obj !== 'object' || _obj === null ?
false :
(
(function () {
while (!false) {
if ( Object.getPrototypeOf( _test = Object.getPrototypeOf(_test) ) === null) {
break;
}
}
return Object.getPrototypeOf(_obj) === _test;
})()
)
);
}
Additionally, some test stuff:
var _cases= {
_objLit : {},
_objNew : new Object(),
_function : new Function(),
_array : new Array(),
_string : new String(),
_image : new Image(),
_bool: true
};
console.dir(_cases);
for ( var _test in _cases ) {
console.group(_test);
console.dir( {
type: typeof _cases[_test],
string: _cases[_test].toString(),
result: isObjLiteral(_cases[_test])
});
console.groupEnd();
}
Or on jsbin.com...
http://jsbin.com/iwuwa
Be sure to open firebug when you get there - debugging to the document is for IE lovers.
Edit: I'm interpreting "object literal" as anything created using an object literal or the Object constructor. This is what John Resig most likely meant.
I have a function that will work even if .constructor has been tainted or if the object was created in another frame. Note that Object.prototype.toString.call(obj) === "[object Object]" (as some may believe) will not solve this problem.
function isObjectLiteral(obj) {
if (typeof obj !== "object" || obj === null)
return false;
var hasOwnProp = Object.prototype.hasOwnProperty,
ObjProto = obj;
// get obj's Object constructor's prototype
while (Object.getPrototypeOf(ObjProto = Object.getPrototypeOf(ObjProto)) !== null);
if (!Object.getPrototypeOf.isNative) // workaround if non-native Object.getPrototypeOf
for (var prop in obj)
if (!hasOwnProp.call(obj, prop) && !hasOwnProp.call(ObjProto, prop)) // inherited elsewhere
return false;
return Object.getPrototypeOf(obj) === ObjProto;
};
if (!Object.getPrototypeOf) {
if (typeof ({}).__proto__ === "object") {
Object.getPrototypeOf = function (obj) {
return obj.__proto__;
};
Object.getPrototypeOf.isNative = true;
} else {
Object.getPrototypeOf = function (obj) {
var constructor = obj.constructor,
oldConstructor;
if (Object.prototype.hasOwnProperty.call(obj, "constructor")) {
oldConstructor = constructor;
if (!(delete obj.constructor)) // reset constructor
return null; // can't delete obj.constructor, return null
constructor = obj.constructor; // get real constructor
obj.constructor = oldConstructor; // restore constructor
}
return constructor ? constructor.prototype : null; // needed for IE
};
Object.getPrototypeOf.isNative = false;
}
} else Object.getPrototypeOf.isNative = true;
Here is the HTML for the testcase:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<!-- Online here: http://code.eligrey.com/testcases/all/isObjectLiteral.html -->
<title>isObjectLiteral</title>
<style type="text/css">
li { background: green; } li.FAIL { background: red; }
iframe { display: none; }
</style>
</head>
<body>
<ul id="results"></ul>
<script type="text/javascript">
function isObjectLiteral(obj) {
if (typeof obj !== "object" || obj === null)
return false;
var hasOwnProp = Object.prototype.hasOwnProperty,
ObjProto = obj;
// get obj's Object constructor's prototype
while (Object.getPrototypeOf(ObjProto = Object.getPrototypeOf(ObjProto)) !== null);
if (!Object.getPrototypeOf.isNative) // workaround if non-native Object.getPrototypeOf
for (var prop in obj)
if (!hasOwnProp.call(obj, prop) && !hasOwnProp.call(ObjProto, prop)) // inherited elsewhere
return false;
return Object.getPrototypeOf(obj) === ObjProto;
};
if (!Object.getPrototypeOf) {
if (typeof ({}).__proto__ === "object") {
Object.getPrototypeOf = function (obj) {
return obj.__proto__;
};
Object.getPrototypeOf.isNative = true;
} else {
Object.getPrototypeOf = function (obj) {
var constructor = obj.constructor,
oldConstructor;
if (Object.prototype.hasOwnProperty.call(obj, "constructor")) {
oldConstructor = constructor;
if (!(delete obj.constructor)) // reset constructor
return null; // can't delete obj.constructor, return null
constructor = obj.constructor; // get real constructor
obj.constructor = oldConstructor; // restore constructor
}
return constructor ? constructor.prototype : null; // needed for IE
};
Object.getPrototypeOf.isNative = false;
}
} else Object.getPrototypeOf.isNative = true;
// Function serialization is not permitted
// Does not work across all browsers
Function.prototype.toString = function(){};
// The use case that we want to match
log("{}", {}, true);
// Instantiated objects shouldn't be matched
log("new Date", new Date, false);
var fn = function(){};
// Makes the function a little more realistic
// (and harder to detect, incidentally)
fn.prototype = {someMethod: function(){}};
// Functions shouldn't be matched
log("fn", fn, false);
// Again, instantiated objects shouldn't be matched
log("new fn", new fn, false);
var fn2 = function(){};
log("new fn2", new fn2, false);
var fn3 = function(){};
fn3.prototype = {}; // impossible to detect (?) without native Object.getPrototypeOf
log("new fn3 (only passes with native Object.getPrototypeOf)", new fn3, false);
log("null", null, false);
log("undefined", undefined, false);
/* Note:
* The restriction against instantiated functions is
* due to the fact that this method will be used for
* deep-cloning an object. Instantiated objects will
* just have their reference copied over, whereas
* plain objects will need to be completely cloned.
*/
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var doc = iframe.contentDocument || iframe.contentWindow.document;
doc.open();
doc.write("<body onload='window.top.iframeDone(Object);'>");
doc.close();
function iframeDone(otherObject){
// Objects from other windows should be matched
log("new otherObject", new otherObject, true);
}
function log(msg, a, b) {
var pass = isObjectLiteral(a) === b ? "PASS" : "FAIL";
document.getElementById("results").innerHTML +=
"<li class='" + pass + "'>" + msg + "</li>";
}
</script>
</body>
</html>
It sounds like you are looking for this:
function Foo() {}
var a = {};
var b = new Foo();
console.log(a.constructor == Object); // true
console.log(b.constructor == Object); // false
The constructor property on an object is a pointer to the function that is used to construct it. In the example above b.constructor == Foo. If the object was created using curly brackets (the array literal notation) or using new Object() then its constructor property will == Object.
Update: crescentfresh pointed out that $(document).constructor == Object rather than being equal to the jQuery constructor, so I did a little more digging. It seems that by using an object literal as the prototype of an object you render the constructor property almost worthless:
function Foo() {}
var obj = new Foo();
obj.constructor == Object; // false
but:
function Foo() {}
Foo.prototype = { objectLiteral: true };
var obj = new Foo();
obj.constructor == Object; // true
There is a very good explanation of this in another answer here, and a more involved explanation here.
I think the other answers are correct and there is not really a way to detect this.
An object literal is the notation you use to define an object - which in javascript is always in the form of a name-value pair surrounded by the curly brackets. Once this has been executed there is no way to tell if the object was created by this notation or not (actually, I think that might be an over-simplification, but basically correct). You just have an object. This is one of the great things about js in that there are a lot of short cuts to do things that might be a lot longer to write. In short, the literal notation replaces having to write:
var myobject = new Object();
I had the same issue, so I decide to go this way:
function isPlainObject(val) {
return val ? val.constructor === {}.constructor : false;
}
// Examples:
isPlainObject({}); // true
isPlainObject([]); // false
isPlainObject(new Human("Erik", 25)); // false
isPlainObject(new Date); // false
isPlainObject(new RegExp); // false
//and so on...
There is no way to tell the difference between an object built from an object literal, and one built from other means.
It's a bit like asking if you can determine whether a numeric variable was constructed by assigning the value '2' or '3-1';
If you need to do this, you'd have to put some specific signature into your object literal to detect later.
Nowaday there is a more elegant solution that respond exactly to your question:
function isObject(value) {
return value !== null && value !== undefined && Object.is(value.constructor, Object)
}
// Test stuff below //
class MyClass extends Object {
constructor(args) {
super(args)
}
say() {
console.log('hello')
}
}
function MyProto() {
Object.call(this)
}
MyProto.prototype = Object.assign(Object.create(Object.prototype), {
constructor: MyProto,
say: function() {
console.log('hello')
}
});
const testsCases = {
objectLiteral: {},
objectFromNew: new Object(),
null: null,
undefined: undefined,
number: 123,
function: new Function(),
array: new Array([1, 2, 3]),
string: new String('foobar'),
image: new Image(),
bool: true,
error: new Error('oups'),
myClass: new MyClass(),
myProto: new MyProto()
}
for (const [key, value] of Object.entries(testsCases)) {
console.log(`${key.padEnd(15)} => ${isObject(value)}`)
}
Best regards
typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === Object.prototype
below all return false
123
null
undefined
'abc'
false
true
[]
new Number()
new Boolean()
() => {}
function () {}
an improvement over jesse's answer
11 year old question here is my tidy solution, open to edge case suggestions;
steps -> look for objects only then compare to check properties -> object literals do not have length, prototype and for edge case stringyfy properties.
tried in test for JSON and
Object.create(Object.create({cool: "joes"})).
"use strict"
let isObjectL = a => {
if (typeof a !=='object' || ['Number','String','Boolean', 'Symbol'].includes(a.constructor.name)) return false;
let props = Object.getOwnPropertyNames(a);
if ( !props.includes('length') && !props.includes('prototype') || !props.includes('stringify')) return true;
};
let A={type:"Fiat", model:"500", color:"white"};
let B= new Object();
let C = { "name":"John", "age":30, "city":"New York"};
let D= '{ "name":"John", "age":30, "city":"New York"}';
let E = JSON.parse(D);
let F = new Boolean();
let G = new Number();
console.log(isObjectL(A));
console.log(isObjectL(B));
console.log(isObjectL(C));
console.log(isObjectL(D));
console.log(isObjectL(E));
console.log(isObjectL(JSON));
console.log(isObjectL(F));
console.log(isObjectL(G));
console.log(isObjectL(
Object.create(Object.create({cool: "joes"}))));
console.log(isObjectL());
Another variant showing inner working
isObject=function(a) {
let exclude = ['Number','String','Boolean', 'Symbol'];
let types = typeof a;
let props = Object.getOwnPropertyNames(a);
console.log((types ==='object' && !exclude.includes(a.constructor.name) &&
( !props.includes('length') && !props.includes('prototype') && !props.includes('stringify'))));
return `type: ${types} props: ${props}
----------------`}
A={type:"Fiat", model:"500", color:"white"};
B= new Object();
C = { "name":"John", "age":30, "city":"New York"};
D= '{ "name":"John", "age":30, "city":"New York"}';
E = JSON.parse(D);
F = new Boolean();
G = new Number();
console.log(isObject(A));
console.log(isObject(B));
console.log(isObject(C));
console.log(isObject(D));
console.log(isObject(E));
console.log(isObject(JSON));
console.log(isObject(F));
console.log(isObject(G));
console.log(isObject(
Object.create(Object.create({cool: "joes"}))));

Categories