Archive

Calender

«   2019/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

[ Javascript ] typeof VS Object.prototype.toString

1. 기본적인 사용법 ( How to use )


 
<button onclick="testing()"> Click me </button>

<p id="demo1"> </p>
<p id="demo2"> </p>

<script type="text/javascript">
function testing (){ 
    var text = "어쩌구저쩌구... blah blah blah... "; 

    demo1.innerHTML = typeof text; 
    demo2.innerHTML = Object.prototype.toString.call( text ); 
} 
</script>
 

Object.prototype.toString() 함수를 이용하려면, call() 함수를 사용해서 불러와야(call) 한다는 거!!
To use "Object.prototype.toString", call it using "call" function.

2. 문자 테스트 ( Test string )


 
<button onclick="testing()"> Click me </button>

<p id="demo1"> </p>
<p id="demo2"> </p>

<script type="text/javascript">
function testing (){ 
    var str = String( "blah blah blah... " ); 

    demo1.innerHTML = typeof str; 
    demo2.innerHTML = Object.prototype.toString.call( str ); 
} 
</script>
 

 
<button onclick="testing()"> Click me </button>

<p id="demo1"> </p>
<p id="demo2"> </p>

<script type="text/javascript">
function testing (){ 
    var str = new String( "blah blah blah... " ); 

    demo1.innerHTML = typeof str; 
    demo2.innerHTML = Object.prototype.toString.call( str ); 
} 
</script>
 

new String()이라고 작성하면, typeof 는 string 이 아니라 object 이라고 알려준다는 거!!
When you use "String()" with "new", typeof tells you that it's object, not string.

3. 숫자 테스트 ( Test number )


 
<button onclick="testing()"> Click me </button>

<p id="demo1"> </p>
<p id="demo2"> </p>

<script type="text/javascript">
function testing (){ 
    var num = 123; 

    demo1.innerHTML = typeof num; 
    demo2.innerHTML = Object.prototype.toString.call( num ); 
} 
</script>
 

 
<button onclick="testing()"> Click me </button>

<p id="demo1"> </p>
<p id="demo2"> </p>

<script type="text/javascript">
function testing (){ 
    var num = Number( 123 ); 

    demo1.innerHTML = typeof num; 
    demo2.innerHTML = Object.prototype.toString.call( num ); 
} 
</script>
 

 
<button onclick="testing()"> Click me </button>

<p id="demo1"> </p>
<p id="demo2"> </p>

<script type="text/javascript">
function testing (){ 
    var num = new Number( 123 ); 

    demo1.innerHTML = typeof num; 
    demo2.innerHTML = Object.prototype.toString.call( num ); 
} 
</script>
 

4. 배열 테스트 ( Test array )


 
<button onclick="testing()"> Click me </button>

<p id="demo1"> </p>
<p id="demo2"> </p>

<script type="text/javascript">
function testing (){ 
    var arr = [ "a", "b", "c" ]; 

    demo1.innerHTML = typeof arr; 
    demo2.innerHTML = Object.prototype.toString.call( arr ); 
} 
</script>
 

배열은 무조건 object 이라고 알려준다는 거!!
If it's an array, typeof always tells you that it's object, not array.

여기까지만 읽다보면, Object.prototype.toString 함수가 모든 문제를 해결해 줄 것 같지만...
If you just read this far, it seems that "Object.prototype.toString" would solve all the problems. But...

5. 그 밖의 것들 ( Other things )


 
<button onclick="testing()"> Click me </button>

<p id="demo1"> </p>

<script type="text/javascript">
function testing (){ 
    var style = demo1.style; 

    demo1.innerHTML = Object.prototype.toString.call( style ); 
} 
</script>
 

결과가 브라우저마다 다르게 나온다는 거!!
The result is different on each browser.

Chrome & Opera & Safari : [object CSSStyleDeclaration]
Firefox : [object CSS2Properties]
Internet Explorer : [object MSStyleCSSProperties]


 
<button onclick="testing()"> Click me </button>

<p id="demo1"> </p>

<script type="text/javascript">
function testing (){ 
    var proto = document.__proto__; 

    demo1.innerHTML = Object.prototype.toString.call( proto ); 
} 
</script>
 

Chrome & Opera : [object HTMLDocument]
Firefox & Explorer & Safari : [object HTMLDocumentPrototype]

6. 해결 방안 ( Solution )


그래서 getTypeof() 이라는 함수를 하나 만들어보았다.
So, I wrote "getTypeof" function.


