内容要点:

介绍了三种用以检测任意对象的类的技术,instanceof运算符、constructor属性,以及构造函数的名字。

但每种技术都不甚完美,本节总结了鸭式辩型,这种编程哲学更加关注对象可以完成什么工作(它包含什么方法)而不是对象属于哪个类

一.instanceof运算符

1.左操作数是带检测其类的对象,右操作数是定义类的构造函数。如果o继承自c.prototype,则表达式 o instanceof c值为true.这里的继承可以不是直接继承,如果o所继承的对象继承自另一个对象,后一个对象继承自c.prototype,这个表达式的运算结果也是true,

2.构造函数是类的公共标识,但原型是唯一的标识。尽管Instanceof运算符的右操作数是构造函数,但计算过程实际上是检测了对象的继承关系,而不是检测创建对象的构造函数。

3.isPrototypeOf()方法:不使用构造函数作为中介,来检查对象的原型链上是否存在某个特定的原型对象。

range.methods.isPrototypeOf(r); //range.method 是原型对象

4.instancof运算符和isProtootypeOf()方法的缺点是:

我们无法通过对象来获得类名,只能检测对象是否属于指定的类名。

在客户端JS中还有一个比较严重的不足,就是在多窗口和多框架子页面的Web应用中兼容性不佳。每个窗口和框架子页面都具有单独的执行上下文,每个上下文都包含独有的全局变量和一组构造函数。在两个不同框架页面中创建的两个数组继承自两个相同但相互独立的原型对象,其中一个框架页面中的数组不是另一个框架页面的Array()构造函数的实例,instanceof运算结果是false。

二.constructor属性

1.另一种识别对象是否属于某个类的方法是使用constructor属性,因为构造函数是类的公共标识,所以最直接的方法就是使用constructor属性,比如:

function typeAndValue(x){

if(x == null ) return ""; //Null和undefined没有构造函数

switch(x.constructor){

case Number : return "Number" + x; //处理原始类型

case String : return "String: ' " + x + " ' ";

case Date : return "Date" + x; //处理内置类型

case RegExp : return "RegExp:" + x;

case Complex : return "Complex:" + x; //处理自定义类型

}

}

需要注意的是,在代码中关键字case后的表达式都是函数,如果改用typeof运算符或获取到对象的class属性的话,它们应当改为字符串。

2.使用constructor属性检测对象属于某个类的技术的不足之处和instanceof一样。在多个执行上下文的场景中它是无法正常工作的(比如在浏览器窗口的多个框架子页面中)。在这种情况下,每个框架页面各自拥有独立的构造函数集合,一个框架页面中的Array构造函数和另一个框架页面的Array构造函数不是同一个构造函数。

同样,在javascript中也并非所有的对象都包含constructor属性。在每个新创建的函数原型上默认会有constructor属性,但我们常常会忽觉原型上constructor属性。比如例9-1和例9-2它们的实例都没有constructor属性。

三.构造函数的名称

1.使用instanceof运算符和constructor属性来检测对象所属的类有一个主要的问题,在多个执行上下文中存在构造函数的多个副本的时候,这两种方法的检测结果会出错。多个执行上下文中的函数看起来是一模一样,但它们是相互独立的对象,因此彼此也不相等。

2.一种可能的解决方案是使用构造函数的名字而不是使用构造函数本身作为类标识符。

一个窗口里的Array构造函数和另一个窗口的Array构造函数是不相等的,但是它们的名字是一样的。

在一些js的实现中为函数对象提供了一个非标准的属性name,用来表示函数的名称。

对于那些没有name属性的javascript实现来说,可以将函数转换为字符串,然后从中提取出函数名。

3.例9-4:可以判断值的类型的typeof()函数

/*以字符串形式返回o的类型:如果o是null,返回"null";如果o是NaN,返回"nan"。。。如果typeof所返回的值不是"object",则返回这个值。。如果o的类不是"object",则返回这个值,,如果o包含构造函数并且这个构造函数具有名称,则返回这个名称,,,否则,一律返回"object"。*/

