0
  1. I am trying to use the Factory pattern to create a Person object in javascript. While doing this I am trying to set the property of a function to non enumerable while creating the object. But that does not seem to take effect , please can you tell me why it is still enumerating the function property.

  2. In the defineProperty call, when I pass only the function name I get a error stating that printPersonDetails is undefined. I have to pass obj.printPersonDetails to make it work.


function createPerson(name, age ,sex){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sex = sex;
obj.printPersonDetails = function(){
console.log("Name: "+ obj.name + " Age: "+ obj.age);
}
Object.defineProperty(obj,obj.printPersonDetails , {                
    writeable:false,
        enumerable:false,
        configurable: false
    });

return obj;
}
var person1 = createPerson("salman", 29,"M");
var person2 = createPerson("rahman", 59,"M");
var person3 = createPerson("sarah",  19,"F");

//person1.printPersonDetails();
//console.log(person1)

for(prop in person1){
console.log( prop +"->" + person1[prop])}

Output

C:\dev\javascript>node constructorpattern.js
name->salman
age->29
sex->M
printPersonDetails->function (){
    console.log("Name: "+ obj.name + " Age: "+ obj.age);
    }
1
  • for(prop in person1) is creating a global variable, which you should almost always avoid. Commented Jul 9, 2016 at 17:10

2 Answers 2

1

That's just not how you use Object.defineProperty. Here's an example:

Object.defineProperty(obj, "printPersonDetails", {
    value: function(){
        console.log("Name: "+ obj.name + " Age: "+ obj.age);
    }
});

Object.defineProperty accepts various flags (writable, enumerable, configurable) which default to false. So by not doing enumerable: true we've made the property referring to the function non-enumerable.

Here's a complete createPerson, which uses defineProperty for the function and object initializer syntax for the rest of the object:

function createPerson(name, age ,sex){
  var obj = {
    name: name,
    age: age,
    sex: sex
  };
  Object.defineProperty(obj, "printPersonDetails", {
    value: function(){
      console.log("Name: "+ obj.name + " Age: "+ obj.age);
    }
  });
  return obj;
}

var person1 = createPerson("salman", 29,"M");
for (var prop in person1) {
    console.log(prop + "->" + person1[prop]);
}


Side note: There's virtually never any reason to use new Object(). Just use {}.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Crowder.. Thanks for the tip to use {} instead of new Object().
0

Wrong:

obj.printPersonDetails = function(){
  console.log("Name: "+ obj.name + " Age: "+ obj.age);
}

Object.defineProperty(obj,obj.printPersonDetails , {                
  writeable:false,
  enumerable:false,
  configurable: false
});

Right:

function printPersonDetails(){
  console.log("Name: "+ this.name + " Age: "+ this.age);
}

Object.defineProperty(obj, 'printPersonDetails' , {                
  writeable:false,
  enumerable:false,
  configurable: false,
  value: printPersonDetails
});

BUT, what I think you really want to do is put the utility function on another object.

JavaScript has built-in support for keeping functionality off object instances: the prototype (although this does not solve the for..in issue).

So instead of:

var obj = new Object();

you could use:

var obj = Object.create({ printPersonDetails });

And then instead of for...in you could use Object.keys to avoid seeing the property.

The other approach is to keep the printPersonalDetails function on another object entirely (which is probably what I would do).

Edit:

The following is merely food for thought and not a recommendation:

var DEFAULT_PROPERTIES = {
  name: null,
  age: null,
  eyeColor: null,
  sex: null,
};

function personFactory(options){
  return Object.assign({}, DEFAULT_PROPERTIES, options);
}

function personPrinter(person) {
   document.write("Name: "+ person.name + " Age: "+ person.age);
}

var person = personFactory({ name: "salman", age: 29, sex: "M" });
personPrinter(person);

4 Comments

Hi Ben, when you say "The other approach is to keep the printPersonalDetails function on another object entirely (which is probably what I would do)." - can you please provide a code snippet to illustrate this?
"JavaScript has built-in support for this: the prototype." No. Being on the prototype has nothing to do with whether a property is enumerable, and in fact your example (which relies on ES2015 syntax) would create an enumerable property that would show up in for-in loops on objects created via createPerson. You could create a prototype object with a non-enumerable printPersonDetails, but it would rely on this, which is typically what people are trying to avoid with things like createPerson.
I know. I am making the distinction between own and non-own properties (not enumerability).
I have clarified my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.