第6章----面向对象的程序设计

在此我会主要记录下三大点,属性类型、创建对象模式和继承方式

一、属性类型
描述了属性的各种特征,可以使用Object.getOwnPropertyDescriptor()/Object.getOwnPropertyDescriptors查看单个属性或则对象所有属性的属性特征。

1、数据属性
数据属性包含有四个描述其特征的属性
configurable:表示能否删除属性或修改属性特性。
enumerable:表示是否具有可枚举性(被for…in遍历)
writable:表示此属性值能否被修改
value:表示此属性值

2、访问器属性
访问器属性不包含属性值,但包含另外两个函数,set\get
configurable:表示能否删除属性或修改属性特性。
enumerable:表示是否具有可枚举性(被for…in遍历)
set:在读取属性时调用函数。默认返回值为undefined
get:在写入属性时调用函数。默认返回值为undefined
注意:set、get不能操作自身即

Object.defineProperty(person, 'basic', {
  enumerable: true,
  configurable: false,
  get: function() {
    console.log(this)
    return this.basic
  },
  set: function(value) {
    this.basic = value
  }
})

使用场景:一般使用在利用另外一个特定的属性来约束此属性,即

const object = (data) => {
  function Person() {
    this.leg = 'two'
    this._name = '你不是chujiu'
  }
  const person = new Person()
  person.basic = data
  return person
}
const person = object(prototypeObj)

Object.defineProperty(person, 'basic', {
  enumerable: true,
  configurable: false,
  get: function() {
    return this._name
  },
  set: function(value) {
    this._name = (this._name !== value ? '你是chujiu' : '你不是chujiu') 
  }
})

console.log(person.basic) // 你不是chujiu
person.basic = 'chujiu'
console.log(person.basic) // 你是chujiu

二、创建对象模式
关于对象创建,本质上是利用new字符或则原型对象继承(构造函数.prototype)

1、工厂模式(通过内部new字符)

// 工厂模式
const createPerson = (...data) => {
  const [name, gender] = data
  const result = new Object()
  result.name = name
  result.gender = gender
  return result
}

console.log(createPerson('埋埋', '女'))
// {name: "埋埋", gender: "女"}

2、构造函数模式(通过为外部new字符)

// 构造函数模式
const createPerson = function(name, gender) {
  this.name = name
  this.gender = gender
}

console.log(new createPerson('埋埋', '女'))
// createPerson {name: "埋埋", gender: "女"}

