• JS如何创建对象和继承对象


    JS创建对象的几种方法:工厂模式,构造函数模式,原型模式,混合模式,动态原型模式

    1 在工厂模式中,在构造函数内部创建一个新对象,最后返回这个对象。当实例化时,我们不需要用new关键字,就像调用方法一样就可以实例化。

    工厂模式的缺点是容易和普通函数混淆,只能通过命名来确认它是一个 构造函数。不推荐使用这种模式。

    //factory pattern

    function createPerson(name, age, job){
        var o = {};
        o.name = name;
        o.age = age;
        o.job = job;
        o.friends = ["Mike", "Sun"];
        o.sayName = function(){
            alert("factory pattern: " + this.name);
        }
        return o;
    }

    var Abby = createPerson("Abby", "22", "Softwarre Engineer");
    Abby.sayName();

    2 构造函数模式,用new关键字来实例化对象。与工厂方式相比,使用构造函数方式创建对象,无需在函数内部重新创建对象,而使用this指代,并且函数无需明确return。不推荐使用这种模式。

    构造函数的缺点是不断的拷贝,每new一次就造出一个副本,每个方法都要在每个实例上重新创建一遍,显然这样是不行的,我们想要的是一种有些方法共享所有,有此方法私有,于是Eric发明了原型链。

    //constructor pattern
    function Person(name, age, job){
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = function(){
            alert("constructor pattern: " + this.name);
        }
    }

    var Abby = new Person("Abby", "22", "Software Engineer");
    Abby.sayName();

    3 原型模式,这里就要说到prototype。我们创建的每个函数都有有一个 prototype(原型)属性,它也是一个对象,它的用途是包含有特定类型的所有实例的属性和方法。不推荐使用这种模式。

    下面例子,我们把所有方法一个个添加到prototype上,但由于prototype上方法属于一种共享,这些方法有些别人用的到,有些别人根本用不到,有些别人想用的没有的方法还要再次往prototype上添加。这样就不好了,所以最常用的模式其实是混合型的。

    //prototype pattern
    function Abby(){}

    Abby.prototype.name = "Abby";
    Abby.prototype.age = "22";
    Abby.prototype.sayName = function(){
        alert("prototype pattern: " + this.name);
    }

    var person1 = new Abby();
    person1.sayName();

    4 构造函数模式和原型模式的混合类型。将所有属性不是方法的属性定义在函数中(构造函数方式),将所有属性值为方法的属性利用prototype在函数之外定义(原型方式)。 推荐使用这种方式创建对象。

    //hybrid constructor & prototype pattern
    function Student(name, sno){
      this.name = name;
      this.sno = sno;
      this.sayName = function(){
        alert("hybrid constructor & prototype pattern: " + this.name);
      }
    }

    Student.prototype = {
      constructor : Student,
      teacher : ["mike", "abby"],
      sayTeacher : function(){
        alert("hybrid constructor & prototype pattern(teacher): " + this.teacher);
      }
    }

    var zhangsan = new Student("zhangsan", "22");
    var lisi = new Student("lisi", "23");
    zhangsan.sayName();
    lisi.sayName();
    zhangsan.sayTeacher();
    lisi.sayTeacher();

    5 动态原型方式

    动态原型方式可以理解为混合模式的一个特例。该模式中,属性为方法 的属性直接在函数中进行了定义,但是因为if从句从而保证创建该对象的实例时,属性的方法不会被重复创建。推荐使用这种模式。

    //dynamic prototype pattern
    function Person(){
      this.name = "Mike";
      this.age = 22;
    }
    if (typeof Person._lev == "undefined"){
       Person.prototype.lev = function(){
         return this.name;
       }
       Person._lev = true;
    }

    var x = new Person();
    alert(x.lev());

    6. 寄生构造函数模式

    //parasitic constructor pattern (hybird factory)
    function Person1(name, age, job){
      var o = new Object();
      o.name = name;
      o.age = age;
      o.job = job;
      o.sayName = function(){
        alert(this.name);
      }
      return o;
    }

    var mike = new Person1("Mike", 22, "Software Engineer");
    mike.sayName();

    7 稳妥构造函数模式,这种模式不用this,不用new,目的是安全,这是一种方法,不是主流

    //durable constructor pattern
    function Person2(name, age, job){
      var o = new Object;
      o.name = name;
      o.age = age;
      o.job = job;
      o.sayName = function(){
        alert(name);
      }
      return o;
    }

    var mike = Person2("Mike", 22, "Software Engineer");
    mike.sayName();


    JS中的继承主要依靠原型链。

    每个构造函数都拥有一个原型对象,原型对象都包含一个指向构造函数的指针(constructor),实例都包含一个指向原型对象的内部指针(_proto_)。

    如果对原型进行多次赋值,那么后面的赋值会覆盖前面的,也就是通过原型链只能继承离实例化最近的一个 原型对象。

    原型链继承的本质就是一个单链表的深度搜索。例如,原型对象(Son.prototype)等于另一个原型(Person)的实例(person1),那么此时的原型对象(Son.prototype)将包含一个指向另一个原型(Person.prototype)的指针,相应的,另有一个原型(Person.prototype)中也包含着一个指向另一个构造函数(Person())的指针。

    再如,另一个原型(Person.prototype)又是另一个类型(Person)的实例(person1),那么上述关系依旧成立,如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链。

    所有引用类型默认继承了Object类型,所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype.这也正是自定义类型能通过使用toString()等默认方法的原因。

    在通过原型链实现继承时,不能使用对象字面量创建原型对象,这样会重写原型链。

    call函数的用法(可用于实现继承)

    call([thisObj[,arg1[, arg2[,   [,.argN]]]]]),调用一个对象的一个方法,以另一个对象替换当前对象。

    call方法可以用来代替另一个对象调用一个方法。call方法可将一个函数的对象上下文从初始的上下文改变为由htisObj指定的新对象。如果没有提供thisObj参数,那么Global对象被用作thisObj。

    function Animal(name){
      this.name = name;
      this.showName = function(){
        alert(this.name);
      }
    }

    function Cat(name){
      Animal.call(this, name);
    }

    var cat = new Cat("Black Cat");
    cat.showName();

    Animal.call(this) 的意思就是使用 Animal对象代替this对象,那么 Cat中不就有Animal的所有属性和方法了吗,Cat对象就能够直接调用Animal的方法以及属性了.

    同样,如果使用多个call就可以实现多重继承。

    new操作符创建实例的过程:创建一个新对象->将构造函数的作用域赋给新对象(因此this就指向了这个新对象)->执行构造函数的代码(为这个新对象添加属性)->返回新对象

  • 相关阅读:
    Memoization-329. Longest Increasing Path in a Matrix
    Map-560. Subarray Sum Equals K
    Geometry-587. Erect the Fence
    Reservoir Sampling-382. Linked List Random Node
    Brainteaser-292. Nim Game
    Minimax-486. Predict the Winner
    Topological Sor-207. Course Schedule
    web前端开发规范手册
    css初始化
    asp.net LINQ实现数据分页
  • 原文地址:https://www.cnblogs.com/sunshinegirl-7/p/5193481.html
Copyright © 2020-2023  润新知