JS-面向对象?面向过程?创建对象?

112 阅读4分钟

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

第一部分

面向对象?

总听说面向对象编程,那面向对象到底是什么? 面向对象就是将构成问题的事物分解成多个对象,然后由对象之间分工和合作。

面向过程

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的一次调用就可以了

区别

  1. 面向过程性能比面向对象高,适合跟硬件联系很紧密的东西。例如单片机。
  2. 没有面向对象易维护、易复用、易扩展。
  3. 面向对象编程具有灵活、代码可复用、容易维护和开发的优点、更适合多人合作的大型软件项目。
  4. 可以设计出低耦合的系统,使系统更加灵活。

面向对象的特征

  1. 封装性
  2. 继承性
  3. 多态性

第二部分

创建对象的多种方式

js就是一门面向对象的编程语言

  1. 字面量创建对象
var person ={
        name:'张三',
        age:20,
        like:function () {
            console.log('他喜欢打篮球')
        }
    }
    console.log(person.name);
  1. new Object()
var person = new Object();
    person.name = '张三';
    person.age = 20;
    person.like = function () {
        console.log('他喜欢打篮球');
    }
  1. 自定义函数
 function Person(){
        this.name = '张三';
        this.age = 20;
        this.like= function () {
            console.log('他喜欢打篮球');
        }
    }
  1. 工厂模式创建对象
function Person(name,age){
        var obj = new Object();
        obj.name = name;
        obj.age = age;
        obj.like= function () {
            console.log('他喜欢打篮球');
        }
        return obj;
    }

    console.log(Person('张三', 20));
  1. 构造函数模式创建
 class Star {
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }
        sing(song) {
            console.log('我唱歌');
            console.log(this.name + song);
        }
    }

    var ldh = new Star("刘德华", 20);
    console.log(ldh);
    ldh.sing("冰雨");

构造函数和普通函数的区别

  1. 它们都是函数,构造函数也可以当成普通函数调用,做普通函数调用的时候,this指向window对象。
  2. 用new的方式去使用一个函数,那么它就是一个构造函数了。
  3. 为了区别,如果一个函数想作为构造函数,我们经常将首字母大写来表示这是一个构造函数。
  //当作普通函数调用
  function Person1(){
      this.name = "张三"; // 把name属性添加到了window对象上面
      alert(this === window);  //作为普通函数调用,则是true
  }
  Person();  // 把构造函数当做普通方法调用。这个时候内部的this指向了weindow
  alert(window.name);  //张三

  function Person2(){
      this.name = "Mark";
      alert(this instanceof window);  // false
      alert(this instanceof Human);  //true
  }
  var h = new Human();  //当做构造函数来调用,创建一个对象
  alert(h.name);//张三

继承

  1. 原型链继承 核心:将父类的实例作为子类的原型 缺点:父类新增的原型方法/原型属性,子类都能获取的到。但是父类一旦改变,子类也会跟着改变。
 function Person() {}

    Person.prototype.name = "john";
    Person.prototype.age = 20;
    Person.prototype.sayHello = function () {
        console.log(this.name);  //john
    }

    function Male() {}

    /*  Male.prototype = Person.prototype; //Male原型对象就具有了Person原型对象的属性和方法
     //但是父类原型和子类原型是同一个,子类的修改会影响到父类
     Male.prototype.sexy = "male"; */

    Male.prototype = new Person();//这一步实现了Male对Person的继承  成为原型继承

    Male.prototype.sexy = "male";

    var male = new Male();
    /*
   male这个实例里面有没有__proto__
   male.__proto__== Male.prototype
   Male.prototype.__proto__ == Person.prototype
   //这时就形成了原型链
    */
    male.sayHello();
    //male访问sayHello,访问顺序:实例属性->Male.prototype->Person.prototype->……->Object.prototype->undefined
    console.log(male.sexy);  //male
    var person = new Person();
    console.log(person.sexy);  //undefined
  1. 构造函数继承 核心:将父类的实例复制给子类(实际上没有用到原型链) 缺点:只能继承父类实例的方法和属性,不能继承原型链上的属性和方法,无法实现函数复用
    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.sayHello = function () {
            console.log(this.name);
        }
    }

    function Male(name, age) {
        Person.call(this, name, age);//利用call方法改变this指向
        
        this.sexy = "male";

}

var male = new Male("john", 20);
console.log(male);  //返回是一个对象
  1. 组合继承 所有的实例都能拥有自己的属性,并且可以使用相同的方法 核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后再通过将父类实例作为子类原型,实现函数复用
function Person  (name) {
             this.name = name;
             this.friends = ['andy','edgar'];
         };

         Person.prototype.getName = function () {
             return this.name;
         };

        function Parent (age) {
            Person.call(this,'riemann');  //这一步很关键
            this.age = age;
        };

        Parent.prototype = new Person('riemann');  //这一步也很关键
        var result = new Parent(24);
        console.log(result.name);    //riemann
        result.friends.push("小智");  //
        console.log(result.friends);  //['andy','edgar','max']
        console.log(result.getName());  //riemann
        console.log(result.age);    //26

        var result1 = new Parent(26);   //通过借用构造函数都有自己的属性,通过原型享用公共的方法
        console.log(result1.name);  //riemann
        console.log(result1.friends);  //['andy','edgar']

  1. 寄生方式 核心:通过寄生方式,砍掉父类实例
function Person(name) {
            this.name = name;
            this.friends = ['andy','edgar'];
        }

        Person.prototype.getName = function () {
            return this.name;
        };

        function Parent(age) {
            Person.call(this,"riemann");
            this.age = age;
        }

        (function () {
            var Super = function () {};     // 创建一个没有实例方法的类
            Super.prototype = Person.prototype;
            Parent.prototype = new Super();     //将实例作为子类的原型
        })();

        var result = new Parent(26);
        console.log(result.name);
        console.log(result.friends);
        console.log(result.getName());
        console.log(result.age);