• javascript中对象的创建-原型模式1


    function Person(name,age,job){
    }
    Person.prototype.name="nUll";
    Person.prototype.age=25;
    Person.prototype.job="software";
    Person.prototype.sayName=function(){
         alert(this.name); 
    };
    
    var person1=new Person();
    person1.sayName();    //nUll
    var person2=new Person();
    person2.sayName();    //nUll
    alert(person1.sayName==person2.sayName); //true

    原型中的所有属性与方法是所有实例所共享的.

    person1的内部属性prototype 指向 Person.prototype

    Person.prototype指向原型对象

    而原型对象中的构造函数属性constructor 指向Person

    注意,person1与person2与它们的构造函数没有直接关系,虽然这两个实例都不包含属性和方法,但是却可以调用person1.sayName(); 

    这里简述一下查找sayName的查找过程,类似于作用域链的查找过程,由下至上,即实例-原型

    person1与person2与它们的构造函数没有直接关系,那如何确定他们之间的间接关系呢?

    alert(Person.prototype.isPrototypeOf(person1));//true
    alert(Person.prototype.isPrototypeOf(person2));//true

    person1的内部属性prototype,在脚本中是无法直接访问的.但是可以通过其他方法访问,例如在ECMAScript5 中提供了Object.getPrototypeOf()方法,至于javascript与ECMAScript5 的关系,可以google一下.

    alert(Object.getPrototypeOf(person1)==Person.prototype);//true
    alert(Object.getPrototypeOf(person2).name);//nUll

    Object.getPrototypeOf()方法返回的对象,就是这个实例的原型

    如果给实例添加一个属性,这个属性与原型中的某个属性名称一样,那么该属性就会屏蔽原型中的属性.

    var person1=new Person();
    var person2=new Person();
    person1.name="mywei";    
    alert(person1.name); //mywei   来至实例
    alert(person2.name); //nUll 来至原型
    delete person1.name; //删除实例中的 name属性
    alert(person1.name); //nUll  又来至原型了

    如何判断实例的属性值来自实例还是来至原型?

    var person1=new Person();
    var person2=new Person();
    alert(person1.hasOwnProperty("name")); //false
    person1.name="mywei";    
    alert(person1.name); //mywei   来至实例
    alert(person2.name); //nUll 来至原型
    alert(person1.hasOwnProperty("name")); //true
    delete person1.name; //删除实例中的 name属性
    alert(person1.name); //nUll  又来至原型了
    alert(person1.hasOwnProperty("name")); //false

    实用代码:

    function hasPrototypeProperty(object,name){
            return !object.hasOwnProperty(name)&&(name in object);
    }
    
    var person1=new Person();
    alert(hasPrototypeProperty(person,"name")); //false 来自原型
    
    person1.name="mywei";
    alert(hasPrototypeProperty(person,"name")); //true 来自实例

    以上 name in object中的in操作符是判断 name的值是否存在于原型或实例中.其实,in操作符只能枚举必须是可枚举的([Enumerable]=true),属性有几种特性?google一下吧.

    另一种原型模式创建对象的方式:

    function Person(){
    }
    Person.prototype.name="nUll";
    Person.prototype.age=25;
    Person.prototype.job="software";
    Person.prototype.sayName=function(){
         alert(this.name); 
    };
    
    var person1=new Person();
    alert(person1 instanceof Object); //true
    alert(person1 instanceof Person);//true
    alert(person1.constructor==Person);//true
    alert(person1.constructor==Object);//true
    //--------------------------邪恶的分割线------------------------------------------//
    function Person(){
    }
    Person.prototype={
        name:"nUll",
        age:25,
        job="software",
        sayName=function(){
             alert(this.name);
        }
    }
    var person2=new Person();
    alert(person2 instanceof Object); //true
    alert(person2 instanceof Person);//true
    alert(person2.constructor==Person);//false 注意,这里变成了false原因在于这里的"字面量写法",覆盖了原型里的所有属性,包括constructor,而默认的constructor 是 Object
    alert(person2.constructor==Object);//true
    
    //怎么破? 写回去!
    function Person(){
    }
    Person.prototype={
        constructor:"Person",
        name:"nUll",
        age:25,
        job="software",
        sayName=function(){
             alert(this.name);
        }
    };
    //可惜的是,这样写回去会改变constructor属性的特性[Enumerable],默认情况下,constructor属性是不可枚举的.更好的写法是这样,当然,这是在建立在如何设定特性值的情况下,刚才说让你google的...:
    function Person(){
    }
    Person.prototype={
        constructor:"Person",
        name:"nUll",
        age:25,
        job="software",
        sayName=function(){
             alert(this.name);
        }
    };
    Object.defineProperty(Person.prototype,"constructor",{
        enumerable:false,
        value:Person
    });

    原型的动态性:

    function Person(){}
    var person1=new Person();
    Person.prototype.sayHi=function(){
         alert("hi");
    };
    person1.sayHi(); //hi      没有问题!原型中新增了sayHi方法,先找实例,没找到就找原型.
    
    
    function Person(){}
    var person1=new Person();
    Person.prototype(
         sayHi:function(){
         alert("hi");
         }
    };
    person1.sayHi(); //error    刚说过了,尽管上面为原型添加属性和方法可以在所有对象的实例中反映出来,但这种"字面量"写法重写了整个原型,情况就不一样了.这种重写已经改变原有对象与构造函数之间的联系,它是一个新的原型(虽然旧的原型没有显式定义,但它确实存在?)
    
        

     如何为通过原型模式为原生对象添加方法:

    String.prototype.startsWith=function(text){
          return this.indexOf(text)==0;
    }
    var msg="Hello world";
    alert(msg.startsWith("Hello"));  //true   说的好!但这毫无意义(这里仅是提供扩展的示例,并不是说扩展的startsWith方法多么的精辟!)

    原型对象的缺点:

    function Person(){}
    Person.prototype={
            name:"nUll",
            friends:["gay1","gay2"],
            sayName:function(){
                   alert(this.name);
            }  
    };
    var person1=new Person();
    var person2=new Person();
    person1.friends.push("gay3");
    alert(person2.friends); //gay1,gay2,gay3
    //WTF? person2 的friends 怎么会有gay3?  好吧,如果这就是你想要的结果,就当书上什么也没说-_- 
  • 相关阅读:
    webkit webApp 开发技术要点总结
    EJB 教程推荐
    MySQL 教程分享
    php 教程列表
    html 学习资料列表
    JAVA 教程推荐
    php+mysql预查询prepare 与普通查询的性能对比
    Spring 5 新特性:函数式Web框架
    Java多线程之并发协作生产者消费者设计模式
    php使用file函数、fseek函数读取大文件效率分析
  • 原文地址:https://www.cnblogs.com/nullcnb/p/3653262.html
Copyright © 2020-2023  润新知