javascript创建对象

前端这块,不总结感觉自己都得要学晕。

  1. 标准对象模式

    var person = new Object();
    person.name = "Nicholas";
    person.age = 29;
    person.job = "Software Enginner";
    person.sayName = function () {
         console.log(this.name);
    }
  2. 对象字面量形式

    var person = {
        name: "Nicholas",
        age: 29,
        job: "Software Enginner",
        sayName: function () {
            console.log(this.name)
        }
    }
  3. 工厂模式

    抽离了创建具体对象的过程,使用函数来封装以特定接口创建对象的细节
    优点:可以反复创建相似的对象
    缺点:无法解决对象识别的问题

    function createPerson(name, age, job) {
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayName = function () {
            console.log(this.name)
        }
        return o
    }
    var person1 = createPerson("hugo", 18,"webFont");
    var person2 = createPerson("hugo2", 18,"webFont2");
    
    console.log(person1, person2);
    //此时,得到person1 和 person2 都是Object类型
    //假如我们继续创建另外一个工厂,用来创建一个动物类。那么它的类型也一定是Object
    //所以,不管是哪个工厂,创建出来的对象类型居然一致,也就是上面所说的无法解决对象识别的问题
    
  4. 构造函数模式

    优点:解决了工厂模式无法解决对象识别的问题, 没有显示的创建对象,直接将属性和方法赋给this对象,没有return对象

    缺点:在案例中,每个Person对象都包含一个不同的Function实例的本质,以这种方式创建函数,会导致不同的作用域链和标识符解析,但创建Function新实例的机制仍是相同的。而如果将方法放到全局作用域中,自定义的引用类型就没有封装性可言
    new操作具体做了什么(调用构造函数实际操作步骤)?
    —1、创建一个新对象
    —2、将构造函数的作用域赋值给新对象(this指向该对象)
    —3、执行构造函数中的代码(为新对象添加属性)
    —4、返回新对象

    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = function () {
            console.log(this.name)
        }
    }
    var person3 = new Person("hugo",18,"webFont");
    console.log(person3);
    //检测对象类型
    console.log(person3.constructor == Object); //false
    console.log(person3.constructor == Person); //true
    console.log(person3 instanceof Object); //true
    console.log(person3 instanceof Person); //true
    
    var person4 = new Person("hugo2",18,"webFont2");
    person4.sayName(); //hugo2
    console.log(person3.sayName() == person4.sayName()); //ture
    
    //将共有的方法放在外面
    
    function Person2(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = sayName2;
    }
    function sayName2() {
        console.log(this.name)
    }
    var person11 = new Person('hugo11',18, 'webFont11');
    var person22 = new Person('hugo11',18, 'webFont11');
    console.log(person11.sayName == person22.sayName); //true
    //将方法放在外面,存在一个问题,这样会造成全局变量的污染。
  5. 原型模式(很少使用)

    省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值,需要各自单独传入参数

    优点:可以解决构造函数模式创建多个方法实例的问题,可以让所有对象实例共享原型所包含的属性和方法,不必在构造函数中定义对象实例的信息,而可以直接将信息添加到原型对象中

    function Person3() {
    
    }
    Person3.prototype.name = "hugo";
    Person3.prototype.age = 18;
    Person3.prototype.sayName = function () {
        console.log(this.name)
    };
    var person33 = new Person3();
    person33.sayName(); //hugo
    var person44 = new Person3();
    person44.name = "hugo33";
    person33.sayName(); //hugo
    person44.sayName(); //hugo33
    console.log(person33.sayName == person44.sayName); //true
    //对原型中的初始值修改后,所有子实例都会修改初始值
    Person3.prototype.name = "HUGO";
    person33.sayName(); //HUGO
    person44.sayName(); //hugo33
    
    //*********************************************************
    //用对象字面量的形式来创建原型,注意:此时是相当于创建了一个新的对象。此时constructor属性不再指向Person,而是指向Object,所以应该修改constructor的指向
    function Person55() {
    
    };
    Person55.prototype = {
        name: 'hugo',
        age: 18,
        sayName: function () {
            console.log(this.name)
        }
    }
    var person66 = new Person55();
    console.log(Person55.constructor); //[Function: Function]
    console.log(person66.constructor); //[Function: Object]
    
    //正确写法如下
    function Person66() {
    
    };
    Person66.prototype = {
        constructor: Person66,
        name: 'hugo',
        age: 18,
        sayName: function () {
            console.log(this.name)
        }
    }
    var person77 = new Person66();
    console.log(person77.constructor); //[Function: Person66]
    console.log(person77 instanceof Person66); //true
    
    //问题:对于一个实例的数组进行操作时,其他所有实例都会跟随着变化
    function Animal() {
    
    }
    Animal.prototype = {
        constructor: Animal,
        name: "Dog",
        arr: [1,2]
    }
    var animal = new Animal();
    var animal2 = new Animal();
    console.log(animal.arr); //[ 1, 2 ]
    console.log(animal2.arr); //[ 1, 2 ]
    animal.arr.push(3);
    console.log(animal.arr); //[ 1, 2, 3 ]
    console.log(animal2.arr); //[ 1, 2, 3 ]
    console.log(animal.arr === animal2.arr); //true
    
  6. 组合使用构造函数模式和原型模式

    是最常见的方式,构造函数模式用于定义实例属性,原型模式用于定义方法和共享属性。支持向构造函数传递参数

    优点:每个实例都有自己的一份实例属性的副本, 同时又共享着对方法的引用,最大限度节省内存。

    function Student(name, age) {
        this.name = name;
        this.age = age;
        this.arr = [1,2];
    }
    Student.prototype = {
        constructor: Student,
        sayName: function () {
            console.log(this.name)
        }
    }
    var student1 = new Student('jiang',18);
    var student2 = new Student('wei',18);
    student1.arr.push(3);
    console.log(student1.arr); //[ 1, 2, 3 ]
    console.log(student2.arr); //[ 1, 2 ]
    console.log(student1.arr === student2.arr); //false
    console.log(student1.sayName === student2.sayName); //true
  7. 动态原型模式

    将所有信息都封装在构造函数中,通过在构造函数中初始化原型(必要情况下)由保持了同时使用构造函数和原型的优点

    优点:可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型

    注意点:在该模式下不能使用对象字面量重写原型。如果在已经创建了实例的情况下重写原型,会切断现有实例和新原型之间的联系

    function Student(name, age) {
        this.name = name;
        this.age = age;
        // 只有在sayName()方法不存在的情况下,才会将它添加到原型中,if这段代码只会在初次调用构造函数时才会执行
        // 这里对原型所做的修改,能够立即在所有实例中得到反映
        if(typeof this.sayName != "function"){
            Student.prototype.sayName = function () {
                console.log(this.name);
            }
        }
    }
    var student = new Student('hugo',18);
    student.sayName(); //hugo
    
  8. 寄生构造函数模式

    在前几种模式不适用的情况下,可以使用寄生(parasitic)构造函数模式

    创建一个函数,仅封装创建对象的代码,然后返回新创建的对象

    与工厂模式的区别:使用new操作,并把使用的包装函数叫做构造函数

    使用场景: 假设我们想创建一个具有额外方法的特殊数组,由于不能直接修改Array构造函数,就可以使用这个模式

    注意点:返回的对象与构造函数或与构造函数的原型属性之间没有关系,也就是说,构造函数返回的对象与在构造函数外部创建的对象没有不同,不能依赖instanceof操作符来确定对象类型,如果可以使用其他模式的情况下,建议不要使用这种模式

    function Student(name, age) {
        var o = new Object();
        o.name = name;
        o.age = age;
        o.sayName = function () {
            console.log(this.name)
        }
        return o
    }
    var student = new Student('hugo', 18);
    student.sayName();
    
    //使用场景
    function NowArray() {
        var arr = new Array();
        arr.push.apply(arr,arguments);
        arr.toNowString = function () {
            return this.join('-');
        };
        return arr
    }
    var nums = new NowArray('1','2','3');
    console.log(nums); //[ '1', '2', '3', toNowString: [Function] ]
    console.log(nums.toNowString()); //1-2-3
  9. 稳妥构造函数模式

    指的是没有公共属性而且其方法也不引用this的对象

    使用场景:安全的环境中(这些环境会禁止使用this和new),防止数据被其他应用程序改动时使用

    与寄生构造函数模式的区别:新建对象时不引用this,不适用new操作符构造函数。与寄生构造函数模式类似,该模式创建的对象与构造函数之间也没有什么关系,instanceof操作符无意义

    function Student(name, age) {
        var o = new Object();
        o.name = name;
        o.age = age;
        o.sayName = function () {
            console.log(this.name)
        }
        return o
    }
    var student = Student('hugo', 18);
    student.sayName();
    
  10. 闭包类

    最关键的差别就是多了一层作用域

    (function () {
        var a = 10;
        var People = function (name, age) {
           this.name = name;
           this.age = age;
        }
        People.prototype.hei = function () {
            console.log(a)
        }
    })()
  11. 单例模式

    直接初始化,而是等到某一个条件触发的时候才初始化。而且,初始化的需求比较多的时候。

    var Single = (function () {
        //定义一个构造函数
        function People(name, age) {
            this.name = name;
            this.age = age;
        }
        //定义一个单例变量用于保存单例
        var instance = null; //惰性单例
        //非惰性
        //var instance = new People("hugo", 18);
        console.log(instance);
        return function () {
            //惰性单例
            if(instance === null){
                return instance = new People("hugo", 18)
            }else{
                return instance
            }
            //非惰性
            //return instace
        }
    })()
    
  12. 安全类

    在创建一个构造函数的实例的时候。如果我们知道它是一个构造函数,我们会自动的去使用new关键字 但是,如果不知道的人去书写我们的代码。那么就会出问题。

     function People(name, age){
         this.name = name;
         this.age = age;
     }
     当不使用new的时候,我们执行一下
     var people = People("hugo",18,);
     console.log(people);
    // 当People自己执行的时候,我们可以视为window.People执行。所以内部的this其实是window// 分析一下:People 与 new People在执行的时候,有什么区别?
    // 内部的this不同。
    // 根据这个this来进行不同的处理。以便得到一致的结果

安全类就是为了解决这一类问题

function People(name, age){
    // 如果this是People的实例 我们才可以使用this来赋值
    if(this instanceof People){
        this.name = name;
        this.age = age;
    }else{
        // 不管什么方式调用,只要你的this不是People的实例,我就返回一个实例给你。
        // People执行的时候,this不是People的实例,就是一个普通的函数在调用。那么一个普通函数是不会自动返回数据的。所以必须要加return关键字
        return new People(name,age);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值