内容要点:

介绍了三种用以检测任意对象的类的技术,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. iframe自适应高度问题

    我页面中的iframe <iframe name="mainFrame" id="mainFrame" src="/account/${page ...

  2. C#Dictionary集合的使用

    题目:输入一串字符串字母,比如:Welcome to China,比较每个字母出现的次数,不区分大小写. 解决这道题的方法很多.可能一百个人有一百个思路.当时第一眼看到这个题我的思路是:先将接受的一串 ...

  3. VS2015 使用

    1,使用vs2015时,首先需要安装DAEMON Tools Lite虚拟光驱:

  4. 使用Stardict命令行版本sdcv

    sdcv命令的常用选项如下: -l:列出安装的词典 -u:指定查词所用的词典 在我的电脑上列出的词典有: Dictionary's name Word count Merrian Webster 10 ...

  5. JSONP 的工作原理是什么?

    利用<script>标签没有跨域限制的"漏洞"来达到与第三方通讯的目的. 当需要通讯时,本站脚本创建一个<script>元素,地址指向第三方的API网址,形 ...

  6. 《JavaScript网页经典特效300例》

    <JavaScript网页经典特效300例> 基础篇 进阶篇 高级篇

  7. Android UI方面的学习记录

    1,android:textAllCaps=“false” android5.0后有可能button的text显示全是大写,设置这个后才能正常显示小写 2,优化listview性能: 1,view重用 ...

  8. 浏览器内核控制Meta标签说明(内核渲染优先问题)

    渲染优先选择极速模式 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> ...

  9. opencv3.1自带demo的介绍和运行操作。转载

    opencv3.1自带demo的介绍和运行操作. 下列实验基本都试过,有些需要根据自己的电脑修改一些路径或者调试参数. 值得注意的是,控制台程序输入有时候要在图像所在的窗口输入相应的指令.我的电脑上安 ...

  10. Mysql基础知识整

    web项目部署 Java项目使用的web服务器:Tomcat.weblogic.webshare.jetty Php.python使用的web服务器:nginx.apache 搭建环境过程: 部署.发 ...