工厂模式,构造函数模式和原型模式

红宝书P144,152

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script>
    //-----------------------------工厂模式
    function createPerson(name,age,job) {
        var n = new Object();
        n.name = name;
        n.age = age;
        n.job = job;
        n.sayName = function () {
            console.log(this.name)
        };
        return n;
    }
    let person1 = createPerson("Hongbin",21,"students");
    let person2 = createPerson("Hongbin2",21,"Software Engineer");

    // console.log(person1);
    // console.log(createPerson.prototype.__proto__.constructor);// Object() { [native code] }
    // console.log(person1.__proto__.constructor);// Object() { [native code] }
    // console.log(person1 instanceof createPerson);//false
    // console.log(person2);
    //工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别问题(即怎样知道一个对象的类型),所以有了下面的新模式出现

    //----------------------------构造函数模式(首字母大写,用new创建实例)
    function Person(name,age,job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.say = function () {
            console.log(this.name)
        }
    }
    let Person1 = new Person("Hongbin1",21,"Problem Solve");
    let Person2 = new Person("Hongbin2",21,"program");

    // console.log(Person1.say() === Person2.say());//true 他俩调用的函数一相同的,不是一个
    //console.log(Person.prototype === Person1.__proto__);//true
    //Person1是Person的一个实例,Person1的__proto__指向person1所属类的原型(prototype)。Person2也一样
    //console.log(Person1.__proto__);//IE并没有__proto__属性,所以要用下面的方法获取
    // Object.getPrototypeOf()
    //__proto__([[prototype]])是一个指针,指向该实例的类的prototype属性,叫[[prototype]],要注意它连接于实例与构造函数的原型对象之间。
    //console.log(Object.getPrototypeOf(Person1));
    //还有一个方法isPrototypeOf()测试传入实例的__proto__属性([[prototype]])是否指向调用该方法的对象的原型,返回布尔值
    //console.log(Person.prototype.isPrototypeOf(Person1));
    //console.log(Person1);
    //console.log(Person2);
    //创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型;而这正式构造函数胜过工厂函数的地方。

    //构造函数模式的缺点:每创建一个实例,就会创建一个say方法,或者换一种写法:
    function Person(name,age,job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.say = say;
    }
    function say () {
        console.log(this.name)
    }

    var person3 = new Person("Honbgin3",21,"Doctor");
    var person4 = new Person("Honbgin4",21,"Children");

    // console.log(person3.say() === person4.say());//true  比较的是say()这个方法,并不是说他俩调用say方法结果是相同的
    //console.log(person3);
    //console.log(person4);
    //这样虽然解决了不同的实例调用一个方法,但这个say方法定义在全局作用域中,却只能被某独享调用,全局作用域有点名不其实;更主要的是如果需要多个方法,要在全局作用域中定义多个全局函数,这使我们自定义的引用类型没有丝毫封装性可言。  于是有了新的方法解决问题:原型模式

    //原型模式
    /*
    * 我们创建的每一个函数都有一个prototype(原型)属性,该属性是一个指针,指向一个对象,这个对象是包含可以由特定类型的所有实例共享的属性和方法,使用函数原型的好处是可以让所有据此创建的实例共享该函数所包含的所有属性和方法。就是说,不必在构造函数中定义独享实力的信息,而是将这些信息直接添加到对象的原型中,如下所示:
    * 注意:函数prototype中的属性和方法是实例共享的,所以prototype自带的constructor属性也是它的实例可以直接访问的。
    * */
    function Dog() {
    }

    Dog.prototype.name = "xiaoxiaobin";
    Dog.prototype.age = 2;
    Dog.prototype.job = "happy everyday";
    Dog.prototype.say = function () {
        console.log("Wang! Wang!"+this.job);
    };

    var dog1 = new Dog();
    dog1.say();//Wang! Wang!happy everyday
    console.log(dog1);
    //每次执行执行读取某对象属性时,都会执行一次搜索,目标是具有给定的名字的属性。搜索首先从对象实例本身开始,如果找到,返回,如果没有,则顺着原型链向上找,直至找到
    //实例可以访问原型中的值,但不可以改变,如果在实例中定义了一个和原型中同名的属性,那就再实例中创建了该值,该值会屏蔽原型中的同名值。
    dog1.name = "tiger";
    console.log(dog1);//"tiger" --来自实例
    var dog2 = new Dog();
    dog2.say();//Wang! Wang!happy everyday
    console.log(dog2);//{}
    console.log(dog2.name);//"xioxiaobin" --来自原型
    //可以说再实例中定义的属性,阻止查找原型中同名属性,要想恢复原型中属性,只需将实例中同名的属性用delete操作符删掉即可
    delete dog1.name;
    console.log(dog1.name);//xiaoxiaobin

    //console.log(dog1.constructor);// constructor属性返回对创建此对象的数组函数的引用
    //函数prototype中的属性和方法是实例共享的,所以prototype自带的constructor属性也是它的实例可以直接访问的。
    //console.log(dog1.say === dog2.say);//true
    //console.log(Object.getPrototypeOf(dog1) === Dog.prototype);//true
    ////IE并没有__proto__属性,所以要用下面的方法获取
    // Object.getPrototypeOf()
    //__proto__([[prototype]])是一个指针,指向该实例的类的prototype属性,叫[[prototype]],要注意它连接于实例与构造函数的原型对象之间。
    //console.log(Object.getPrototypeOf(dog1))//dog1的__proto__;
    //还有一个方法isPrototypeOf()测试传入实例的__proto__属性([[prototype]])是否指向调用该方法的对象的原型,返回布尔值
    // console.log(Dog.prototype.isPrototypeOf(dog1));//true

    //方法 hasOwnProperty()方法可以检测一个属性是在实例中还是原型中,在实例中返回true
    dog1.age = 3;
    console.log(dog1.hasOwnProperty("age"));//true
    console.log(Object.getOwnPropertyDescriptor(dog1,"age"));//获取某对象上某属性的特性(描述符)
    delete dog1.age;
    console.log(dog1.hasOwnProperty("age"));//false
    console.log(Object.getOwnPropertyDescriptor(Dog.prototype,"age"));//如果要获取原型属性的描述符,必须在原型对象上调用Object.getOwnPropertyDescriptor()方法
    Object.defineProperties(dog1,{
        name:{//用了这个方法后,不特意声明4个特性(描述符)均默认为false
            value:"newName"
        }
    });

    console.log(Object.getOwnPropertyDescriptor(dog1,"name"));

    for (var value in dog1){
        console.log(value);
    }

</script>
</body>
</html>
发布了40 篇原创文章 · 获赞 54 · 访问量 7381

猜你喜欢

转载自blog.csdn.net/printf_hello/article/details/104249130