js面向对象编程

①:字面量方式创建。

其实就是json形式的对象,适用于创建单个对象。

例:var obj = {

  name:"小明",

  age:18,

  run: function(){

    console.log(this.name)

}

}

②:实例创建。

实例创建对象,使用new Object()创建一个实例对象,然后再给这个对象添加属性和方法。

例:var box = new Object();      //创建一个Object对象

  box.name = "小明";            //创建一个name属性并赋值

  box.age= 18;                 //创建一个age属性并赋值

  box.run = function(){           //创建一个run ()方法并返回值

  console.log(this);

  return this.name + '--' + this.age

}

缺点:想创建一个类似的对象,就会产生大量的代码。

例:var box2 = box                   //得到box的引用

  box2.name = "小明";          //直接改变了name属性

  console.log(box2.run());

  console.log(box.run());      //box的name也改变了

  var box2 = new Object();   //创建一个Object对象

  box2.name = "小红";           

  box2.age= 20;               

  box.run = function(){         

  console.log(this);

  return this.name + '--' + this.age

  }

  console.log(box2.run())     //这样才避免和box混淆,从而保持独立

③:工厂模式创建对象

解决实例化对象产生大量重复代码的问题;工厂模式创建对象,其实就是函数封装

例:function createObject(name,age){    //集中实例化函数

    var obj = new Object();         //原材料

    obj.name = name;           //加工

    obj.age = age;

    obj.run = function(){

      return this.name + '--' + this.age;

  };

  return obj;              //出厂

  }

  var box1 = createObject('Lee' , 100);  //第一个实例

  var box2 = createObject('Jack , 200);    //第二个实例

  console.log(box1.run())

  console.log(box2.run())          //保持独立

 工厂模式解决了重复实例化的问题,但是还有一个问题,那就是识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。

例:console.log(typeod box1);    //Object判断对象类型。

  //instanceof运算符,一个对象是否为指定的构造函数的实例,返回布尔值

  console.log(box1 instanceof Object);    //true box1是Object1的实例

  console.log(box1 instanceof createObject);    //false

但是我们box1应该是createObject创建出来的。

④:构造函数创建对象
构造函数创建对象,是使用最多的创建对象的方式,也是将所有的操作都封装在函数中,但是跟工厂模式的创建方式有很大的不同,而且可以明确区分对象的种类。
构造函数的特点:
∝:构造函数名首字母大写(为了区分普通函数,不是必须,是约定)
∝:构造函数方法没有显示的创建对象(new Object())
∝:直接将属性和方法赋值给 this 对象

∝:没有 return 语句,不需要返回对象

∝:通过构造函数创建对象,必须使用 new 运算符(直接调用跟普通函数一样)

例:function Student(namne){  //首字母大写

  this.name = name;    //不用new Object,直接通过this添加属性和方法

  this.eat = function(){

    console.log("吃饭")  

}

}

//实例对象

var s1 = new Student('MM');  //必须使用new

var s2 = new Student('GG);

console.log(s1 instanceof Student);  //true , s1是Student创建出来的

要创建 Student 的新实例,必须使用 new 操作符。以这种方式调用构造函数实际上会经历以下4个步骤:
(1)创建一个新对象;

(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);

(3)执行构造函数中的代码(为这个新对象添加属性);

(4)返回新对象。

缺点:console.log(s1.eat == s2.eat);   //false,判断内存地址

同一个方法,因对象不同,所存储的位置也不同,如果有多个对象,则要分配存储多次,占用不必要内存。

⑤:原型创建对象

1)原型prototype

每个对象都会有自己的原型对象,是这类对象共有的方法和属性的集合。如Array 对象的原型对象中定义了很多的方法和属性,所有的数组都能使用这些方法和属性。

例:var arr = [1]

       console.log(arr)
       效果如下
  
  __proto__是实例对象的一个属性,指向原型对象,可以说是一个东西。原型对象需要用类名调用,如 Array.prototype
  console.log(arr.__proto__ == Array.prototype);  //true
当我们修改了原型对象的方法以后,所以这类对象在调用这个方法时都是修改之后的,因为原型对象中的内容是共享的。
 
例:修改string对象的原型方法
  String.prototype.charAt = function(index){
          console.log("原型" + index)
      }
     var str = 'web';
     str.charAt(1);  //原型1  不在是原来的获取操作了
2)constructor
  我们可以看到,原型下面有个constructor的属性,他又指向构造函数,因此我们也可以利用它来做类型判断。
      var arr = []
      console.log(arr.constructor);//Array
      console.log(arr.constructor === Array);     //true 证明arr是数组
  对象的constructor 属性最初是用来标识对象的。所以,这里我们用来做类型的判断
 
3)原型创建对象 
function Student(){};      //定义一个构造函数
    //使用原型添加属性和方法
    Student.prototype.name = "小敏";
    Student.prototype.run = function(){
        console.log(this.name);
    }
    // prototype:通过原型添加的方法和属性都是共享的,每一个实例对象都能够使用
    var s1 = new Student()
    var s2  =new Student()
    console.log(s1.name,s2.name);//小敏 小敏
    console.log(s1.run == s2.run) //true 原型方法同一个

通过原型创建的对象,对象的方法和属性是共享的,只会存储一次,因此能够解决内存浪费的问题。但是会出现一个新的问题,原型创建的对象的属性不能传参,都是固定的值。这样的话就不能创建不同的对象了。
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针

⑥:混合模式创建(构造 + 原型)

用构造函数创建对象,会有重复定义方法的问题,用原型创建属性不能传参,所以这里结合一下,用构造函数 + 原型 混合使用的方法创建对象,构造函数中放属性和一直改变的方法,原型中存储共享的属性和方法。

例:

 // 构造函数中写可变的属性和变量
    function Student(name){
        this.name = name
    }
    // 原型上写共有的属性和方法
    Student.prototype.eat = function(){
        console.log('吃饭')
    }
    // 实例对象
    var s1 = new Student('小敏');
    var s2 = new Student('如花')
    console.log(s1.name,s2.name);//小敏,如花
    console.log(s1.eat == s2.eat);//true

 上面代码中,通过混合创建的方式,在构造函数中放一些可变的属性和方法,通过参数传入,在原型对象中,
 添加共享的不变的属性和方法,节约内存。但是也会有人说,创建对象分成了两部分,破坏了对象的封装性的特点

⑦:动态混合模式。
 一般创建对象用混合模式就够了,但是严格来说这种方式破坏了封装性,所以还可以使用动态混合模式创建,将原型方法也写到构造函数当中

例:

 function Student(name) {
        this.name = name
    }
    //判断方法是否存在,不存在则在原型上添加
    if (typeof (this.eat) !== "function") {
        Student.prototype.eat = function () {
            console.log('吃饭')
        }
    }
    // 实例对象
    var s1 = new Student('小敏');
    var s2 = new Student('如花')
    console.log(s1.name, s2.name);//小敏,如花
    console.log(s1.eat == s2.eat);//true
 
posted @ 2021-07-02 01:36  奇函数  阅读(72)  评论(0)    收藏  举报