Brief                              

有时我们需要根据入参的数据类型来决定调用哪个函数实现,就是说所谓的函数重载(function overloading)。因为JS没有内置函数重载的特性,正好给机会我们思考和实现一套这样的机制。

使用方式:

function foo(){
return dispatch(this, arguments)
}
foo["object,number"] = function(o, n){console.log(o.toString() + ":" + n)}
foo["string"] = function(s){console.log(s)}
foo["array"] = function(a){console.log(a[])}

机制实现:

;(function(e/*xports*/){
e.dispatch = function(thisValue, args){
var rSignature = getSignature(args)
for (var p in args.callee){
if (rSignature.test(p)){
return args.callee[p].apply(thisValue, args)
}
}
}
function getSignature(args){
var arg, types = []
for (var i = , len = args.length; i < len; ++i){
arg = args[i]
types.push(type(arg))
}
var rTypes = "^\\s*" + types.join("\\s*,\\s*") + "\\s*$"
return RegExp(rTypes)
}
function type(val){
// TODO
}
}(window))

那现在问题就落在type函数的实现上了!

关于获取变量的数据类型有typeof、Object.prototype.toString.call和obj.constructor.name三种方式,下面我们一起来了解一下!

typeof Operator                        

语法: typeof val

内部逻辑:

function typeof(val){
var ret = Type(val)
if (ret === "Reference"
&& IsUnresolvableReference(val)) return "undefined"
ret = GetValue(val)
ret = Type(ret)
return ret
}

Type(val)抽象操作的逻辑:

Undefined -> "undefined"

Null -> "object"

Boolean -> "boolean"

Number -> "number"

String -> "string"

Objecjt,若对象为native object并且没有[[Call]]内置方法,则返回"object"

      若对象为native object或host object且有[[Call]]内置方法,则返回"function"

      若对象为host object并且没有[[Call]]内置方法,则返回除"undefined"、"boolean"、"number"和"string"外的数据类型字符串。

native object,就是Math、{foo:1}、[]、new Object()和RegExp等JS规范中定义的对象,其中Math、RegExp等程序运行时立即被初始化的对象被称为built-in object。

host object,就是宿主环境提供的对象,如浏览器的window和nodejs的global。

从上述Type(val)抽象操作的逻辑得知:

1. typeof能清晰区分Boolean、Number、String和Function的数据类型;

2. 对于未声明和变量值为Undefined的变量无法区分,但对未声明的变量执行typeof操作不会报异常;

3. typeof对Null、数组和对象是无能的。

针对2、3点我们可以求助于 Object.prototype.toString.call(val) 。

Object.prototype.toString.call(val)              

Object.prototype.toString.call(val)或({}).toString.call(val)均是获取val的内置属性[[Class]]属性值,并经过加工后返回。

内部逻辑:

function Object.prototype.toString(){
if (this === undefined) return "[object Undefined]"
if (this === null) return "[object Null]"
var o = ToObject(this)
var clazz = o.[[Class]]
return "[object " + clazz + "]"
}

注意:1. 由于内部硬编码null返回"[object Null]",因此虽然null本应不属于Object类型,但JS中我们依然将其当作Object来使用(历史+避免破坏已有库的兼容性,导致后来无法修正该错误了);

2. 即使入参为primitive value,但内部还是会对其进行装箱操作(通过ToObject抽象操作)。

那现在我们就需要了解一下[[Class]]内部属性了。

内部属性[[Class]]

  在构造对象时会根据对象的类型设置[[Class]]的值,而其值类型为字符串。对于native object而言,其值范围是:Arguments
Array、Boolean、Date、Error、Function、JSON、Math、Number、Object、RegExp、String。对于host object而言,则用HTMLElement、HTMLDocument等了。

注意:[[Class]]是用于内部区分不同类型的对象。也就是仅支持JS语言规范和宿主环境提供的对象类型而已,而自定义的对象类型是无法存储在[[Class]]中。

function Foo(){}
var foo = new Foo()
console.log(({}).toString.call(foo)) // 显示[object Object]

于是我们需要求助于constructor.name属性了。

obj.constructor.name                    

function Foo(){}
var foo = new Foo()
console.log(foo.constructor.name) // 显示Foo

那如果采用匿名函数表达式的方式定义构造函数呢?只能说直接没辙,要不在构造函数上添加个函数属性来保存(如Foo.className="Foo"),要不自己构建一个类工厂搞定。

Implementaion of type function              

综上所述得到如下实现:

/*
* 获取对象的数据类型
* @method type
* @param {Any} object - 获取数据类型的对象
* @param {Function} [getClass] - 用户自定义获取数据类型的方法
* @returns {String} 数据类型名称
*/
function type(o/*bject*/, g/*etClass*/){
var t = typeof o
if ("object" !== t) return t.replace(/^[a-z]/, function(l){return l.toUpperCase()}) var rType = /\s*\[\s*object\s*([-9a-z]+)\s*\]\s*/i
t = ({}).toString.call(o)
t = t.match(rType)[]
if ("Object" !== t) return t t = o.constructor.name
if (!t && arguments.callee(g) === "Function"){
t = g(o)
}
t = t || "Object"
return t
}