function type (o){

var t,c,n;  //type,class,name

//处理null值的特殊情况

if(o===null)return "null";

//另外一种特殊情况:NaN和它自身不相等

if(o!==o) return "nan";

//如果typeof的值不是"object",则使用这个值,这可以识别出原始值得类型和函数

if((t == typeof o)!=="object") return t;

//返回对象的类名,除非值为"object",这种方式可以识别出大多数的内置对象。

if((c == classof(o))!=="Object") return c;

//如果对象构造函数的名字存在的话,则返回它

if(o.constructor && typeof o.constructor === "function" && (n = o.constructor.getName())) return n;

//其他的类型都无法判别,一律返回"Object"

return "Object";

}

//返回对象的类

function classof(o){

return Object.prototype.toString.call(o).slice(8,-1);

};

//返回函数的名字(可能是空字符串),不是函数的话返回null

Function.prototype.getName = function(){

if("name" in this) return this.name;

return this.name = this.toString().match(/function\s*([^(]*)\(/)[1])

};

var a = new Date();//Date
         var b = [1,2,3]; //Array
         var c = {}; //Object
         var d = true; //boolean
         var e = "1"; //string
         var f = 1;//number
         var g = function(){};//function
         var h = new Function(); //function

console.log(type(g));

这种使用构造函数名字来识别对象的类的做法和使用constructor属性一样有一个问题:并不是所有的对象都具有constructor属性。此外,并不是所有的函数都有名字。如果使用不带名字的函数定义表达式定义一个构造函数,getName()方法则会返回空字符串:

//这个构造函数没有名字

var Complex = function(x,y){ this.r = x;this.i=y; }

//这个构造函数有名字

var Range = function Range(f,t){ this.from = f;this.to = t; }

《JS权威指南学习总结--9.5 类和类型》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. Prefix the choice with ! to persist it to bower.json ? Answer (问你选择哪个1,2,3.........)

    Unable to find a suitable version for underscore, please choose one by typing on e of the numbers be ...

  2. 使用Gradle编译release apk报错:Please correct the above warnings first

    在开发SDK的过程中,遇到了一个研发,使用了自己的SDK之后遇到了各种问题,于是我们自己帮忙接入. 所有代码都接入完成之后,准备export出一个release包,但是此时却报错: 此时出现了很多的w ...

  3. svn自动备份并上传到ftp

    .建立bat文件 simpleBackup.bat,文件内容如下 @echo 正在备份版本库%1......@%SVN_HOME%bin\svnadmin hotcopy %1 %BACKUP_DIR ...

  4. 使用 voluptuous 校验数据

    在 Python 中,我们经常需要对参数进行校验,这是我们有好多种方法,例如写很多 if 啊,或者写正则表达式啊等等,技巧高的人可以写得很巧妙,而技巧一般的人呢,可能会写得很冗长,例如我,经常就不能很 ...

  5. 第33届 MPD软件工作坊(南京站)有哪些亮点值得我们参加?

    MPD软件工作坊由msup2010年创办,自创办以来,共吸引了万名的软件从业者到场参与.第33届 MPD软件工作坊(南京站)将于12月17-18日在南京召开,大会报名平台:活动家! 快捷报名通道:ht ...

  6. 接口速度慢问题查找(TTFB时间长)

    前些天自己写了一个网站,但是发现接口的速度按超级慢,业务逻辑并不复杂,原因究竟在哪呢? 首先说一下,我的数据库和项目均在同一台服务器上,按道理来说,接口访问本地的数据库应该会很快才对. 后来我发现线上 ...

  7. Windows 多用户远程访问 Ubuntu 14.04桌面

    使用X2Go实现多用户远程访问 Ubuntu 14.04桌面:VNC也可以,但是每次连接VNC就回新创建一个Seession,想要在下次远程登录的时候返回上次活动,需要记住开启的线程,这种繁琐的操作不 ...

  8. pgmpy包的安装,以及conda的安装

    pgmpy包的安装,以及conda的安装 pgmpy的官方网站是这样说明安装过程的: 链接:Installation 共有三个步骤,第一步是安装依赖包 首先它讲述了在linux下使用pip安装的方法: ...

  9. informix数据迁移工具使用介绍

    一.dbschema  USAGE:     dbschema [-q] [-t tabname] [-s user] [-p user] [-r rolename] [-f procname]    ...

  10. html5获取图片的宽高

    var fr = new FileReader; fr.readAsDataURL($("#inputFileId").files[0]); fr.onload = functio ...