js面向对象编程

184 阅读4分钟

面向对象就是将需求抽象出来成一个对象,针对对象分析其特性(属性)和动作(方法)。这个对象称之为类,面向对象最大的特点就是封装,将所需要的功能放在一个对象中。

1、封装一个类

在函数(类)内部通过 this 或者通过类的原型 prototype 来添加属性和方法

function People(name, sex) {
 this.name = name
 this.sex = sex
 this.show = function(){
   console.log('my name is' + this.name)
 }
}
People.prototype.say = function() {
 return 'Hello World'
}

此时已经将需要用的属性和方法都封装在了抽象的类 People 中。使用时只需通过关键字 new 来进行实例话。

var people = new People('小平不小', '男')
console.log(people)
console.log(people.name) //小平不小
console.log(people.say()) //Hello World

通过 this 添加的方法和属性是在当前对象上添加的,而通过prototype添加的方法和属性在当前对象的 proto 上。而js是基于原型 prototype 的语言,因此它会通过 prototype 向上一级一级的查找。如下图:

2、属性和方法的封装

js中没有显示的声明私有属性、私有方法。但可以通过js的灵活性来创建类的私有变量和私有方法。

var People = function(name, sex, age) {
  //静态私有属性和私有方法
  var like = 'gril'
  function checkName() {}
  // 特权方法
  this.getName = function() {
    return this.name
  }
  this.getSex = function() {
    return this.sex
  }
  this.setName = function(name) {
    this.name = name
  }
  this.setSex = function(sex) {
    this.sex = sex
  }
  this.getLike = function() {
    return like
  }
  //对象的公有属性
  this.age = age
  this.say = function() {
    return 'Hello World'
  }
  //构造器
  this.setName(name)
  this.setSex(sex)
}
//类的静态共有属性和静态共有函数 
People.country = 'China'
People.introduce = function() {
  return 'I come from China'
}
//类的共有属性和共有方法
People.prototype = {
  isAnimal: true,
  display: function() {
    return 'my name is ' + this.name + ',' + 'I am a ' + this.sex
  }
}
var people = new People('小平不小', 'boy', 18)
console.log(people)
console.log(people.getLike()) //gril
console.log(people.display()) //my name is 小平不小,I am a boy
console.log(people.country)   //undefined
console.log(People.country)   //China   只能通过类来访问

在类的内部,通过 this 创建的对象和属性,在类的实例话创建对象时,每个对象都会拥有一份,并且在外部可以访问的到,因此 this 创建的属性可以看作时对象的共有属性和共有方法, this 创建的方法不仅可以访问对象的共有属性和共有方法,而且还可以访问类创建时的私有属性和私有方法,由于权利比较大,因此被称为特权方法。同时在对象创建时可以使用特权方法来初始化对象的属性,因此在创建对象时调用的特权方法还可以看成是类的构造器。通过类的 prototype 创建的属性和方法并不会在每一个对象上创建,但可以通过原型链一级一级的找到,因此被称为类的共有属性和共有方法。

3、利用闭包来实现一个完整的类

var People = function() {
  var like = 'gril'
  function checkName() {}
  function _people(name, sex, age) {
    // 静态私有属性和私有方法
    var like = 'gril'
    function checkName() {}
    // 特权方法
    this.getName = function() {
      return this.name
    }
    this.getSex = function() {
      return this.sex
    }
    this.setName = function(name) {
      this.name = name
    }
    this.setSex = function(sex) {
      this.sex = sex
    }
    this.getLike = function() {
      return like
    }
    // 对象的公有属性和共有方法
    this.age = age
    this.say = function() {
      return 'Hello World'
    }
    //构造器
    this.setName(name)
    this.setSex(sex)
  }
  //类的静态共有属性和静态共有函数 
  _people.country = 'China'
  _people.introduce = function() {
    return 'I come from China'
  }
  //构建原型
  _people.prototype = {
    //公有属性和共有方法
    isAnimal: true,
    display: function() {
      return 'my name is ' + this.name + ',' + 'I am a ' + this.sex
    }
  }
  return _people
}()
var people = new People('小平不下', 'boy', 18)
console.log(people)
console.log(people.getLike()) //gril
console.log(people.display()) //my name is 小平不小,I am a boy
console.log(people.country)   //undefined
console.log(People.country)   //China  

此时看起来更像是一个整体,代码更加清晰。

4、创建对象的安全模式

上面的代码当我们在使用时,如果忘记进行 new 的操作,则函数内所有的 this 都指向 window,从而引起错误,因此可以再进行处理。如下

var People = function() {
  var like = 'gril'
  function checkName() {}
  function _people(name, sex, age) {
    // 静态私有属性和私有方法
    if (this instanceof People) {
      var like = 'gril'
      function checkName() {}
      // 特权方法
      this.getName = function() {
        return this.name
      }
      this.getSex = function() {
        return this.sex
      }
      this.setName = function(name) {
        this.name = name
      }
      this.setSex = function(sex) {
        this.sex = sex
      }
      this.getLike = function() {
        return like
      }
      // 对象的公有属性和共有方法
      this.age = age
      this.say = function() {
        return 'Hello World'
      }
      //构造器
      this.setName(name)
      this.setSex(sex)
    } else {
      return new People(name,sex,age)
    }
  }
  //类的静态共有属性和静态共有函数 
  _people.country = 'China'
  _people.introduce = function() {
    return 'I come from China'
  }
  //构建原型
  _people.prototype = {
    //公有属性和共有方法
    isAnimal: true,
    display: function() {
      return 'my name is ' + this.name + ',' + 'I am a ' + this.sex
    }
  }
  return _people
}()

此时即使是忘记 new 操作,也能正常使用。

var people = People('小平不下', 'boy', 18)
console.log(people)
console.log(people.getLike()) //gril
console.log(people.display()) //my name is 小平不小,I am a boy
console.log(people.country)   //undefined
console.log(People.country)   //China  

4、继承

关于js的继承实现的多种方法

5、参考资料

《JavaScript设计模式 张容铭》

《JavaScript设计模式 》Addy Osmani著 徐涛译版

6、结束语

最近在看有关js设计模式的知识,整理出来作为笔记,如果错误,欢迎大家指正,谢谢🙏