1

I'm looking for a way to create a custom Object() object. I want a way to check the what a given object is an instance of. I need a way of differentiating the custom object from the native.

function CustomObj (data) {
  if (data) return data
  return {}
}
CustomObj.prototype = Object.prototype

var custom = new CustomObj()
var content = new CustomObj({'hello', 'world'})
var normal = new Object()

console.log(custom) // => {}
console.log(content) // => {'hello', 'world'}
console.log(custom instanceof CustomObj) // => true (expected: true)
console.log(content instanceof CustomObj) // => true (expected: true)
console.log(custom instanceof Object) // => true (expected: false)
console.log(content instanceof Object) // => true (expected: false)
console.log(normal instanceof CustomObj) // => true (expected: false)
console.log(normal instanceof Object) // => true (expected: true)

I'm assuming that this is because I'm inheriting the prototypes from Object. I tried adding a this.name but it didn't change instanceof.

ThomasReggi
  • 55,053
  • 85
  • 237
  • 424
  • _"I tried adding a `this.name`"_ So, you added a `name` property to your Object, what did you expect to change? – blex Aug 21 '15 at 19:53
  • @blex I expected that `custom.constructor.name` would change and that `instanceOf` would use that name to detect what the object is an `instanceOf`. – ThomasReggi Aug 21 '15 at 19:54
  • An object in JavaScript is always going to inherit from Object. – Adam Aug 21 '15 at 19:55
  • @Adam Ok, how is that help me achieve what I'm trying to do? – ThomasReggi Aug 21 '15 at 19:56
  • @Adam - `Object.create(null)` – Amit Aug 21 '15 at 19:56
  • @ThomasReggi - what *are you really* trying to achieve? What's the purpose of this? – Amit Aug 21 '15 at 19:57
  • yeah, you can do it. Check here http://stackoverflow.com/questions/1919295/can-i-set-the-type-of-a-javascript-object , there are a couple of solutions. – looshi Aug 21 '15 at 20:00
  • @Amit Kind of complicated, I'm trying to detect if the return value from this promise is the original object. https://gist.github.com/reggi/cddbc7c961d9c5d2ca77 – ThomasReggi Aug 21 '15 at 20:01
  • Yeah you're right, it's complicated. Probably unnecessarily complicated. And it appears on first sight that there are some logical mistakes, but again, too complicated to know. I'd suggest you post that code as a question, explain what you're trying to achieve and why what you've tried isn't working. My gut tells me you'll end up with something completely different – Amit Aug 21 '15 at 20:12
  • @Amit this is the simplest way to solve my problem within Javascript, and I was curious why the behavior of `instanceof` did not work as I expected. I'll consider opening a new question, but I'd still like a solution to this question, independent of my use-case. – ThomasReggi Aug 21 '15 at 20:30
  • @ThomasReggi do you need the standard `Object` methods to exist for your custom object (for example `hasOwnProperty`)? And why do you need `... instanceof Object` to equal false? – Amit Aug 21 '15 at 21:47
  • @Amit here's the post http://stackoverflow.com/questions/32149895/keeping-track-of-variable-instances – ThomasReggi Aug 21 '15 at 22:05
  • @Amit I guess I don't need `instanceOf` to work both ways I just need some way of knowing that the custom object is different from a normal Object. As in both `custom` and `normal` can be `instanceof` `Object` but `normal` can't be an `instanceof` `Custom`. – ThomasReggi Aug 21 '15 at 22:06

3 Answers3

0

I believe this satisfies your requirements. Note that properties of the prototype need to be defined in the constructor using this solution as the prototype will be overridden.

function CustomObj (data) {
  CustomObj.prototype = Object.create(null)
  CustomObj.prototype.x = "Hello world!"

  return Object.create(CustomObj.prototype)
}

var custom = new CustomObj()
var normal = new Object()