일단, 아래의 세 함수를 먼저 작성한다.
Firstly, write the following three functions.


 
function getFunctionName ( fn ){ 

        if ( typeof fn !== 'function' ){ 
                if ( document.defaultView.alert == fn ) return 'alert'; 
                return ""; 
        } 

        var name = ""; 

        if (  !! (function x (){}).name ){  name = fn.name;  } 
        else { 
                name = Function.prototype.toString.call( obj ); 
                name = /^function[^\(]+/.exec( str )[ 0 ].substr( 7 ).trim();
        } 

        return name.replace( /anonymous[\s]*|bound (?=\w)/i, '' ); 
} 

function isNode ( obj ){  return obj && typeof obj.nodeType == 'number' && typeof obj.nodeName == 'string';  } 

function isElement ( obj ){  return isNode(obj) && obj.nodeType === 1;  } 
 

그러고 나서, getTypeof() 함수를 작성한다.
Then, write "getTypeof" function.



첫번째 방법 ( First way )

 
function getTypeof ( obj ){ 
        var str; 
        var typeA = typeof obj; 

        if ( typeA == 'undefined' ) return 'Undefined'; 
        if ( obj === null ) return 'Null'; 

        var toString = function ( obj ){ 
                var str = Object.prototype.toString.call( obj ); 
                return str.substr( 8, str.length - 9 ); 
        }; 

        var typeB = toString( obj ); 

        var doc = document; 
        var view = doc.defaultView; 

        switch ( true ){ 
                case ( obj == view.alert ) : return 'Function'; 

                case ( obj == doc ) : return 'Document'; 
                case ( obj == view ) : return 'Window'; 

                case ( obj == doc.__proto__ ) : return 'DocumentPrototype'; 
                case ( obj == view.__proto__ ) : return 'WindowPrototype'; 

                case isNode( obj ) : 

                        var name = obj.nodeName;

                        switch ( obj.nodeType ){ 

                                case 1 : return name.charAt( 0 ) + name.substr( 1 ).toLowerCase(); 
                                case 2 : return 'Attribute'; // attribute of element 
                                case 3 : return 'Text'; 

                                case 8 : return 'Comment'; 
                                // case 9 : return 'Document'; 

                                case 10 : return 'DocumentType'; // document.doctype 
                                case 11 : return 'Fragment';  // document.createDocumentFragment() 

                                /*  
                                 * if it's xml file, not html...  
                                 * 
                                 * case 4 : return 'CDATASection'; 
                                 * case 5 : return 'EntityReference'; 
                                 * case 6 : return 'Entity'; 
                                 * case 7 : return 'ProcessingInstruction'; 
                                 * case 12 : return 'Notation'; 
                                 */ 
                        } 

                        return; 

                case ( typeA == 'string' || typeB == 'String' ) : return 'String';  
                case ( typeA == 'number' || typeB == 'Number' ) : return 'Number'; 

                case ( obj.constructor && obj == obj.constructor.prototype ) : 

                        var ctor = obj.constructor; 

                        if ( typeof ctor == 'function' ){  str = getFunctionName( ctor );  } 
                        else {  str = typeB;  } 

                        return str + 'Prototype'; 

                default : 
                        if ( typeof obj.length == 'number' ){ 

                                if ( 'callee' in obj ) return 'Arguments'; 

                                if ( 'cssText' in obj ) return 'CSSStyle'; // style of element 

                                if ( typeof obj.item == 'function' ){ 
                                        /* 
                                         * childNodes :: NodeList , children :: HTMLCollection , classList :: DOMTokenList 
                                         * 
                                         * NodeList :: function item() , 
                                         * HTMLCollection :: function item() , function namedItem() , 
                                         * DOMTokenList :: function item() , function add() , function remove() , function toggle() , 
                                         */ 

                                        if ( 'toggle' in obj ) return 'DOMTokenList'; 
                                        if ( 'namedItem' in obj ) return 'HTMLCollection'; 
                                        if ( 'item' in obj ) return 'NodeList'; 
                                } 
                        } 

                        if ( typeB == 'DocumentConstructor' || typeB == 'Window' ){  // Document in safari 5.1.7 , Window in firefox 
                                return 'Function'; 
                        } 

                        return typeB; 
        } 
} 
 

두번째 방법 ( Second way )

위의 내용에서 몇 줄을 수정한 것이다.

문자일 경우,
글자 하나 없이, 띄어쓰기만 잔뜩 들어있거나, 아니면 아예 아무것도 없는 빈 문자열인지를
구별해줘야 할 때가 있기 때문이다.

숫자일 때에도 마찬가지이다.
일반적인 숫자가 아닌, NaN이나 Infinity로 나오는 경우를 따로 구분해야 할 때가 있다.


This is slightly modified on the above.

When it's a string,
sometimes, it's necessary to distinguish whether it is an empty string, or all that whitespaces.

It's true when the numbers, too.
Because it may be "NaN" or "Infinity".


 
function getTypeof ( obj ){ 
        var str; 
        var typeA = typeof obj; 

        if ( typeA == 'undefined' ) return 'Undefined'; 
        if ( obj === null ) return 'Null'; 

        var toString = function ( obj ){ 
                var str = Object.prototype.toString.call( obj ); 
                return str.substr( 8, str.length - 9 ); 
        }; 

        var typeB = toString( obj ); 

        var doc = document; 
        var view = doc.defaultView; 

        switch ( true ){ 
                case ( obj == view.alert ) : return 'Function'; 

                case ( obj == doc ) : return 'Document'; 
                case ( obj == view ) : return 'Window'; 

                case ( obj == doc.__proto__ ) : return 'DocumentPrototype'; 
                case ( obj == view.__proto__ ) : return 'WindowPrototype'; 

                case isNode( obj ) : 

                        var val = obj.nodeValue; 
                        var name = obj.nodeName;

                        switch ( obj.nodeType ){ 

                                case 1 : return name.charAt( 0 ) + name.substr( 1 ).toLowerCase(); 

                                case 2 : return 'Attribute'; // attribute of element 

                                case 3 : return ( /\S/ ).test( val ) ? 'Text' : ( val == '' ? 'EmptyText' : 'SpaceText' ); // whitespaces
                                /* Or, simply... 
                                 * case 3 : return 'Text'; 
                                 */ 

                                case 8 : return 'Comment'; 
                                // case 9 : return 'Document'; 

                                case 10 : return 'DocumentType'; // document.doctype 
                                case 11 : return 'Fragment';  // document.createDocumentFragment() 

                                /*  
                                 * if it's xml file, not html...  
                                 * 
                                 * case 4 : return 'CDATASection'; 
                                 * case 5 : return 'EntityReference'; 
                                 * case 6 : return 'Entity'; 
                                 * case 7 : return 'ProcessingInstruction'; 
                                 * case 12 : return 'Notation'; 
                                 */ 
                        } 

                        return; 

                case ( typeA == 'string' || typeB == 'String' ): return /\S/.test(obj) ? typeB : ( obj == '' ? 'EmptyString' : 'SpaceString' );
                case ( typeA == 'number' || typeB == 'Number' ) : return isFinite( obj ) ? typeB : obj.toString();
                /* Or, simply... 
                 * 
                 * case ( typeA == 'string' || typeB == 'String' ) : return 'String'; 
                 * case ( typeA == 'number' || typeB == 'Number' ) : return 'Number'; 
                 */ 

                case ( obj.constructor && obj == obj.constructor.prototype ) : 

                        var ctor = obj.constructor; 

                        if ( typeof ctor == 'function' ){  str = getFunctionName( ctor );  } 
                        else {  str = typeB;  } 

                        return str + 'Prototype'; 

                default : 
                        if ( typeof obj.length == 'number' ){ 

                                if ( 'callee' in obj ) return 'Arguments'; 

                                if ( 'cssText' in obj ) return 'CSSStyle'; // style of element 

                                if ( typeof obj.item == 'function' ){ 
                                        /* 
                                         * childNodes :: NodeList , children :: HTMLCollection , classList :: DOMTokenList 
                                         * 
                                         * NodeList :: function item() , 
                                         * HTMLCollection :: function item() , function namedItem() , 
                                         * DOMTokenList :: function item() , function add() , function remove() , function toggle() , 
                                         */ 

                                        if ( 'toggle' in obj ) return 'DOMTokenList'; 
                                        if ( 'namedItem' in obj ) return 'HTMLCollection'; 
                                        if ( 'item' in obj ) return 'NodeList'; 
                                } 
                        } 

                        if ( typeB == 'DocumentConstructor' || typeB == 'Window' ){  // Document in safari 5.1.7 , Window in firefox 
                                return 'Function'; 
                        } 

                        return typeB; 
        } 
} 
 

이 내용이 도움이 되셨다면, 아래의 하트 버튼을 눌러주세요 *^^*
If this article is helpful to you, please click the heart button below. :)

0 Comments