JS面向对象——原型模型

以下通过一段示例代码,说明原型模型中的基本概念以及知识点。

<!DOCTYPE html>
<html>
<head>
    <title>原型模型</title>
    <script type="text/javascript">
        function Person(){};

        // Person.prototype.name="Lucy";
        // Person.prototype.age=15;
        // Person.prototype.sayName=function(){
        //     alert(this.name);
        // };

        //3.更简单的原型语法
        Person.prototype={
            constructor:Person,//若constructor属性值真的很重要,则需要手动设置回适当的值。
            name:"Lucy",
            age:15,
            sayName:function(){
                alert(this.name);
            }
        };

        // var p1,p2;
        p1=new Person();
        p2=new Person();
        //hasOwnProperty()检测一个属性存在于实例中(true),还是存在于原型中(false)
        alert(p1.hasOwnProperty("name"));//false
        p1.name="Bob";
        p1.job="student";//设置实例属性
        alert(p1.name);//"Bob",来自实例
        alert(p1.hasOwnProperty("name"));//true

        alert(p1.sayName==p2.sayName);//true 检查实例是否共享方法
        alert(p1.job);        
        alert(p1.hasOwnProperty("age"));//false
        alert(p1.hasOwnProperty("job"));//true

        // /*********************************** 2.原型与in操作符 *********************************************/

        // /********单独使用in操作符********/
        // 通过对象能够访访问到属性时,返回true
        alert("job" in p1);//true
        alert("age" in p1);//true
        alert("name" in p1);//true
        alert("name" in p2);//true

        //该函数确定属性是存在于原型对象中还是存在于实例对象中。 true:属性为原型对象属性;false:为实例对象属性。
        function hasPrototypeProperty(object,name){
            return !object.hasOwnProperty(name)&&(name in object);
        }
        alert(hasPrototypeProperty(p1,"job"));
        alert(hasPrototypeProperty(p2,"name"));
        // /******************************/

        // /********for-in ***********/
        // 返回的是所有能够通过对象访问的、可枚举的属性,其中包括存在于原型中的属性、也包括存在于实例中的属性。
        // Object.keys(object):接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。
        var keys=Object.keys(Person.prototype);
        alert(keys);//"name,age,sayName" 
        var p1keys=Object.keys(p1);
        alert(p1keys);//"name,job"

        //顺序即为for-in访问时的顺序
        for(var prop in p1keys){
            alert(p1keys[prop]);
        }

        //Object.getOwnPropertyNames(object) 获取实例所有属性,包括不可枚举属性
        var p1allkeys=Object.getOwnPropertyNames(p1);
        alert(p1allkeys);//"name,job"        
        var p1allkeys=Object.getOwnPropertyNames(Person.prototype);
        alert(p1allkeys);//constructor,name,age,job,sayName   constructor属性为不可枚举
        // /******************************/
        //  /*****************************************************************************************/


        /************************************ 3.更简单的原型语法 ****************************************/
        //设置为简单的原型语法后,Person.prototype设置为一个以对象字面量形式创建的新对象。最终结果相同,不过对象的constructor属性不再指向Person。
        //若constructor属性值真的很重要,则需要手动设置回适当的值。
        var friend=new Person();
        alert(friend instanceof Object);//true
        alert(friend instanceof Person);//true
        alert(friend.constructor==Person);//false
        alert(friend.constructor==Object);//true

        var keys2=Object.keys(Person.prototype);
        alert(keys2);//constructor,name,age,job,sayName   //简单原型语法中手动设置constructor属性之后,会导致它的[Enumerable]特性值为true,默认情况下原生的constructor值为false
        //重设构造函数,只适用于ECMAScript5兼容浏览器
        Object.defineProperty(Person.prototype,"constructor",{
            enumerable:false,
            value:Person
        });
        var keys3=Object.keys(Person.prototype);
        alert(keys3);//name,age,job,sayName //
         /**********************************************************************************************/


        /************************************ 4.原型的动态性 ****************************************/
        var per=new Person();
        //可以随时为原型添加属性和方法,并且所有的修改能够立即在所有对象实例中反映出来。        
        Person.prototype.sayHi=function(){
            alert("Hi!");
        }
        per.sayHi();


        //若重构整个原型对象,就会在调用构造函数时为实例添加一个指向最初原型的[Prototype]指针,而把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。
        //实例中的指针仅指向原型,而不是构造函数。
        function Student(){};        
        var st=new Student();//先创建实例对象            
        Student.prototype={//重构原型对象原型
            constructor:Student,
            name:"Nike",
            age:20,
            speakEnglish:function(){
                alert("Hello!");
            }
        };
        st.speakEnglish();//error  0: Object doesn't support property or method 'speakEnglish'
        //  /**********************************************************************************************/


        /************************************ 5.原型的问题 ****************************************/
        //原型中所有属性是被很多实例共享的,这种共享对于函数非常适合。对于包含基本值得属性也没有什么,通过在实例上添加一个同名属性就可以隐藏原型中对应的属性。
        //然而,对于包含引用类型的值来说,就会存在问题。如下例所示。
        function Singer(){};                
        Singer.prototype={
            constructor:Singer,
            name:"Nike",
            age:30,
            albums:["Suger","Live"]//"Suger","Live"是所有实例对象的共享albums集合
        };
        var s1=new Singer();
        var s2=new Singer();
        s1.albums.push("Flowers");//“Flowers”是s1的唱片集
        alert(s1.albums);//"Suger","Live","Flowers"
        alert(s2.albums);//"Suger","Live","Flowers",而"Flowers"不是s2的唱片
        alert(s1.albums===s2.albums);//指向同一个albums 
        /**********************************************************************************************/
    </script>
</head>
<body>

</body>
</html>

部分摘自《JavaScript高级程序设计(第3版)》

posted @ 2019-09-16 21:34  用脑袋行走的人  阅读(584)  评论(1编辑  收藏  举报