Consolusion                             

尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/5156912.html^_^肥子John

Thanks                              

http://segmentfault.com/q/1010000000669230

http://es5.github.io/#x15.2.4.2

JS魔法堂:函数重载 之 获取变量的数据类型的更多相关文章

  1. JS魔法堂:不完全国际化&本地化手册 之 实战篇

    前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...

  2. JS魔法堂:判断节点位置关系

    一.前言 在polyfill querySelectorAll 和写弹出窗时都需要判断两个节点间的位置关系,通过jQuery我们可以轻松搞定,但原生JS呢?下面我将整理各种判断方法,以供日后查阅. 二 ...

  3. JS魔法堂:属性、特性,傻傻分不清楚

    一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...

  4. JS魔法堂:那些困扰你的DOM集合类型

    一.前言 大家先看看下面的js,猜猜结果会怎样吧! 可选答案: ①. 获取id属性值为id的节点元素 ②. 抛namedItem is undefined的异常 var nodes = documen ...

  5. JS魔法堂:精确判断IE的文档模式by特征嗅探

    一.前言 苦逼的前端攻城狮都深受浏览器兼容之苦,再完成每一项功能前都要左顾右盼,生怕浏览器不支持某个API,生怕原生API内含臭虫因此判断浏览器类型和版本号成了不可绕过的一道关卡,而特征嗅探是继浏览器 ...

  6. JS魔法堂:追忆那些原始的选择器

    一.前言                                                                                                 ...

  7. JS魔法堂:不完全国际化&本地化手册 之 理論篇

    前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...

  8. JS魔法堂:IMG元素加载行为详解

    一.前言 在<JS魔法堂:jsDeferred源码剖析>中我们了解到img元素加载失败可以作为函数异步执行的优化方案,本文打算对img元素的加载行为进行更深入的探讨. 二.资源加载的相关属 ...

  9. JS魔法堂:jsDeferred源码剖析

    一.前言 最近在研究Promises/A+规范及实现,而Promise/A+规范的制定则很大程度地参考了由日本geek cho45发起的jsDeferred项目(<JavaScript框架设计& ...

随机推荐

  1. 【Bugly干货】Android性能优化典范之多线程篇

    本文涉及的内容有:多线程并发的性能问题,介绍了 AsyncTask,HandlerThread,IntentService 与 ThreadPool 分别适合的使用场景以及各自的使用注意事项,这是一篇 ...

  2. Java多线程8:wait()和notify()/notifyAll()

    轮询 线程本身是操作系统中独立的个体,但是线程与线程之间不是独立的个体,因为它们彼此之间要相互通信和协作. 想像一个场景,A线程做int型变量i的累加操作,B线程等待i到了10000就打印出i,怎么处 ...

  3. SQL 行列倒置

    SQL的的行列倒置已经不是新知识了,但在博主的技术咨询期间,仍发现其实有很多人并不了解这块,所以在此专门写一篇博客记录.本文将以Mysql为例,并以数据采集指标信息获取为例子.在下面的例子,你可以在s ...

  4. jQuery读取和设定KindEditor的值

          在使用Kindeditor的时候,想要利用Ajax传值,但是通过editor封装的方法是行不通的,原因在于编辑器我们是放在另一个jsp页面,通过iframe来加载的,同时这个iframe的 ...

  5. [ACM_几何] Pipe

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28417#problem/B     本题大意: 给定一个管道上边界的拐点,管道宽为1,求 ...

  6. 使用Chef管理windows集群

    但凡服务器上了一定规模(百台以上),普通的ssh登录管理的模式就越来越举步维艰.试想Linux发布了一个高危漏洞的补丁,你要把手下成百上千台机器都更新该补丁,如果没有一种自动化方式,那么至少要耗上大半 ...

  7. IOS 手势-轻点、触摸、手势、事件

    1.概念 手势是从你用一个或多个手指接触屏幕时开始,直到手指离开屏幕为止所发生的所有事件.无论手势持续多长时间,只要一个或多个手指仍在屏幕上,这个手势就存在. 触摸是指把手指放到IOS设备的屏幕上,从 ...

  8. javascript_core_05之正则表达式

    1. 检索关键词: ①检索固定关键词的位置: var i=str.indexOf(“关键词”,fromi):在str中查找fromi位置后,下一个关键词的下标位置:省略fromi,从0开始: var ...

  9. javascript_core_03之数组

    1.数组:连续存储多个数据,一组连续变量的集合: ①创建空数组:var arr=[]:或者var arr=new Array(): ②创建初始化数组:var arr=[值1,值2,……]:或者var ...

  10. Git使用相关

    Git使用相关 使用git这么久还是时不时碰到小问题,根本原因在于没有仔细研究和做笔记 Git修改remote地址 之前一直使用的ssh的地址,估计是没配置好,每次都需要输密码烦死了,今天看到个用ht ...