原型包括三个独立但相关的访问器。这三个单词都是对单词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

[Effective JavaScript 笔记]第30条:理解prototype、getPrototypeOf和__ptoto__之间的不同的更多相关文章

  1. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  2. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  3. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  4. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  5. [Effective JavaScript 笔记]第36条:只将实例状态存储在实例对象中

    理解原型对象与其实例之间是一对多的关系,对于实现正确的对象行为很重要.常见的错误是不小心将每个实例的数据存储到了其原型中. 示例 一个实现了树型数据结构的类可能将子节点存储在数组中. 实例状态在原型中 ...

  6. [Effective JavaScript 笔记] 第2条:理解JavaScript的浮点数

    JavaScript数值型类型只有数字 js只有一种数值型数据类型,不管是整数还是浮点数,js都把归为数字. typeof 17;   // “number” typeof 98.6; // “num ...

  7. [Effective JavaScript 笔记]第47条:绝不要在Object.prototype中增加可枚举的属性

    之前的几条都不断地重复着for...in循环,它便利好用,但又容易被原型污染.for...in循环最常见的用法是枚举字典中的元素.这里就是从侧面提出不要在共享的Object.prototype中增加可 ...

  8. [Effective JavaScript 笔记] 第12条:理解变量声明提升

    js支持词法作用域,即除了极少的例外,对变量的引用会被绑定到声明变量最近的作用域中. js不支持块级作用域,即变量定义的作用域并不是离其最近的封闭语句或代码块,而是包含它们的函数. 不了解这个会产生一 ...

  9. [Effective JavaScript 笔记]第18条:理解函数调用、方法调用及构造函数调用之间的不同

    面向对象编程中,函数.方法.类的构造函数是三种不同的概念. JS中,它们只是单个构造对象的三种不同的使用模式. 三种不同的使用模式 函数调用 function hello(username){ ret ...

随机推荐

  1. 『设计』Laura.Compute 设计思路

    前言: 前一篇文章 <『开源』也顺手写一个 科学计算器:重磅开源> ,继 Laura.Compute 算法开源之后,有 博客园 园友 希望公开一下 Laura.Compute算法 的 设计 ...

  2. CSS元素分类

    快级元素:在html中<div>,<p>,<h1>,<form>,<ul>,<li>就是块级元素.                ...

  3. 微信小程序全面实战,架构设计 && 躲坑攻略(小程序入门捷径教程)

    最近集中开发了两款微信小程序,分别是好奇心日历(每天一条辞典+一个小投票)和好奇心日报(轻量版),直接上图: Paste_Image.png 本文将结合具体的实战经验,主要介绍微信小程序的基础知识.开 ...

  4. Git.Framework 框架随手记--IIS7运行序列化问题

    客户反馈系统又登录不了,这是最近几次连续出现相同的问题,从日志反应情况来看: 日志级别:[info] 日志位置:Git.Framework.Resource.ResourceManager 日志时间: ...

  5. 怎样提高Windows Azure Cloud Service中的WebRole的文件访问权限

    关键字:WebRole 1. 背景 Web应用程序需要读取和写入该项目下的文件的权限. 在默认情况下,W3wp.exe 和WaIISHost.exe的运行账号是Network Service,而Net ...

  6. WCF入门(7)

    前言 前段时间忙着驾照科目二的考试,都没有机会碰自己的电脑.说起来也是第一次参加这么没信心的考试,不过好在过了. 再打个广告吧,昨天终于把下载的WCF视频全部传到了QQ群共享里面,群号37819043 ...

  7. php 字符串的一些操作,以便记忆

    php 字符串的操作 trim($str,'特殊字符')-----去除字符串左右两边的字符,返回字符串 ltrim(),rtrim()--------------------左,由两边,与trim() ...

  8. try throw catch异常处理机制

    /*本程序实现分块查找算法  又称索引顺序查找     需要注意的是分块查找需要2次查找  先对块查找  再对块内查找    2013.12.16    18:44*/ #include <io ...

  9. 【uoj150】 NOIP2015—运输计划

    http://uoj.ac/problem/150 (题目链接) 题意 给出一棵树以及m个询问,可以将树上一条边的权值修改为0,求经过这样的修改之后最长的边最短是多少. Solution 老早就听说过 ...

  10. 关于bash的shellshock漏洞

    这一漏洞的描述如下: Shellshock (CVE-2014-6271, CVE-2014-6277, CVE-2014-6278, CVE-2014-7169, CVE-2014-7186, CV ...