argon argon - 6 months ago 17
Javascript Question

JavaScript - access to properties after (closure).bind()

I've constructed a rather useful function to identify data-types; however, while coding happily I was rudely interrupted with a rather worrying dilemma.

As you may know, after calling

.bind({foo:'bar'})
on a closure, you cannot access said
foo
property "externally"; however, inside the closure,
this.foo
works.

Also, when assigning something in such a way, you often face a throw:
intermediary ... blah blah is undefined
when you try access a property - directly after defining it. The code below fixes these issues but...

The problem is explained after the code:

"use strict";

if ('undefined' == typeof global)
{
Object.defineProperty
(
window,'global',
{
writable:false,
configurable:false,
enumerable:false,
value:window
}
);
}


Object.defineProperty
(
Function.prototype, 'wrap',
{
writable:false,
enumerable:false,
configurable:false,

value:function(jsob)
{
this.bind(jsob);

for (var i in jsob)
{ this[i] = jsob[i]; }

return this;
}
}
);


global.typeOf = function(data)
{
if ((data === null) || (data === undefined))
{ return 'void'; }

if ((data === true) || (data === false))
{ return 'bool'; }

var tpof = (({}).toString.call(data).match(/\s([a-zA-Z]+)/)[1].toLowerCase());

if ((tpof == 'array') || (tpof == 'htmlcollection') || (tpof == 'namednodemap'))
{ return 'list'; }

if ((tpof == 'global') || (tpof == 'window'))
{ return 'glob'; }

switch (tpof.substr(0,6))
{
case 'number': return 'unit';
case 'string': return (/[^\x20-\x7E\t\r\n]/.test(data) ? 'blob' : 'text');
case 'object': return 'jsob';
case 'functi': return 'func';

default: return 'node';
}
}
.wrap
({
list:'void bool unit text blob list jsob func node glob'.split(' '),
init:function()
{
this.list.forEach(function(item)
{
global[(item.toUpperCase())] = item;
global[('is'+(item[0].toUpperCase() + item.substr(1,item.length)))] = function(data)
{
return ((typeOf(data) == this.text) ? true : false);
}
.bind({text:item.toLowerCase()}); // <-- ISSUE
});

return this;
}
}).init();


So the little
wrapper
above takes care of such weirdness; however, have a look on the line where
<-- ISSUE
is; see, I cannot use
wrap()
there, I have to use
bind()
, else - inside the function -
this
is undefined!!

Let me clarify: If you use the entire code just as it is above in
<script>
tags inside a brand-spanking-new html file; just change that
ISSUE
line's
bind
word to:
wrap
; then try something like:
isText("bite me!");


You will see an error that specifies something like:


cannot read property "text" from undefined ..


so; if you do a
console.log(this)
inside that function definition there; you will see
undefined
.

If anyone could help fixing this, or at least explain why this is happening, I'd really appreciate the input.

Answer

I see absolutely no purpose for this wrap function. In fact there's no reason to use this or bind at all for this use case. Just do

global.typeOf = function(data) {
    if (data == null) return 'void';
    switch (typeof data)
        case "boolean": return 'bool';
        case "number": return 'unit';
        case "string": return /[^\x20-\x7E\t\r\n]/.test(data) ? 'blob' : 'text';
    }
    switch (Object.prototype.toString.call(data).slice(8, -1).toLowerCase()) {
        case "array":
        case "htmlcollection":
        case "namednodemap": return 'list';
        case "global":
        case "window": return 'glob';
        case "object": return 'jsob';
        case "function": return 'func';
        default: return 'node';
    }
};
global.typeOf.list = 'void bool unit text blob list jsob func node glob'.split(' ');

global.typeOf.list.forEach(function(item) {
    global[item.toUpperCase()] = item;
    global['is'+item[0].toUpperCase()+item.slice(1)] = function(data) {
        return typeOf(data) == item;
    }
});