console.log(custom.x); // => "Hello world!" (expected: "Hello world!")
console.log(custom instanceof CustomObj) // => true (expected: true)
console.log(custom instanceof Object) // => false (expected: false)
console.log(normal instanceof CustomObj) // => false (expected: false)
console.log(normal instanceof Object) // => true (expected: true)
Adam
  • 2,204
  • 2
  • 15
  • 15
  • Thanks a bunch for this. However, it doesn't fulfill one major requirement and that is that the `data` is the return value from the `customObject`. Regardless if something is passed into `CustomObj` or not. – ThomasReggi Aug 21 '15 at 20:18
  • 1. You're not doing anything with `data`, why is it there? 2. Redefining `CustomObj.prototype` on each call is pointless. Do it only one time, and not inside the function. 3. A constructor function's return value is ignored when used to construct an object (`new ...`). 4. You no longer have the standard object methods. 5. I see you changed your mind regarding inheritance of `Object`. – Amit Aug 21 '15 at 20:22
  • I'm thinking about this like I want to create a custom Object Object. Objects take data. `new Object({'hello': 'world'})` or `new Object()`, and return data. – ThomasReggi Aug 21 '15 at 20:25
  • @ThomasReggi my comment was directed at Adam, not you. For you see my comment on the question itself. – Amit Aug 21 '15 at 20:27
  • 1
    @Amit 1. Not knowíng more about what data is, I suppose its properties could be copied onto the prototype of CustomObj in the constructor. 2. Please post your solution. 3. Then how come removing the return statement create a different result? 4. Why would they be needed? Please give an example. 5. I did. Thank you for sharing your knowledge. – Adam Aug 21 '15 at 20:34
  • @Adam - I'm just commenting from mobile so can't post a full, validated answer. I can however draw attention to inaccuracies/mistakes and help people learn (just like I showed you regarding inheritance). Regarding 3, I don't know what you're seeing, but try `function a(){return 1}alert(new a())` - it won't be 1. Regarding 4, I don't know but that seems to be the intention of OP. Regarding 5, maybe I shouldn't have been "suggestive" like that, I just felt a thank you was in order, so sorry – Amit Aug 21 '15 at 20:54
  • 1
    @Amit `A constructor function's return value is ignored` this is true only if the returned value is not an object. – Mihai Vilcu Aug 21 '15 at 20:59
0

This answer is wrong. I'm keeping it here because the comments might be useful to understand the question.

The reason all your expressions evaluate to true is that instanceof searches for the prototype of the right-hand constructor (the "type") in the left-hand's instance prototype chain. The prototype of Object and the prototype of CustomObj are identical so the expression evaluates to true in all your cases

Amit
  • 45,440
  • 9
  • 78
  • 110
  • I actually think it's because I'm returning a generic object, which is an `instanceof` Object. All of this information is great but it's not an answer :) – ThomasReggi Aug 21 '15 at 21:07
  • @ThomasReggi - Respectfully, my answer explains why your expressions evaluated to true. It's based on facts, not assumptions. That's just how `instancrof` is defined. Whether this satisfies you as an answer, that's entirely your decision to make, and I only hope this answer helps you understand. As you wrote in the comment to your question, independently of your use case, you wanted to understand the issue... – Amit Aug 21 '15 at 21:12
  • I'm saying I believe this answer to be an incorrect description of what's happening, it has nothing to do with prototypes. the return value from the `CustomObj` is a generic object `{}` and it is an instance of `Object`. That's why `instanceOf` is false. – ThomasReggi Aug 21 '15 at 21:17
  • @ThomasReggi - got it. You're right. I didn't notice this part. I think you can put this question to rest now (either post your own answer, or delete it completely) – Amit Aug 21 '15 at 21:20
  • I don't believe I've gotten an answer to this question yet, are you implying there's no way to create a custom generic object? – ThomasReggi Aug 21 '15 at 21:22
  • I'm just not entirely sure what you mean by "*custom generic object*", or what your ultimate goal is. Are you just trying to have a type that has no features of its own? If so, just create a constructor that does nothing, but that's obviously not what you're after – Amit Aug 21 '15 at 21:26
  • Perhaps the term is `object literal`. I want a custom object literal constructor, that does nothing but return an object literal who's constructor is the custom one. – ThomasReggi Aug 21 '15 at 21:28
  • Well that is definitely not possible. You can't override the default behavior of an object literal. What you can do is extend `Object` with the functionality you'd like to add but that's a generally bad idea. That brings things back to what I recommended before post a question that explains your use case, show what you tried and why it's not working. Personally I'll be glad to take a stab at an answer one you do that :-) – Amit Aug 21 '15 at 21:34
0
function Custom (literal) {
  if (literal) return literal
  return {}
}
Custom.prototype = Object.prototype
Custom.prototype.constructor = Custom

var foo = new Custom()

if (foo.constructor.name === 'Custom') {
  // foo is a custom object literal
}

// However it registers as an instance of both `Custom` and `Object`
console.log(foo instanceof Custom) // => true
console.log(foo instanceof Object) // => true
console.log({} instanceof Custom) // => true
console.log({} instanceof Object) // => true
ThomasReggi
  • 55,053
  • 85
  • 237
  • 424