内容要点:

介绍了三种用以检测任意对象的类的技术,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. Python自动化开发-基础语法

    1.编码 计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.解决思路:数字与符号建立一对一映射,用不同数字表示不同符号. ASCII(American Standard Code ...

  2. IntelliJ IDEA新建JAVA WEB项目(转载)

    IntelliJ IDEA是java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手.代码自动提示.重构.J2EE支持.各类版本控制工具(git.svn ...

  3. gridcontrol如何根据值来动态设置某一行的颜色

    应用场景:当我们使用devexpress gridcontrol wpf控件时.可要会要根据这一行要显示的值来设置相应的颜色 可以通过下面方法来实现 一.先定义一个style <local:Co ...

  4. sublime 2中Package control安装和使用

    安装: 安装时,如果想查看安装进度,可打开console(View->Show Console) 安装Package control有两中方法: 方法1:通过代码安装 import urllib ...

  5. iOS中的布局

    1.UIView 有三个比较重要的布局属性: frame , bounds 和 center , CALayer 对应地叫做 frame , bounds 和 position .为了能清楚区分,图层 ...

  6. java操作mongodb——连接数据库

    import com.mongodb.MongoClient; MongoClient mongoClient = new MongoClient(); 连接MongoDB实例,默认为localhos ...

  7. tomcat配置https方法

    利用tomcat服务器配置https双向认证 步骤 1.为服务器生成证书进入控制台,切换到%JAVA_HOME%/bin目录,具体操作略. 使用keytool为Tomcat生成证书,假定目标机器的域名 ...

  8. HTML,CSS,JS,JQ

    CSS: <style> <!--属性选择器--> .container input[type="text"][name="txt"]{ ...

  9. CodeForces 670B Game of Robots

    简单题. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #inclu ...

  10. ModelState.IsValid一直为false的原因

    一,问题:ModelState.IsValid一直为false 二,解决方法和原因, 由于这个方法中传过来的RegisterForm模型的字段,某一个为空值,则会造成这个验证验证为false,去注释掉 ...