• 原型prototype


    在Js中,当试图引用对象的某个属性时,会进行GET操作,第一步会检查对象本身是否拥有这个属性,如果有的话就使用它,否则就会往对象的原型链上查询,一直查到该属性或者到达原型链的最顶端(与作用域类似,作用域查询变量,原形链查询属性)。如下代码:

      

     var anotherObject = {a:2};
    
       var myObject = Object.create(anotherObject);
    
       console.log(myObject.a);  //2

    myObject本身是没有a属性的,但是它关联到了anotherObject,anotherObject.prototype即作为它的上层原型。

    注:使用(for..in)遍历对象时,原理和查找原型链类似,任何可以在原型链中找到的属性并且是可枚举的都会被枚举,如下

      var anotherObject = {a:2};
    
      var myObject = Object.create(anotherObject);
    
      for(k in myObject){
    
       console.log(k); //2
    
    }

    所有普通的原型链最终都会指向内置的Object.prototype.

    在JS原型链中,假设对myObject.a进行赋值操作,如 myObject.a = 3; 通常情况下,我们会认为myObject会新创建一个a属性,并遮蔽上层的anotherObject.a,使得下次访问myObject.a的值时是为3,但事实并非如此,当我们进行这种操作时,引擎会根据三种情况进行不同工作。

       1.当myObject的上层原型链(本例子即为anotherObject.prototype)中的a属性是只读的(即writable = false),该语句会被忽略(如果在严格模式下,即会抛出一个错误);

       2.当myObject的上层原型链(本例子即为anotherObject.prototype)中的a属性是一个setter,即myObject.a=3的实质是对anotherObject.prototype.a =3的相同操作,不会为myObject新建一个属性。

       3.当myObject的上层原型链(本例子即为anotherObject.prototype)中的a属性是一个普通属性,并且不是只读的,则会进行上述遮蔽操作。

    如果想在第一种和第二种情况下进行遮蔽操作,那应该使用Object.defineProperty(...),而不是使用=符号赋值。

    Js中并没有像面向类语言一样的复制机制,Js没有实质的类,不能复制多个实例,只能创建多个对象,并且他们的原型都会关联到同一个对象,如下代码:

     function foo(){
    
       ...
    
    };
    
      var a = new foo();
    
      var b = new foo();
    
      Object.getPrototypeOf(a) === foo.prototype //(true)
    
     Object.getPrototypeOf(b) === foo.prototype //(true)

    实际上,new操作带来的对象关联只是一个副作用,他的实际上调用foo函数,比较好的关联操作应该是选择Object.create(...)(下面介绍),而且new操作会带来一些误解,会让人误以为foo是一个类,并且有一个奇怪的constructor构造属性,如a.construtor === foo (true) ,foo.prototype.construtor === foo(true);实际上a本身并没有construtor这个属性,它是在找不到的时候往上一层查询在foo.prototype中找到。

    举例来说,foo.prototype的construtor属性只是foo函数声明的时候的默认属性,与a是没有任何关系的,如果你创建了一个新对象代替foo.prototype,那么新对象不会自动获取该属性,如下

      

    function foo(){
    
    };
    
      foo.prototype = {...};
    
     var a  = new foo();
    
      a.construtor === foo; //false
    
      a.construtor === Object; //true

    这是一种委托行为。a并没有construtor属性,所以他会委托给原型链上的foo.prototype,但是这个对象也没有这个属性,foo,prototype就会再委托给他的原型链上的Object.prototype,并在Object.prototype对象中找到这个属性。

    Js最好的继承机制应该是Object.create(...),如下:

     function foo(){
    
       ...
    
    };
    
      var a = Object.create(foo.prototype);

    调用Object.create函数会创建一个新对象,并把新对象的原型链关联到你指定的对象(本例子中为foo,prototype).

    注意,下面是两种常见的错误操作:

       1.bar.prototype = foo.prototype;(和想要的机制不一样,是引用,而不是委托)

       2.var bar.prototype = new foo();(会产生一些副作用,如foo会被执行,可能与预期结果不一样)

    另外,在E5之前是没有Obect.create函数的,可以采用以下代码:

     

     if(!Object.create){
    
        Object.create = function(o){
    
           function F(){};
    
           F.prototype = o;
    
           return new F();
    
    }
    
    }
  • 相关阅读:
    跨域问题(使用jsonp解决)
    通用Mapper使用(Maven+SSM)
    hosts文件修改(域名和IP地址对应修改)
    ExportExcel(用poi导出Excel文件:用List<Map<String,Object>>)
    activiti已结束子流程退回
    一个数据库死锁的案例
    mysql函数使用的例子
    mybatis拦截器
    Objects工具类
    Spring Boot 中读取配置属性
  • 原文地址:https://www.cnblogs.com/Darlietoothpaste/p/6399380.html
Copyright © 2020-2023  润新知