zoukankan      html  css  js  c++  java
  • js中面向对象(创建对象的几种方式)

    1、面向对象编程(OOP)的特点

      抽象:抓住核心问题

      封装:只能通过对象来访问方法

      继承:从已有的对象下继承出新的对象

      多态:多对象的不同形态

     注:本文引用于 http://www.cnblogs.com/yuxingyoucan/p/5797142.html


    一、创建对象的几种方式

    javascript 创建对象简单的来说,无非就是使用内置对象或各种自定义对象,当然还可以使用JSON,但写法有很多,也能混合使用。

    1、工厂方式创建对象:面向对象中的封装函数(内置对象)

    function createPerson(name){
       //1、原料
        var obj=new Object();
       //2、加工
        obj.name=name;
        obj.showName=function(){
           alert(this.name);
        }     
        //3、出场
         return obj; 
    } 
    var p1=createPerson('小米');
    p1.showName();

    与系统对象的区别:

        var arr=new Array();//生成一个系统数组对象

        1、系统对象是直接用 new 在外面生成,而工厂定义的是在函数内部生成

        2、工厂定义的函数名称第一个是小写开头,而系统定义的是大写开头

    工厂模式的优缺点:虽然解决了创建相似对象的问题,但是却没有解决对象识别问题(即怎样知道一个对象的类型)。

    2、构造函数创建对象

      当new去调用一个函数,这个时候函数中的this就是创建出来的对象,而且函数的返回值就是this(隐式返回)

      new后面的函数叫做构造函数

      <1>有参数的构造函数

    function CreatePerson(name){
      this.name=name;
      this.showName=function(){
        alert(this.name);
      }
    }
        var p1=new CreatePerson('小米');

      <2>无参数的构造函数

      function CreatePerson(){}
        var p1=new CreatePerson();
        p1.name="小米";
        p1.showName=function(){
         alert(p1.name);
        }
        p1.showName();

    构造函数模式的优缺点:

      1、优点:创建自定义函数意味着将来可以将它的实例标识为一种特定的类型,这是构造函数胜过工厂模式的地方

      2、缺点:每个方法都要在每个实例上重新创建一遍

    3、对象字面量方式创建对象

    person={
      name:"小米",
      age:23
    };

    4、用原型方式 

      1、原型对象:只要创建了一个新函数,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针

      2、可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系

    function Person(){}
    Person.prototype.name="小米";
    Person.prototype.showName=function(){
    alert(this.name);
    }
    var p1=new Person();
    p1.showName();

    原型模式的优缺点:

      1、优点:可以让所有的对象实例共享它所包含的属性和方法

      2、缺点:原型中是所有属性都是共享的,但是实例一般都是要有自己的单独属性的。所以一般很少单独使用原型模式。

    5.混合模型

      构造函数模式定义实例属性,而原型模式用于定义方法和共享的属性

    function CreatePerson(name){
      this.name=name;
    }
      Create.prototype.showName=function(){
        alert(this.name);
      }
        var p1=new CreatePerson('小米');
        p1.showName();
       var p2=new CreatePerson('小米');
        p2.showName();
      alert(p1.showName==p2.showName);//true;原因:都是在原型下面,在内存中只存在一份,地址相同

      总结:

      function 构造函数(){

        this.属性;

      }

      构造函数.原型.方法=function(){};

      var 对象1=new 构造函数();

      对象1.方法();


    原型:去改写对象下面公用的的方法或属性,让公用的方法或属性在内存中存在一份(提高性能)

    原型:prototype:要写在构造函数的下面

    var  arr=[];
    arr.number=10;
    Array.prototype.number=20;
    alert(arr.number);//10,
    //原因:普通定义的要比原型定义的权重大,先会找自身的,自身没有的话再沿着原型链找原型上是否有

    属性是否要放在原型下面,就要看该属性是否是可变的,如果不是可变的,就可以放在原型下面,用来公用属性,可变的话放在构造函数下面。


    this的指向问题:在事件或者定时器下比较容易出问题


     

     二、包装对象

    1、我们把系统自带的对象,叫做系统对象。例如:Array,Date

    2、包装对象:基本类型都有自己对应的包装对象:String,Number,Boolean

      var str='hello';//基本类型:字符串类型

      str.charAt(0);//基本类型会找到对应的包装对象类型,然后包装对象把所有的属性和方法给了基本类型,然后包装对象消失。

      str.number=10;//在包装对象下创一个对象,将属性创建在对象下面,然后包装对象就消失了,

      alert(str.number);//会弹出undefined;原因:会在包装对象下重新创建一个对象


    三、原型链

      原型链:实例对象与原型之间的连接,叫做原型链  

      _proto_(隐式连接)

       Object对象类型是原型链的最外层

      

      实例对象->先查找自己本身下面的属性和方法->自身没找到会沿着原型链找到该对象的原型,再查看原型上是否有要查找的属性或方法->依次继续查找如果找到的话则返回,否则找到最顶层Object上还没有就真没有了


    四、面向对象中的属性和方法 

     1、hasOwnProperty():看是否为对象自身下面的属性和方法

      只有对象自己定义的属性和方法则返回true,如果在prototype下定义发属性和方法为公用的,所以返回为false;

    2、constructor:查看对象的构造函数

      (可以用来检测函数类型例如检测是否是数组)

      每个原型函数都会自动添加constructor属性(只会生成这一个属性)

      for in的时候有些属性是找不到的(系统自带的属性是for in找不到的,自己定义的可以找到)

      避免修改constructor属性

    function Aaa(){}
    //Aaa.prototype.name='小米';
    //Aaa.prototype.age=6;
    //alert(a1.constructor);//Aaa 原因:只是给原型添加了属性,并不是重新赋值了,自动添加的constructor属性还在。
    Aaa.prototype={
    //  constructor:'Aaa',//需要手动修正指向问题
      name:'小米',
      age:6
    }
    var a1=new Aaa();
    alert(a1.constructor);//Object 原因:将原型的prototype重新赋值了,但里面没有constructor

     注意:以这种方式重设constructor属性会使它的[Enumerable]特性被设置为true,默认情况下,原生的constructor属性是不可枚举的。可以通过Object.defineProperty()来修改。

    3、instanceof:运算符

      对象与构造函数在原型链上是否有关系,也可以用作类型判断但不是最好的方案,最好的方案是用toString 方法来判断。

    4、toString():object上的方法,把对象转化为字符串

    var arr=[];
    alert(arr.toString==Object.prototype.toString);//false
    //原因:系统对象下面都是自带的(例如数组的toString在Array.prototype下),自己写的对象都是通过原型链找到object下面的toString
    function Aaa(){}
    var a1=new Aaa();
    alert(a1.toString==Object.prototype.toString);//true

    1>利用toString 进制转化

     Number.toString(进制);

    var num=255;
    alert(num.toString(16));//ff---转化为16进制,默认不写转化为十进制

    2>利用toString做类型判断:

      //跨页面的情况下上面两种情况会失效
    
     var oF=document.createElement('iframe');
    
      document.body.appendChild('oF');
    
      var ifArray=windows.frames[0].Array;//iframe下的Array数组
    
      var arr=new ifArray();
    
      alert(arr.constructor==Array);//false
    
      alert(arr instanceof Array);//false
    
      alert(Object.prototype.toString.call(arr)=='[object Array]');//true
    var arr=[];
    alert(Object.prototype.toString.call(arr));//[Object Array] 
    var arr={};
    alert(Object.prototype.toString.call(arr));//[Object Object] 
    var arr=new Date;
    alert(Object.prototype.toString.call(arr));//[Object Date] 
    var arr=new RegExp;
    alert(Object.prototype.toString.call(arr));//[Object RegExp]  
    var arr=null;
    alert(Object.prototype.toString.call(arr));//[Object Null] 


    五 、继承

    1、继承方式:

      1、拷贝继承:通用型  有new无new都可以用

      2、类式继承:new构造函数---利用构造函数(类)继承的方式

      3、原型继承:无new的对象---借助原型来实现对象继承对象

      属性继承:调用父类的构造函数call

      方法继承:用for in的形式 拷贝继承(jq也用拷贝继承)

            var a = {
                name: '小米'
            };
            //拷贝继承
            function extend(obj1, obj2) {
                for (var attr in obj2) {
                    obj1[attr] = obj2[attr];
                }
            }
            //原型继承
                var b=cloneObj(a);
                b.name='小乔';
                alert(a.name);
                alert(b.name);
                function cloneObj(obj) {
                    var F=function () {};
                    F.prototype=obj;
                    return new F();
                }
            //类式继承
            function A() {//父类
                this.name='小米';
            }
            A.prototype.showName=function () {
                alert(this.name);
            }
            function B() {//子类
                A.call(this);//属性和方法分开继承
            }
        //B.prototype=new A();//一句话实现继承,但会有很多问题,比如指向问题,属性会互相影响
        //类式继承改进:至少由以下四句实现方法的继承,属性需要分开继承
    var F=function () {}; F.prototype=A.prototype; B.prototype=new F(); B.prototype.constructor=A;//修正指向问题 var b1=new B(); b1.name='笑笑'; b1.showName();
  • 相关阅读:
    HTTP报文详解
    常用的HTTP协议
    URL详解
    一起切磋
    emacs使用指南
    SSH自动部署
    linux上应用随机启动
    让Maven正确处理javac警告
    最近的学习
    Java application 性能分析分享
  • 原文地址:https://www.cnblogs.com/newze/p/7536385.html
Copyright © 2011-2022 走看看