zoukankan      html  css  js  c++  java
  • JS 创建对象的方法及各种方法的优劣比较 ----JS 学习笔记(四)

    一、最简单的创建对象的两种方法

    1. 创建一个 Object 的实例,然后在为他添加属性和方法:

    var person = new Object();
    person.name = "Jhon";
    person.age = 23;
    person.sayHi = function() {
        console.log("hello,", person.name);
    }
    // 调用对象的方法 person.sayHi() // hello,Jhon

    2. 对象字面量的方法创建对象:目前比较常用的是这种对象字面量的方法

    var person = {
        name: "Jhon",
        age:"23",
        sayhello : function () {
            console.log("Hello,", person.name)
        }
    }
    person.sayhello();

    上面两种方法的缺点:虽然能用来创建单个对象,但是,使用一个接口创建很多对象,会产生大量重复的代码。为解决这个问题,产生了下面的各种创建对象的方法:

    二、工厂模式,用函数来封装以特定接口创建对象的细节:

    function createPerson(name, age, job) {
        var o = new Object();
        o.name = name;
        o.age = age;
        o.job = job;
        o.sayhi = function() {
            console.log("hello,", o.name)
        };
        return o;
    }
    
    var p1 = createPerson("Jack", "23", "doctor");
    var p2 = createPerson("Mary", "11", "student");

    console.log(p1 instanceof createPerson); // false
    console.log(p1 instanceof Object); // true

    工厂模式的缺点:虽然解决了创建多个相似对象的问题,但是没有解决对象识别问题。例如上面,只能判断实例的类型是 Object,但判断不出来是 createPerson。

    三、构造函数模式:

    function Person(name, age, obj) {
        this.name = name;
        this.age = age;
        this.obj = obj;
        this.sayHi = function () {
            console.log(`hello, ${this.name}`);
        }
    }
    
    var p3 = new Person("Jhon", "22", "doctor")
    p3.sayHi();
    var p4 = new Person("Tom", "22", "doctor")
    console.log(p3.sayHi() === p4.sayHi()) // false
     

    对比和工厂模式的不同:1. 没有显示的创建对象;2. 直接将属性和方法赋给了 this 对象;3. 没有 return 语句;4. 使用的时候要用 new 来创建一个新的实例。5. 解决了对象识别问题:constructor 属性指向 Person;或者用 p1 instanceof Person 进行检测。解决对象标识问题上,构造函数模式,优于工厂模式。

    new 的过程经过四个步骤:1. 创建一个新的对象; 2. 将构造函数的作用域赋给新的对象(因此,this 就指向了这个新的对象。注意总结 this 的情况);3. 执行函数中的代码(为这个新的对象添加属性和方法); 4. 返回新的对象。或者这样理解:先把参数传进去,或者不传参数。函数执行的时候,函数里面的 this 先变成一个空对象,再在函数里面对 this. name this.age 进行赋值,赋值之后,返回这个 this。最后,再把存好地址赋值给 doctor 这个变量。

    构造函数缺点:每个方法都要在每个实例上重新创建一遍。这样,不同实例上的同名函数式不相等的。解决方法1. 把所有实例共用的方法放在构造函数的外面 --- 全局作用域中。这样,所有的实例,都可以调用这个方法了。但随之而来的问题是:全局作用域中定义的方法实际上只对某几个实例调用,让全局作用域有点名不副实。而且,对象需要定义很多方法,那么就需要定义很多全局作用域的函数,那么我们自定义的这个引用类型就毫无封装性可言了。所以可以用原型模式来解决这个问题。

    四、原型模式:每个函数都有 prototype(原型)属性,这个属性是一个指针,指向原型对象,这个原型对象里面包含了实例共享的属性和方法。prototype 就是调用构造函数而创建的实例的原型对象。使用原型对象的好处是,让所有对象实例共享原型对象里面的方法和属性。换句话说就是,不必在构造函数中定义实例的信息,而是将这些信息直接添加到原型对象中。

    function Person() {
    
    }
    
    Person.prototype.name = "Jhon";
    Person.prototype.age = "12";
    Person.prototype.obj = "doctor";
    Person.prototype.sayName = function() {
        console.log(this.name);
    }
    
    var p5 = new Person();
    p5.sayName()  // "Jhon"
    var p6 = new Person();
    p6.sayName()  // "Jhon"
    
    console.log(p5.sayName() === p6.sayName())  // true

    理解原型对象

    原型模式缺点:修改一个实例的引用类型(array,function)的属性,也会影响到另一个实例的引用类型属性。例如下面例子中的 friends 属性,修改了 p7 的,会影响到 p8。注意对于基本类型的属性,修改后不会有影响。在实例中添加一个同名的基本类型的属性,可以隐藏原型中对应的属性。解决方式,结合使用构造函数模式和原型模式。

    function Person() {
    
    }
    
    Person.prototype = {
        name : "Jack",
        age : '23',
        friends : ["a", 'b']
    }
    
    var p7 = new Person();
    var p8 = new Person();
    p7.friends.push("Tom");
    console.log(p7.friends);  // [ "a", "b", "Tom" ]
    console.log(p8.friends);  // [ "a", "b", "Tom" ]

    五、组合使用构造函数模式和原型模式

    每个实例都会有一份自己的实例属性副本,但同时又共享着对方法的引用,最大限度的节省了内存。把每个实例不同的写入构造函数中,相同的写入 prototype 中。

    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.friends = ['a', 'b']
    }
    
    Person.prototype = {
        sayhi : function() {
            console.log("hi,", this.name)
        }
    }
    
    var p9 = new Person('Jhon', "23")
    var p10 = new Person('Tom', "12")
    
    p9.friends.push("Jack");
    
    console.log(p9.friends)   // [ "a", "b", "Jack" ]
    console.log(p10.friends)  // [ "a", "b"]
  • 相关阅读:
    ASP.NET获取客户端IP地址Marc地址
    WPF(MultiBinding 数据对比验证,启用提交)
    WPF(Binding of ObjectDataProvider)
    WPF(附加属性 Slider)
    WPF(Binding of ItemsControl)
    WPF( 数据验证)
    WPF(依赖属性)
    WPF(附加属性)
    WPF(Binding of RelativeSource)
    WPF(Binding of LinQ)
  • 原文地址:https://www.cnblogs.com/rougan/p/10600578.html
Copyright © 2011-2022 走看看