zoukankan      html  css  js  c++  java
  • [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的一个实例对象。
    所以这里的可以得到第一部分的图
    1465790019585
    下面再就构造函数User和它的原型对象之间的关系画出一个图
    1465790054119

    User函数带有一个默认的prototype的属性,其包含一个开始几乎为空的对象。上面的例子中添加了两个方法到原型对象中。当使用new操作符创建User的实例时,产生的对象u得到了自动分配的原型对象,该原型对象被存储在User.prototype中。

    最后来一张完整的图
    1465790103720

    注意: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

    下面画一张图,表明它们之间的关系
    1465790241541

    最后的说明

    js程序员往往将User描述为一个类,尽管它跟一个函数差不多。js中的类本质上是一个构造函数与一个用于类(User.prototype)实例间共享方法的原型对象的结合。
    下面是一个User类的概念图。
    1465790380110
    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类型的实例,而且都与其他引用类型一样具有属性和方法。
    具体可以看下图来看对应的关系图
    1465791595254

    函数表达式与函数声明的区别

    看到上面都是产生了函数的实例,但解析器会率先读取函数声明,并使其在执行任何代码之前可用;函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释。
    可以根据函数表达式的特点,按条件给变量赋不同的函数表达式。

    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
  • 相关阅读:
    Elasticsearch:用户安全设置
    Elasticsearch:significant terms aggregation
    Elastic:Elastic部署架构介绍
    Elasticsearch:Smart Chinese Analysis plugin
    Elasticsearch:ICU分词器介绍
    新版本中的hits.total匹配数说明
    Elasticsearch:fuzzy 搜索 (模糊搜索)
    Elasticsearch:运用search_after来进行深度分页
    Elasticsearch:运用scroll接口对大量数据实现更好的分页
    Elasticsearch:search template
  • 原文地址:https://www.cnblogs.com/wengxuesong/p/5580231.html
Copyright © 2011-2022 走看看