《JS权威指南学习总结--9.5 类和类型》
内容要点:
介绍了三种用以检测任意对象的类的技术,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 类和类型》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- bzoj2301: [HAOI2011]Problem b懵逼乌斯反演
属于结果的和好求但是结果不好求的题 (轻易能得到以k的倍数为最大公约数的对数,但是不好直接求k) 所以一波反演结束 其实反演的时候完全没有反演的感觉,就是不停地恒等变形 算是懵逼乌斯反演最简单的例题 ...
- 数据持久层框架iBatis, Hibernate 与 JPA 比较
在本文中我们介绍并比较两种最流行的开源持久框架:iBATIS和Hibernate,我们还会讨论到Java Persistence API(JPA).我们介绍每种解决方案并讨论其所规定的品质,以及在广泛 ...
- Nuget 学习一
初识Nuget 对应C#开发的人员来说, DLL和相关的引用 并不陌生吧,通过手动拷贝DLL 存在很多问题, 比如SOA的实体DLL,开发者和使用者的DLL不一致,就可能存在字段的不一致, 通过Nug ...
- webpack + vue最佳实践
webpack + vue最佳实践 我的原文地址:http://www.xiaoniuzai.cn/2016/10/04/webpack%20+%20vue%E6%9C%80%E4%BD%B3%E5% ...
- php计算几分钟前、几小时前、几天前的几个函数分享
/* * 精确时间间隔函数 * $time 发布时间 如 1356973323 * $str 输出格式 如 Y-m-d H:i:s * 半年的秒数为15552000,1年为31104000,此处用半年 ...
- [MFC] 对话框菜单项Menu选中打勾(单选,多选)
近期需要实现一个功能:MFC对话框中,一项菜单下有五个菜单项,改变菜单项选中状态,每次只能选择其中一个打勾.(单选) 然后在网上搜了下资料,稍微总结下,以防后面用到. 1.单选实现: CMenu* m ...
- html使用css让文字多行超出部分用省略号三个点显示的方法案例
text-overflow: -o-ellipsis-lastline;overflow: hidden;text-overflow: ellipsis;display: -webkit-box;-w ...
- PHP检测文件能否下载
用php代码检测一个文件是否可以下载,网上没有找到合适的代码,自己实现了一个还挺好用的,分享给有需要的朋友. 基本原理:使用http的HEAD方法,检测报文的头里httpcode是否为200. pub ...
- 第 2 章 Node.js 中的交互式运行环境 —— REPL
本章内容包括: 如何使用REPL运行环境以及如何在该运行环境中测试各种JavaScript表达式. 如何定义并启动REPL运行环境. Node.js 框架中为REPL运行环境提供了哪些命令以及这些命令 ...
- 杂谈3之English
1.面向过程(OPP):Orient Procedure Program (C语言) 2.面向对象(OOP):Orient ObjectProgram(Java) 3.面向对象的三大特征:继承Inhe ...