• Javascript 对象创建多种方式 原型链


    一、对象创建

    1、new Object 方式

      直接赋上属性和方法

    var obj = new Object(); 
    obj.name = '娃娃';
    obj.showName = function(){ 
      alert(obj.name);
    }
    //调用 obj.showName();

      缺点:每次使用都要写同样的代码,不能重用

    2、工厂方法方式

      把同样的代码封装在一个函数方法里,是对1、改进,减少重复代码。 

    function CreatePerson(name){ 
       var obj = new Object();   //原料
       obj.name = name;         //加工
       obj.showName = function(){
         alert(this.name);
     } 
       return obj;//出厂
    }
    var p1 = CreatePerson('哇哇');
    p1.showName();
    var p2 = CreatePerson('哈哈');
    p2.showName();
    //其实就是简单的封装函数,整个过程像工厂的流水线,所以叫工厂方式

      缺点:无法识别创建的对象的类型。因为全部都是Object,没有区分度,不像Date、Array等,因此出现了构造函数模式。

    3、构造函数方式

      函数名首字母大写,这是为了和普通函数区分,而且有this指针。

    function CreatePerson(name){ 
       this.name = name; 
       this.showName = function(){ 
         alert(this.name);
       } 
    } 
    var p1 = new CreatePerson('娃娃'); 
    p1.showName();
    var p2 = new CreatePerson('哈哈'); 
    p2.showName();

      构造函数本身也是普通函数,取决于使用的方式,可以new(当作构造函数),也可以直接调用(当作普通函数),两者区别是this指针指向不一样。

    new CreatePerson('haha'); //CreatePerson
    CreatePerson('haha');  //window

      new 内部操作

    function CreatePerson(name){ 
       var obj = {}; //声明一个空对象obj 
       obj._proto_= CreatePerson.prototype;
       //把这个对象的_proto_属性指向构造函数的原型对象,这样obj就可以调用CreatePerson原型对象下的所有方法 。
        CreatePerson.apply(obj);   //用apply方法让this指向obj对象
        this.name = name;   //obj对象添加属性,方法
        this.showName = function(){ 
           alert(this.name);
          }; 
        return obj;//返回这个对象
    }

      缺点:可见这两个对象并不是共用一个方法,每new一次,系统都会新创建一个内存,这两个对象各自有各自的地盘,但他们具有相同的功能,还不共用。

    alert(p1.showName==p2.showName);//false

    4、原型+构造函数方式 最优方式

      原型:

        每个函数都有一个prototype属性,它是一个对象,也称作原型对象,我们可以把方法和属性写在它上面(不过原型对象不仅仅有我们写的属性和方法,还有别的),设计时概念。

        而通过这个函数创建出来的实例对象,都能共享这个原型对象下的方法和属性。

      编写方法:

      把共享的属性和方法定义在函数的prototype下,不共享的内容通过构造函数来创建。

    function CreatePerson(name){ 
      //定义不共享内容
      this.name = name;
    }
    //定义共享内容
    CreatePerson.prototype.showName = function(){ 
       alert(this.name);
    }
    var p1 =new CreatePerson('娃娃');
    p1.showName();
    var p2 = new CreatePerson('哈哈');
    p2.showName();
    alert(p1.showName==p2.showName);//true

      由此也可以看出,showName()方法是共享的,也就是说他们共用一个内存,更进一步的说它们存在引用关系,也就是说你更改了p1的showName也会影响p2的showName。

      _proto_属性:

      运行时属性,每个实例化对象都有_proto_属性,它是一个指针,指向函数的prototype(设计时属性),保存了函数的prototype的地址,通过该_proto_属性可以让同一构造函数的多个实例对象能共享这个构造函数的prototype(设计时定义)下的方法和属性。

      js中任何对象的值都是保存在堆内存中,我们声明的变量只是一个指针,保存了这个对象的实际地址,所以有了地址就能找到对象。

      所以,_proto_属性实际就是实例化对象和原型对象之间的连接。

    二、原型链

      每个函数都可以成为构造函数,每个函数都有原型对象,每个原型对象也可以是一个实例化对象。

      创建了构造函数Function的实例化对象fun,而Function的原型对象(Function.prototype),又是Object的实例对象,根据前边介绍,fun有个_proto_属性,指向了Function.prototype,而Function.prototype(是Object的实例对象)又指向了Object.prototype。

      所以,通过_proto_属性,就形成了一条原型链。每个实例化对象都可以访问到链子上方的方法和属性,所以fun是可以访问Object原型对象下的方法和属性的。实际上所有对象都可以访问到Object的原型对象。

       访问规则先在自身的下面寻找,再去一级一级的往原型链上找
      
    function Aaa(){}
    Aaa.prototype.num = 3;
    var a1 = new Aaa();
    a1.num =10;
    alert(a1.num); //10

  • 相关阅读:
    Macos中Office的选择
    基于上一篇的滑动列表,动态添加/删除功能
    GitLab 服务搭建及常用命令
    java多线程中的异常处理
    java实现xml互转json
    nginx集群搭建方案(教你如何搭建nginx集群)
    cmd窗口改字符集编码
    ThreadLocal详解
    查看Linux系统版本信息的几种方法
    Windows命令之tasklist命令
  • 原文地址:https://www.cnblogs.com/shawnhu/p/8470560.html
Copyright © 2020-2023  润新知