对象的创建模式

① Object构造函数模式
  1. var obj = {};
  2. obj.name = 'Tom'
  3. obj.setName = function(name){this.name=name}
  1. * 套路: 先创建空Object对象, 再动态添加属性/方法
  2. * 适用场景: 起始时不确定对象内部数据
  3. * 问题: 语句太多

② 对象字面量模式
  1. var obj = {
  2. name : 'Tom',
  3. setName : function(name){this.name = name}
  4. }
  1. * 套路: 使用{}创建对象, 同时指定属性/方法
  2. * 适用场景: 起始时对象内部数据是确定的
  3. * 问题: 如果创建多个对象, 有重复代码

③ 工厂模式
  1. function createPerson(name, age) { //返回一个对象的函数===>工厂函数
  2. var obj = {
  3. name: name,
  4. age: age,
  5. setName: function (name) {
  6. this.name = name
  7. }
  8. }
  9. return obj
  10. }
  11. // 创建2个人
  12. var p1 = createPerson('Tom', 12) //Object类型
  13. var p2 = createPerson('Bob', 13)
  1. * 套路: 通过工厂函数动态创建对象并返回
  2. * 适用场景: 需要创建多个对象
  3. * 问题: 对象没有一个具体的类型, 都是Object类型

④ 构造函数模式✅
  1. function Person(name, age) {
  2. this.name = name
  3. this.age = age
  4. this.setName = function (name) {
  5. this.name = name
  6. }
  7. }
  8. var p1 = new Person('Tom', 12) //Person类型
  1. * 套路: 自定义构造函数, 通过new创建对象
  2. * 适用场景: 需要创建多个类型确定的对象
  3. * 问题: 每个对象都有相同的数据, 浪费内存

⑤ 构造函数+原型的组合模式
  1. function Person(name, age) { //在构造函数中只初始化一般函数
  2. this.name = name
  3. this.age = age
  4. }
  5. Person.prototype.setName = function (name) {
  6. this.name = name
  7. }
  8. var p1 = new Person('Tom', 23)
  9. var p2 = new Person('Jack', 24)
  1. * 套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
  2. * 适用场景: 需要创建多个类型确定的对象

继承模式

① 原型链继承 : 得到方法
  1. <!--
  2. 方式1: 原型链继承
  3. 1. 套路
  4. 1. 定义父类型构造函数
  5. 2. 给父类型的原型添加方法
  6. 3. 定义子类型的构造函数
  7. 4. 创建父类型的对象赋值给子类型的原型
  8. 5. 将子类型原型的构造属性设置为子类型
  9. 6. 给子类型原型添加方法
  10. 7. 创建子类型的对象: 可以调用父类型的方法
  11. 2. 关键
  12. 1. 子类型的原型为父类型的一个实例对象
  13. -->
  14. <script type="text/javascript">
  15. //父类型
  16. function Supper() {
  17. this.supProp = 'Supper property'
  18. }
  19. Supper.prototype.showSupperProp = function () {
  20. console.log(this.supProp)
  21. }
  22. //子类型
  23. function Sub() {
  24. this.subProp = 'Sub property'
  25. }
  26. // 子类型的原型为父类型的一个实例对象
  27. Sub.prototype = new Supper()
  28. // 让子类型的原型的constructor指向子类型
  29. Sub.prototype.constructor = Sub
  30. Sub.prototype.showSubProp = function () {
  31. console.log(this.subProp)
  32. }
  33. var sub = new Sub()
  34. sub.showSupperProp()
  35. // sub.toString()
  36. sub.showSubProp()
  37. console.log(sub) // Sub
  38. </script>

② 借用构造函数 : 得到属性
  1. <!--
  2. 方式2: 借用构造函数继承(假的)
  3. 1. 套路:
  4. 1. 定义父类型构造函数
  5. 2. 定义子类型构造函数
  6. 3. 在子类型构造函数中调用父类型构造
  7. 2. 关键:
  8. 1. 在子类型构造函数中通用call()调用父类型构造函数
  9. -->
  10. <script type="text/javascript">
  11. function Person(name, age) {
  12. this.name = name
  13. this.age = age
  14. }
  15. function Student(name, age, price) {
  16. Person.call(this, name, age) // 相当于: this.Person(name, age)
  17. /*this.name = name
  18. this.age = age*/
  19. this.price = price
  20. }
  21. let s = new Student('Tom', 20, 14000)
  22. console.log(s);
  23. console.log(s.name, s.age, s.price)
  24. </script>

③ 组合
  1. <!--
  2. 方式3: 原型链+借用构造函数的组合继承
  3. 1. 利用原型链实现对父类型对象的方法继承
  4. 2. 利用super()借用父类型构建函数初始化相同属性
  5. -->
  6. <script type="text/javascript">
  7. function Person(name, age) {
  8. this.name = name
  9. this.age = age
  10. }
  11. Person.prototype.setName = function (name) {
  12. this.name = name
  13. }
  14. function Student(name, age, price) {
  15. Person.call(this, name, age) // 为了得到属性
  16. this.price = price
  17. }
  18. Student.prototype = new Person() // 为了能看到父类型的方法
  19. Student.prototype.constructor = Student //修正constructor属性
  20. Student.prototype.setPrice = function (price) {
  21. this.price = price
  22. }
  23. let s = new Student('Tom', 24, 15000)
  24. s.setName('Bob')
  25. s.setPrice(16000)
  26. console.log(s.name, s.age, s.price)
  27. </script>

new一个对象背后做了些什么?
  • 创建一个空对象
  • 给对象设置proto, 值为构造函数对象的prototype属性值 this.proto = Fn.prototype
  • 执行构造函数体(给对象添加属性/方法)