注意:
2.1、new字符所经历的过程,从而绑定this指向新对象
(1、创建一个新对象(空的)
(2、将构造函数的作用域赋值给新对象,即this绑定到新对象
(3、执行构造内部代码(给对象添加属性和方法)
(4、返回新的对象

2.2、任何函数,只要通过new操作符来调用,那它就是构造函数;而任何构造函数没有通过new操作符来调用,那它和其他函数也没有区别。

3、原型模式
也就是将属性写在其构造函数的原型对象上(构造函数.prototype)。

// 原型模式
const createPerson = function() {
}
createPerson.prototype.name = '埋埋'
createPerson.prototype.gender = '女'

console.log(new createPerson())
// createPerson {} 【属性都在其原型对象上】

注意:
3.1、原型,原型链
原型:每个实例或则构造函数都有个原型对象,即

obj.__proto__ => 原型对象
原型对象.constructor => 构造函数
构造函数.prototype => 原型对象
// 注意obj.__proto__、原型对象.constructor、构造函数.prototype只是指针
// 内部保存着指向地址

原型链:原型链就是以上述为单元,下一个单元就是以原型对象为实例,然后再以上述为链接。最终作用,可以通过原型链来继承,使子类可以使用父类的方法和属性。

3.2、作用域,作用域链
作用域:也可称之为执行环境,决定了变量和函数有权访问的其他数据。每个作用域都有一个变量对象储存着这个作用域内的变量及函数,当关闭网页/函数执行完毕后全局作用域/函数作用域就会销毁,并且接触变量对象中的变量和函数。

作用域链:链接以自身作用域变量对象为开始节点,其后节点为其父类(可能是爸爸,也可能是爷爷)作用域变量对象,最后以全局作用域祖宗变量对象为终止节点。

3.3、in操作符作用于整个原型链

const createPerson = function() {
}
createPerson.prototype.name = '埋埋'
createPerson.prototype.gender = '女'
const person = new createPerson()

console.log(person.hasOwnProperty('name')) // false
console.log('name' in person) // true

3.4、原型的动态性

const createPerson = function() {
}
createPerson.prototype.name = '埋埋'
createPerson.prototype.gender = '女'
const person = new createPerson()

createPerson.prototype.toSay = () => {
  console.log('小埋超可爱')
}

person.toSay()
// 小埋超可爱

实例person依旧可以调用toSay函数,这是因为当我们调用person.toSay()时,首先会在实例中寻找是否有这个方法;若没有,则会沿着原型链上寻找,直到最后找到或没找到。

4、动态原型模式
通过判断条件,动态添加

const createPerson = function(name, gender) {
  this.name = name
  this.gender = gender

  if( !(this.toSay instanceof Function) ) {
    createPerson.prototype.toSay = () => {
      console.log(`${this.name}超可爱`)
    }
  } 
}

const person = new createPerson('埋埋', '女')

person.toSay()
// 埋埋超可爱

判断是否传入了toSay,传入类型是否为函数,例如若传入函数

const createPerson = function (name, gender, toSay) {
  this.name = name
  this.gender = gender
  this.toSay = toSay

  if (!(this.toSay instanceof Function)) {
    createPerson.prototype.toSay = () => {
      console.log(`${this.name}超可爱`)
    }
  }
}

const person = new createPerson('埋埋', '女', function() {
  console.log(`${this.name}可爱`)
})

person.toSay()
// 埋埋可爱

注意:不能用箭头函数,因为没有this,导致this.toSay = toSay绑定this失败

5、寄生构造函数模式

const createPerson = function (name, toSay) {
  const result = new Object()
  result.name = name
  result.toSay = toSay
  return result
}

const person = new createPerson('埋埋', function() {
  console.log(`${this.name}可爱`)
})

console.log(person)

注意:result对象代替默认的createPerson对象
作用:一般用于为某个特殊对象,在不改动相关内置构造函数(比如:Object)的情况下,统一封装相关的特殊方法或属性,返回含有特殊方法的实例。

6、稳妥构造函数模式
就是在不使用this和new的情况下
就是上述寄生构造函数模式,生成实例不使用new字符的情况

三、继承
继承的本质是通过原型链共享某些属性和方法,方式可分为直接操作原型链或则通过this绑定,再或者通过class中的extends

1、组合继承
在构造函数中,通过强制绑定this,所实现的继承方式。

function Mammal(mouse) {
  this.mouse = mouse
}
function Person(mouse, name, toSay) {
  Mammal.call(this, mouse)
  this.name = name
  this.toSay = toSay
}

const person = new Person('mouse', '埋埋', function() {
  console.log(`${this.name}超可爱`)
})
console.log(person)
// Person {mouse: "mouse", name: "埋埋", toSay: ƒ}

2、原型式继承
在原型对象上直接添加属性或方法

const originalObj = {
  name: '埋埋',
}
function Person(original) {
  function Mammal() {}
  Mammal.prototype = original
  return new Mammal()
}

const person = Person(originalObj)
console.log(person.name)
// 埋埋

注意:这种方式已经可以Object.create(original)方法优化了。

3、寄生式继承
就是在已有的对象上添加属性

const originalObj = {
  name: '埋埋',
}
function Person(original) {
  function Mammal() {}
  Mammal.prototype = original
  return new Mammal()
}

function test(gender) {
  const person = Person(originalObj)
  person.gender = gender
  return person
}

const person = test("女")
console.log(person.gender)
// 女

4、寄生组合式继承
对于属性,在子类构造函数中通过强制绑定this执行父类构造函数,使得继承父类构造函数属性;对于方法,事先写在父类构造函数的原型对象上,再将由父类构建的实例成为子类的原型对象,从而使得由子类创建的实例继承了父类原型上的方法。

   function Parents(name = '') {
     this.name = name
   }
   Parents.prototype.toSay = function() {
     console.log(`${this.name}超可爱`)
   }

   function Son(name) {
     Parents.call(this, name)
   }
   Son.prototype = new Parents()

   const son = new Son('埋埋')
   console.log(son)
   // Son {name: "埋埋"}
   console.log(son.toSay())
   // 埋埋超可爱
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值