[Effective JavaScript 笔记]第30条:理解prototype、getPrototypeOf和__ptoto__之间的不同
原型包括三个独立但相关的访问器。这三个单词都是对单词prototype做了一些变化。
C.prototype用于建立由new C()创建的对象的原型
Object.getPrototypeOf(obj)是ES5中用来获取obj对象的原型对象的标准方法
obj.__proto__是获取obj对象的原型对象的非标准方法
一个例子
要理解这些访问器,我们拿一个典型的js数据类型作例子。
假设User构造函数需要通过new操作符来调用。它需要两个参数,即姓名和密码的哈希值,并将它们存储在创建的对象中。
代码如下:
function User(name,pwd){
this.name=name;
this.pwd=pwd;
}
User.prototype.toString=function(){
return '[User '+this.name+']';
}
User.prototype.checkPwd=function(pwd){
return hash(pwd)===this.pwd;
}
var u=new User('cedrusweng','$sdf99kaslf7');
根据上面的这个代码我们可以画出下面这个图,以表示各种关系。
我们每次在使用
function Fn(){ }
相当于调用下面这样
var fn=new Function([参数,]"函数体");
其中Function是一个构造函数,它的原型对象中包含我们之前讲到过的call、apply、bind等属性和方法。fn是Function的一个实例对象。
所以这里的可以得到第一部分的图
下面再就构造函数User和它的原型对象之间的关系画出一个图
User函数带有一个默认的prototype的属性,其包含一个开始几乎为空的对象。上面的例子中添加了两个方法到原型对象中。当使用new操作符创建User的实例时,产生的对象u得到了自动分配的原型对象,该原型对象被存储在User.prototype中。
最后来一张完整的图
注意:new操作符调用构造函数,会产生一个新的对象实例,这个对象是以构造函数为模板,创建一份私有的性属性和方法,所有的实例都会继承原型对象。当访问u.name时,u对象会首先在它的私有属性中进行搜索,如果有则会返回,如果没有,则会查找对象的原型对象。当访问u.checkPwd时,私有属性和方法不存在时,会返回存储在User.prototype中的方法。
原型有关的方法
首先,构造函数的prototype属性用来设置新实例的原型关系。
其次,ES5中的函数Object.getPrototypeOf()可以用于检索现有对象的原型。
如上面的例子,可以使用下面代码来检测对象u的原型对象。
Object.getPrototypeOf(u)===User.prototype;//true
最后,一些环境提供了非标准的方法检索对象的原型,即特殊的__proto__属性。这可作为在不支持ES5的Object.getPrototypeOf方法的环境中的一个兼容方法。在这些环境中可以使用下面代码完成检测
u.__proto__===User.prototype;//true
下面画一张图,表明它们之间的关系
最后的说明
js程序员往往将User描述为一个类,尽管它跟一个函数差不多。js中的类本质上是一个构造函数与一个用于类(User.prototype)实例间共享方法的原型对象的结合。
下面是一个User类的概念图。
User函数给该类提供了一个公共的构造函数,而User.prototype是实例之间共享方法的一个内部实现。User和u的变通用法都不需要直接访问原型对象。
提示
C.prototype属性是new C()创建的对象的原型
Object.getPrototypeOf(obj)是ES5中检索对象原型的标准函数
obj.__proto__是检索对象原型的非标准方法
类是由一个构造函数和一个关联的原型组成的一种设计模式
附录一:函数声明
函数使用
var fn1=function(){};
var fn2=new Function('');
function fn3(){
}
这3种方式的函数,前面两种都是属性函数表达式,最后一种是函数声明语法。函数实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。
具体可以看下图来看对应的关系图
函数表达式与函数声明的区别
看到上面都是产生了函数的实例,但解析器会率先读取函数声明,并使其在执行任何代码之前可用;函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释。
可以根据函数表达式的特点,按条件给变量赋不同的函数表达式。
function createFn(a)
var fn;
if(a){
fn=function(){console.log(1)}
}else{
fn=function(){console.log(2)}
}
return fn;
}
var fn1=createFn(true);
var fn2=createFn();
fn1();//1
fn2();//2
最新文章
- 你搞懂 ORACLE、 SQLSERVER、MYSQL与DB2的区别了吗
- git常用的命令集合
- Python 爬虫6——Scrapy的安装和使用
- 在Package中处理 bit column
- id to load is required for loading
- 关于RSA加密算法的长度限制问题
- CentOs7 网卡出现问题Job for network.service failed
- Oracle的日期时间范围查询
- iOS crash 异常捕获
- POJ2288 Islands and Bridges
- IOS中UIWebView执行javaScript脚本时注意点
- android学习笔记---发送状态栏通知
- 记录一下跟Python有关的几个拓展名
- 布局—column(属性)
- Qt5中生成和使用静态库
- 两个activity之间的数据传递
- echarts实时数据图表
- Java Exception 和Error
- loadrunner 场景设计-手工场景方案(Schedule)设计
- 自定义滤镜 ColorMatrixFilter
热门文章
- EF实体框架之CodeFirst七
- MongoDB驱动之Linq操作
- css翻页样式
- [USACO2002][poj1945]Power Hungry Cows(启发式搜索)
- tomcat 简介
- 【转】div居中代码 DIV水平居中显示CSS代码
- easyui_动态添加隐藏toolbar按钮
- Android Fresco (Facebook开源的图片加载管理库)
- hasSet,TreeSet,ArrayList,LinkedList,Vector,HashMap,HashTable,TreeMap利用Iterator进行输出
- Java编程思想学习(九) 异常处理