zoukankan      html  css  js  c++  java
  • JavaScript对象的创建之基于原型方式

    原型内存模型介绍

    原型是javascript中非常特殊的一个对象,当一个函数创建之后,会随之就产生一个原型对象。

    当通过这个函数的构造函数创建一个具体的对象之后,在这个具体的对象中就会有一个属性指向原型。

    第一种状态

    function Person(){    
    }

    function Person(){},Person函数中有一个prototype的属性指向了Person Prototype的原型对象,在原型对象中有一个constructor的属性指向了Person函数,所以可以通过new Person()创建对象。内存图如下所示:

    第二种状态

    Person.prototype.name=”zhangsan”;
    Person.prototype.age = 27;
    Person.prototype.say = function(){
        alert(this.name + “,” + this.age);
    }

    通过Person.prototype.name为原型设置值之后,这些属性和方法都是设置在Person原型中。内存图如下所示:

    第三种状态

    var p1 = new Person();
    p1.say();
    
    //检测某个对象是否是某个函数的原型
    //以下方法可以检测出p1是否有_prop_指向Person的原型
    Person.prototype.isPrototypeOf(p1)

    当使用Person创建了对象之后,会在对象中有一个_prop_属性(这个属性是不能被访问的)指向了原型,当使用对象调用原型的时候,首先会在对象的内部找是否有这个属性,如果没有会通过_prop_去原型中找属性,所以当调用p1.say(),在自己的空间中不存在这个方法,就会去原型中寻找,找到之后完成say的调用。内存图如下所示:

    第四种状态

    var p2 = new Person();
    p2.name = “luogankun”; //是在自己的空间中定义了一个属性,不会替换原型中的属性
    p2.say();

    当创建了一个新的p2之后,依然会有一个_prop_属性指向Person的原型,此时如果通过p2.name=”luogankun”设置了属性之后,会在对象自己的内存空间中存储name的值,当调用say方法的时候在寻找name时,在自己的空间中找到之后,就不会去原型中查找了。(特别注意:原型中的值不会被替换,仅仅只是在查找时被覆盖)。内存图如下所示:

    其他方法介绍

    检测某个对象是否是某个函数的原型
    alert(Person.prototype.isPrototypeOf(p2));  //true
    
    检测某个对象的constructor
    alert(p1.constructor==Person);  //true
    
    检测某个属性是否是自己的属性
    alert(p1.hasOwnProperty("name"));  //false , p1自己的空间中没有值
    alert(p2.hasOwnProperty("name"));  //true,p2在自己的空间中设置了name属性
    
    p2.say(); // luogankun 27
    delete p2.name;
    p2.say(); //zhangsan 27
    alert(p2.hasOwnProperty("name")); //由于已经删除了,所以是false
    
    检测某个对象在原型或者自己中是否包含有某个属性,通过in检测
    alert("name" in p1);  //true
    alert("name" in p2);  //true
    alert("address" in p1); //在原型和自己的空间中都没有,false
    
    alert(hasPrototypeProperty(p1,"name"));//true
    alert(hasPrototypeProperty(p2,"name"));//false

    可以通过如下方法检测某个属性是否在原型中存在(在原型中但是不在自己空间中) // prop in obj表示原型和自己中有,!obj.hasOwnProperty(prop)表示自己中没有 function hasPrototypeProperty(obj,prop) { return ((!obj.hasOwnProperty(prop))&&(prop in obj)) }

    原型重写

    以上代码中当属性和方法特别多时,编写起来不是很方便,可以通过json的格式。json格式将会重写原型

    function Person(){}
    
    //重写原型
    Person.prototype = {
        constructor:Person,//手动指定constructor
        name:"Leon",
        age:23,
        say:function() {
            alert(this.name+","+this.age);
        }
    }
    
    var p1 = new Person();
    p1.say();
    alert(p1.constructor==Person); //true, 如果不显示的添加构造,此处打印出false

    原型重写内存模型1

    function Person(){}
    Person.prototype = {
        constructor:Person,//手动指定constructor
        name:"Leon",
        age:23,
        say:function() {
            alert(this.name+","+this.age);
        }
    }
    var p1 = new Person();
    Person.prototype.sayHi = function() {
        alert(this.name+":hi");
    }
    p1.sayHi(); // Leon:hi

    内存图如下所示:

    原型重写内存模型2

    如果把重写放置在new Person()之后,注意内存模型:

    function Person(){}
    var p1 = new Person();
    Person.prototype.sayHi = function() {
        alert(this.name+":hi");
    }
    
    Person.prototype = {
        constructor:Person,//手动指定constructor
        name:"Leon",
        age:23,
        say:function() {
            alert(this.name+","+this.age);
        }
    }
    p1.sayHi(); //undefined :hi  没有报错但是没有name

    内存模型如下所示:

    原型重写内存模型3

    function Person(){}
    var p1 = new Person();
    Person.prototype.sayHi = function() {
        alert(this.name+":hi");
    }
    
    Person.prototype = {
        constructor:Person,//手动指定constructor
        name:"Leon",
        age:23,
        say:function() {
            alert(this.name+","+this.age);
        }
    }
    p1.sayHi(); //undefined :hi  没有报错但是没有name
    var p2 = new Person();
    p2.sayHi(); //报错

    内存模型如下所示:

    原型重写存在的问题

    基于原型的创建虽然可以有效的完成封装,但是依然有一些问题:

    1、法通过构造函数来设置属性值;

    2、当属性中有引用类型变量时,可能存在变量值重复

    function Student(){
    }
    
    Student.prototype.username = new Array();
    Student.prototype.password = "123";
    Student.prototype.getInfo = function(){
        alert(this.username + "-->" + this.password); 
    }
    
    var s1 = new Student();
    var s2 = new Student();
    
    s1.username.push("ww");
    s1.username.push("ss");
    s1.password = "111";
    s1.getInfo(); //ww ss 111
    s2.getInfo(); //ww ss 123

    内存模型如下所示:

  • 相关阅读:
    C# 抽象方法和虚方法的区别
    xmlhttprequest readyState 属性的五种状态
    ServiceStack破解文件
    k8s部署mysql
    docker 开放2376端口的问题
    .net core 发布到IIS 没有 web.config 文件
    1064
    docker mysql 主从同步配置
    Docker 鼠标在虚拟机与主机之间自由切换
    Socket原理解析2
  • 原文地址:https://www.cnblogs.com/luogankun/p/3954300.html
Copyright © 2011-2022 走看看