基本二:javascript面向对象、建立对象、原型和继续总结(上)

媒介:本文主要总结一下javascript建立对象的要领、原型、原型链和继续,然则先从建立对象的几种要领最先,延伸到原型情势建立对象以及别的情势。继续原本想一块写了,发明太多内容了,放到下里总结。

1.建立对象

(1)两个基础要领

建立对象最基础的两个要领是:Object组织函数对象字面量

    //Object组织函数体式格局
    var person = new Object();
    person.name = "Jack";
    person.age = 12;
    person.sayName = function(){
        alert(this.name);
    };
    
    //字面量体式格局
    var person = {
        name: "Jack",
        age: 14,
        job: "码农",
        sayName: function(){
            alert(this.name);
        }
    };

(2)工场情势

上述两个基础要领的瑕玷是:运用统一个接口建立许多对象,会发作大批的复制代码。针对这个瑕玷,看下面
道理是用函数来封装以特定接口建立对象的细节

    function createPerson(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 person1 = createPerson("Jack",15,"码农");
    var person2 = createPerson("rose",12,"顺序媛");

函数createPerson能吸收参数构建一个包含一切属性的对象,而且可以用很少的代码不停的建立多个对象,然则由于它被函数所封装,暴露的接口不能有用的辨认对象的范例(即你不知道是Object照样自定义的什么对象)。

(3)组织函数情势

    function Person(name,age,job){
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = function(){
            alert(this.name);
        };
    }
    var person1 = new Person("Jack",15,"码农");  //满满的java复古风
    var person2 = new Person("Rose",15,"顺序媛");
  1. 与工场情势比拟,组织函数情势用Person()函数替代了createPerson()函数,而且没有显现的建立对象,直接把属性和要领赋值给了this对象。

  2. 要建立Person的实例,必需运用new关键字。

  3. person1和person2都是Person的实例,这两个对象都有一个constructor(组织函数)属性,该属性指向Person。 person1.constructor == Person; //true

  4. person1即是Person的实例又是Object的实例,背面继续原型链会总结。

(3).1组织函数的运用

     //当作组织函数运用
     var person1 = new Person("Jack",15,"码农");
     person1.sayName();   //"Jack"
     
     //当作一般函数运用
     Person("Jack",16,"码农");     //注重:此处增加到了window
     window.sayName();  //"Jack"
     
     //在另一个对象的作用域中挪用
     var o = new Object();
     Person.call(o,"Jack",12,"码农");
     o.sayName();   //"Jack"
  1. 第一种当作组织函数运用就不多说了

  2. 当在全局作用域中挪用Person("Jack",16,"码农");时,this对象老是指向Global对象(浏览器中是window对象)。因而在实行完这句代码后,可以经由历程window对象来挪用sayName()要领,而且返回“Jack”。

  3. 末了也可以运用call()或许apply()在某个特别对象的作用域中挪用Person()函数

(3).2存在的题目

在(3)组织函数情势的代码中,对象的要领sayName的功用都一样,就是alert当前对象的name。当实例化Person以后,每一个实例(person1和person2)都有一个名为sayName的要领,然则两个要领不是统一个Function实例。不要忘了,js中函数是对象,所以每一个实例都包含一个差别的Function实例,但是建立两个功用完整一样的Function实例是完整没有必要的。因而可以把函数定义转移到组织函数外。
以下代码:


     function Person(name,age,job){
            this.name = name;
            this.age = age;
            this.job = job;
            this.sayName = sayName;
        }
    function sayName(){
            alert(this.name);
        }
        
    //实例化对象
    var person1 = new Person("Jack",15,"码农");  //满满的java复古风
    var person2 = new Person("Rose",15,"顺序媛");

然则如许依旧存在题目:

  1. 为了让Person的实例化对象同享在全局作用域中定义的统一个sayName()函数,我们把函数sayName()定义在全局作用域中,并经由历程指针sayName指向组织函数,所以在全局作用域中的sayName()只能被特定对象挪用,全局作用域名不符实,且污染全局变量。

  2. 而且如果对象须要许多种要领,那末就要定义许多全局函数,关于对象就没有封装性,而且污染全局。

2.原型

(1)原型情势建立对象

  1. js差别于强范例言语的java,java建立对象的历程是由类(笼统)到类的实例的历程,是一个从笼统到详细的历程。

  2. javascript则差别,其用原型建立对象是一个详细到详细的历程,即以一个现实的实例为底本(原型),去建立另一个实例对象。

所以用原型情势建立对象有两种体式格局:

1.Object.create()要领
Object.create:它吸收两个参数,第一个是用作新对象原型的对象(即原型),一个是为新对象定义分外属性的对象(可选,不经常使用)。

    var Person = {
        name:"Jack",
        job:"码农"
    };
    //通报一个参数
    var anotherPerson = Object.create(Person);
    anotherPerson.name     //"Jack"
    //通报两个参数
    var yetPerson = Object.create(Person,{name:{value:"Rose"}});
    yetPerson.name;        //Rose
    

2.组织函数要领建立对象

  1. 任何一个函数都有一个prototype属性(是一个指针),指向经由历程组织函数建立的实例对象原型对象,原型对象可以让一切对象实例同享它所包含的属性和要领。

  2. 因而没必要在组织函数中定义对象实例的信息,而是将这些属性和要领直接增加到原型对象中,从而被实例对象多继续(继续背面总结)

    //第一步:用组织函数建立一个空对象
    function Person(){
    }
    //第二步:给原型对象设置属性和要领
    Person.prototype.name = "Jack";
    Person.prototype.age = 20;
    Person.prototype.job = "码农";
    Person.prototype.sayName = function(){
        alert(this.name);
    };
    //第三步:实例化对象后,便可继续原型对象的要领和属性
    var person1 = new Person();
    person1.sayName();           //Jack
    
    var person2 = new Person();
    person2.sayName();           //Jack
    
    alert(person1.sayName == person2.sayName);   //true

person1和person2说接见的是统一组属性和统一个sayName()函数。

(2)明白原型对象

  1. 只需建立一个函数,就会为该函数建立一个prototype属性,这个属性指向函数的原型对象。

  2. 一切原型对象都邑自动获得一个constructor(组织函数)属性,这个属性包含一个指向prototype属性地点函数的指针。

  3. 当挪用组织函数建立一个新的实例对象后,该实例内部会有一个指针([prototype]/_proto_),指向组织函数的原型对象。以下图:
    《基本二:javascript面向对象、建立对象、原型和继续总结(上)》

上图中 :

  1. Person.prototype指向了原型对象,而Person.prototype.construstor又指回了Person。

  2. 注重视察原型对象,除了包含constructor属性以外,还包含厥后增加的别的属性,这就是为何每一个实例化后的对象,虽然都不包含属性和要领,然则都包含一个内部属性指向了Person.prototype,能获得原型中的属性和要领。

(3)推断一个实例对象的原型

这个要领叫:Object.getPrototypeOf(),以下例子:

alert(Object.getPrototypeOf(person1) == Person.prototype); //true
alert(Object.getPrototypeOf(person1).name); //”Jack”

  1. 这个要领可以很轻易的获得一个对象的原型

  2. 还可以应用这个要领获得原型对象中的name属性的值。

(3)搜刮属性的历程

  1. 当我们在建立实例化的对象以后,挪用这个实例化的对象的属性时,会前后实行两次搜刮。

  2. 第一次搜刮实例person1有name属性吗?没有举行第二次搜刮

  3. 第二次搜刮person1的原型有name属性吗?有就返回。

因而举行一次思索,如果对实例举行属性重写和要领掩盖以后,接见实例对象的属性和要领会显现哪一个?实例对象的照样对象原型的?

    function Person(){
    }
    
    Person.prototype.name = "Jack";
    Person.prototype.age = 20;
    Person.prototype.job = "码农";
    Person.prototype.sayName = function(){
        alert(this.name);
    };
    
    var person1 = new Person();
    var person2 = new Person();
    
    person1.name = "Rose";
    alert(person1.name);        //Rose
    alert(person2.name);       //Jack
    
  1. 当为对象实例增加一个属性时,这个属性就会屏障原型对象中保留的同名属性。

  2. 然则这个属性只会阻挠我们接见原型中的谁人属性,而不会修正谁人属性
    3.运用delete操作符可以删除实例属性,从而从新接见原型中的属性。

    function Person(){
    }

    Person.prototype.name = "Jack";
    Person.prototype.age = 20;
    Person.prototype.job = "码农";
    Person.prototype.sayName = function(){
        alert(this.name);
    };

    var person1 = new Person();
    var person2 = new Person();
    
    person1.name = "Rose";
    alert(person1.name);        //Rose  --来自实例
    alert(person2.name);       //Jack  --来自原型
    
    delete person1.name;
    alert(person1.name);      //Jack  --来自原型
    

(4)推断接见的究竟是对象照样原型属性

  1. hasOwnProperty()可以检测一个属性是存在于实例中,照样原型中,只要在给定属性存在于对象实例中,才会返回true。

    person1.hasOwnProperty("name");    //假定name存在于原型,返回false
    
  2. in操作符会在经由历程对象可以接见给定属性时返回true,不管该属性是存在于实例中照样原型中

    "name" in person1   //true
    

所以经由历程这两个可以封装一个hasPrototypeProperty()函数肯定属性是否是原型中的属性。

function hasPrototypeProperty(object,name){
    return !object.hasOwnProperty(name) && (name in object); 
}

(5)更简朴的原型语法

前面每次增加一个属性和要领都要写一次Person.prototype,为了轻便可以直接如许

    function Person(){
    }
    Person.prototype = {
        name:"Jack",
        age:20,
        job:"码农",
        sayName:function(){
            alert("this.name");
        }
    };
    
  1. 上述代码直接将Person.prototype设置为即是一个以对象字面量情势建立的新对象

  2. 上述这么做时:constructor属性就不再指向Person了。

  3. 本质上完整重写了默许的prototype对象,因而constructor属性也就变成了新对象的constructor属性(指向Object组织函数)。

  4. 因而如果constructor值很主要,可以在Person.prototype中设置回恰当的值:
    如上例中可以增加:constructor:Person,

(6)原型的动态性

我们对原型对象所做的任何修正都邑马上从实例上反应出来-纵然先建立实例对象后修正原型也云云

    var friend = new Person();
    Person.prototype.sayHi = function(){
        alert("Hi");    
    };
    friend.sayHi();      //"Hi"

只管可以随时为原型增加属性和要领,而且修正能马上在实例对象中体现出来,然则如果重写全部原型对象,就不一样了。看下面例子:

    function Person(){
    }
    var friend =  new Person();
    Person.prototype = {
        constructor:Person,
        name:"Jack",
        age:20,
        sayName:function(){
            alert(this.name);
        }
    };
    friend.sayName();      //error
  1. 上述代码先建立了一个Person实例,然后又重写了其原型对象,在挪用friend.sayName()时发作毛病。

  2. 由于friend指向的原型中不包含以该名字定名的属性。关联以下图:
    《基本二:javascript面向对象、建立对象、原型和继续总结(上)》

(7)原型对象的题目

  1. 省略了为组织函数初始化参数这一环节,结果是一切实例都获得雷同的属性,但题目不大,可认为实例对象重写属性来处理。
    2.然则,关于包含援用范例值的属性来讲,题目就比较突出了,由于援用范例中,属性名只是一个指针,在实例中重写该属性并没有作用。指针一直指向原本的。

以下例子:

function Person(){}

    Person.prototype = {
        constructor:Person,
        name:"Jack",
        job:"码农",
        friends:["路人甲","路人乙","路人丙"],
    
    };
    var person1 = new Person();
    var person2 = new Person();
    
    person1.friends.push("路人丁");
    alert(person1.friends);     //["路人甲","路人乙","路人丙","路人丁"]
    alert(person2.friends);    //["路人甲","路人乙","路人丙","路人丁"]
    alert(person1.friends === person2.friends);     //true

上面这个,如果每一个实例对象的援用值属性不一样,则没法修正。

3.组合运用组织函数和原型情势

  1. 组织函数情势用于定义实例属性

  2. 原型情势用于定义要领和同享的属性

以下代码:

    function Person(name,age,job){
        this.name = name;
        this.job = job;
        this.age = age;
        this.friends = ["路人甲","路人乙"];
    }
    
    Person.prototype = {
        constructor:Person,
        sayName: function(){
            alert(this.name);
        }
    }
    var person1 = new Person("Jack", 20, "码农");
    var person2 = new Person("Rose", 20, "顺序媛");
    
    person1.friends.push("路人丁");
    alert(person1.friends);                  //["路人甲","路人乙","路人丁"]
    alert(person2.friends);                  //["路人甲","路人乙"]
    alert(person1.friends === person2.friends);     //false
    alert(person1.sayName === person2.sayName);    //true

4.寄生组织函数情势

该情势基础思想是建立一个函数,该函数作用仅仅是封装建立对象的代码,然后返回新建立的对象。

    function Person(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 friend = new Person("Jack", 16, "码农");
    friend.sayName();          //Jack
  1. 组织函数在不返回值的情况下,默许会返回新对象实例。

  2. 经由历程在组织函数末端增加一个return语句,可以重写挪用组织函数时返回的值。

这个要领的用途是:可以建立一个分外要领的特别的数组(由于原生对象Array的组织函数不能直接修正)

       function SpecialArray(){
            //建立数组
            var values = new Array();
            //增加值
            values.push.apply(values,arguments);
            
            //增加要领
            values.toPipedString = function(){
                return this.join("|");
            };
            //返回数组
            return values;
        }
        var colors = new SpecialArray("black","red","blue");    
        alert(colors.toPipedString());
    

原本想接着写继续的,发明实在太多了,分红两篇吧。

    原文作者:yangdepp
    原文地址: https://segmentfault.com/a/1190000005925308
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