JavaScript全解学习要点-面向对象编程

180 阅读4分钟

面向对象编程

实例对象与new关键字

  • js的面向对象通过constructor和原型prototype实现的
  • 构造函数
    • 内部使用this关键字,代表创建实例
    • 生成对象时必须使用new关键字
  • new原理步骤
    1. 创建一个空对象,作为返回的对象
    2. 将空对象原型指向构造函数的prototype属性
    3. 将这个空对象赋值给函数内部的this
    4. 执行构造函数内部代码
  • 构造函数内部return只能返回对象,如果写的是return 5,则不论是什么基本类型,都会返回this指向的对象
  • 构造函数return一个对象,则返回这个对象,不返回this指向的对象(强调上一条)
  • new.target这个属性只有用new关键字时才会有值,可以以此来判断是否使用了new
  • 防止忘记写new去发生错误,可以使用new.target简化省去new
function Person(name,age){
    if(!new.target){
        return new Person(name,age)
    }
    this._name = name
    this._age = age

}

p1 = Person('forkeep',22)
p2 = new Person('hz',20)

console.log(p1._name)//forkeep
console.log(p2._name)//hz
  • Object.create创建实例对象
var person1 = {
    name:'lz',
    age:22,
    hello:function(){
        console.log('Hi! '+this.name)
    }
}

var person2 = Object.create(person1)

console.log(person2.age)//22
person2.hello()//Hi! lz

this关键字

  • 它总返回一个对象

  • this就是属性、方法当前所在的对象

  • 尤其注意函数的定义时刻和触发时刻是截然不同的

  • this的指向会变

  • 实质:对象名存着对象所在内存的地址,函数名存着函数所在内存的地址

  • this使用场景:全局window,构造函数,对象的方法

  • 一定要注意

    • 避免多层this

    • 避免数组处理中使用this

    • 避免回调函数中使用this

  • 绑定this

    • Function.prototype.call(this[,arg1.,arg2..])括号里的第一个参数this
    • Function.prototype.apply(this[,[arg1,arg2...]])括号里的第一个参数是this
    • Function.prototype.bing(this,[,arg1,arg2...])返回一个函数,绑定this不变,也可以绑定参数不变,按顺序绑定

对象继承

  • 通过原型链实现继承功能

  • 不使用继承缺点:相同属性,函数重复声明定义,占用内存空间

  • 原型链继承思想:相同属性、函数定义在构造函数的原型上

  • 实例中有相同的属性、方法,则不去寻找原型中的该属性、方法

  • 原型链

  • 构造函数PersonPerson.prototype.constructor === Person //true

  • Person实例pp.constructor === P.prototype.constructor

  • constructor属性可以知道一个实例是哪个构造函数创建的

  • constructor可以通过一个实例创建另一个实例,不需要知道是哪个构造函数(原因见上一条)

  • 修改原型时,注意不要把constructor无意之间修改了

  • 最好不要直接给Person.prototype赋值,而是使用Person.prototype.method = function(){}

  • instanceof对象是否是一个构造函数的实例

    v instanceof Vehicle
    // 等同于
    Vehicle.prototype.isPrototypeOf(v)
    
  • instanceof检查整个原型链

  • 构造函数的继承

    1. 在子类构造函数中调用父类构造函数

    2. 子类原型指向父类原型(采用Object.create()

      //第一步
      function Sub(value) {
        Super.call(this);
        this.prop = value;
      }
      
      //第二步
      Sub.prototype = Object.create(Super.prototype);
      Sub.prototype.constructor = Sub;
      Sub.prototype.method = '...';
      
  • 多重继承(Object.assign()

    function M1() {
      this.hello = 'hello';
    }
    
    function M2() {
      this.world = 'world';
    }
    
    function S() {
      M1.call(this);
      M2.call(this);
    }
    
    // 继承 M1
    S.prototype = Object.create(M1.prototype);
    // 继承链上加入 M2
    Object.assign(S.prototype, M2.prototype);
    
    // 指定构造函数
    S.prototype.constructor = S;
    
    var s = new S();
    s.hello // 'hello'
    s.world // 'world'
    
  • 模块化方法(封装到一个对象中new Object({})

    var module1 = new Object({
     _count : 0,
     m1 : function (){
      //...
     },
     m2 : function (){
       //...
     }
    });
    
    • 缺点:_count属性暴露在外边可以被随意修改

    • 封装私有变量

      • 构造函数写法(利用闭包)
        • 缺点:buffer变量一直占用内存
      function StringBuilder() {
        var buffer = [];
      
        this.add = function (str) {
           buffer.push(str);
        };
      
        this.toString = function () {
          return buffer.join('');
        };
      
      }
      
      • 立即执行函数写法 IIFE(实际用到的写法)

        var module1 = (function () {
         var _count = 0;
         var m1 = function () {
           //...
         };
         var m2 = function () {
          //...
         };
         return {
          m1 : m1,
          m2 : m2
         };
        })();
        
      • 优化的立即执行函数写法

        (function($, window, document) {
        
          function go(num) {
          }
        
          function handleEvents() {
          }
        
          function initialize() {
          }
        
          function dieCarouselDie() {
          }
        
          //attach to the global scope
          window.finalCarousel = {
            init : initialize,
            destroy : dieCarouselDie
          }
        
        })( jQuery, window, document );
        

        说明:

        1. finalCarousel对象对外暴露initdetory方法,内部方法外部无法调用。
        2. 其他方法外部无法访问
        3. 后边括号传的参数,前边括号声明形参