Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2021/02/26 - class(类)的实现 #57

Open
lxinr opened this issue Feb 25, 2021 · 0 comments
Open

2021/02/26 - class(类)的实现 #57

lxinr opened this issue Feb 25, 2021 · 0 comments

Comments

@lxinr
Copy link
Owner

lxinr commented Feb 25, 2021

只能作为构造函数使用,作为普通函数时会报错

// 类型检测
function _classCallCheck(instance, Constructor) {
  // 检测instance 是否是 Constructor 的一个实例
  if(!(instance instanceof Constructor)) {
    // 如果不是,则抛出一个类型错误
    throw new TypeError('不能直接作为函数调用')
  }
}

var Parent = function () {
  'use strict'; // 类声明和类表达式的主体都执行在严格模式下
  // 判断当前this是否属于构造函数Parent的一个实例
  _classCallCheck(this, Parent)
}

console.log(Parent()) // Uncaught TypeError: 不能直接作为函数调用
console.log(new Parent()) // Parent {}

给父类添加方法

function _defineProperties(target, props) {
  for(var i = 0; i < props.length; i++) {
    var prop = props[i]
    // 如果存在value,即表示为可写入的
    if('value' in prop) prop.writable = true
    // configurable
    Object.defineProperty(target, prop.key, prop)
  }
}

function _createClass(Constructor, protoProps, staticProps) {
  // 如果是原型方法,其应该是挂载在原型上
  if(protoProps) _defineProperties(Constructor.prototype, protoProps)
  // 如果是静态方法,则是直接挂载在构造函数上,静态方法不需要实例化该函数即可使用
  if(staticProps) _defineProperties(Constructor, staticProps)
  return Constructor
}

var Parent = function () {
  'use strict'; // 类声明和类表达式的主体都执行在严格模式下'
  function Parent(options) {
    // 判断当前this是否属于构造函数Parent的一个实例
    _classCallCheck(this, Parent)

    this.name = options.name || ''
    this.age = options.age || 20
  }

  _createClass(Parent, [
    {
      key: 'find',
      value: function(v) {
        return ''.concat(v, '慢慢慢慢慢慢')
      }
    },
    {
      key: 'info',
      get: function() {
        return 'name is '.concat(this.name).concat(',age is ', this.age)
      }
    }
  ], [
    {
      key: 'eat',
      value: function() {
        return ''.concat(this.name, ' eat apple')
      }
    }
  ])

  return Parent
}()

const parent = new Parent({ name: '流了颗星' })
console.log(parent.find('666')) // 666慢慢慢慢慢慢
console.log(parent.info) // name is 流了颗星,age is 20
console.log(parent.eat()) // Parent eat apple

子类实现继承

function _inherits(subClass, superClass) {
  // 判断父类是否是符合要求的
  if (typeof superClass !== 'function' && superClass !== null) {
    throw new TypeError('Super expression must either be null or a function')
  }
  // 让子类继承父类的公有方法
  // Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
  // 大致为 
  // subClass.prototype = Object.create(superClass.prototype)
  // subClass.prototype。constructor = subClass
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: { value: subClass, writable: true, configurable: true },
  })
  // 让子类继承父类的静态方法,即subClass.__proto__ = superClass
  if (superClass) Object.setPrototypeOf(subClass, superClass)
}

const Child = function(Parent) {
  _inherits(Child, Parent) // 继承父类方法

  function Child(options) {
    _classCallCheck(this, Child)
    const val = Parent.call(this, options)
    // 如果父级返回了一个对象类型,则把this指向为这个返回的对象
    if(typeof val === 'object') return val
    return this
  }
  return Child
}(Parent)

完整实现

function _classCallCheck(instance, Constructor) {
  // 检测instance 是否是 Constructor 的一个实例
  if (!(instance instanceof Constructor)) {
    // 如果不是,则抛出一个类型错误
    throw new TypeError('不能直接作为函数调用')
  }
}

function _defineProperties(target, props) {
  for (var i = 0; i < props.length; i++) {
    var prop = props[i]
    // 如果存在value,即表示为可写入的
    if ('value' in prop) prop.writable = true
    // configurable
    Object.defineProperty(target, prop.key, prop)
  }
}

function _createClass(Constructor, protoProps, staticProps) {
  // 如果是原型方法,其应该是挂载在原型上
  if (protoProps) _defineProperties(Constructor.prototype, protoProps)
  // 如果是静态方法,则是直接挂载在构造函数上,静态方法不需要实例化该函数即可使用
  if (staticProps) _defineProperties(Constructor, staticProps)
  return Constructor
}

function _inherits(subClass, superClass) {
  // 判断父类是否是符合要求的
  if (typeof superClass !== 'function' && superClass !== null) {
    throw new TypeError('Super expression must either be null or a function')
  }
  // 让子类继承父类的公有方法
  // Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
  // 大致为 
  // subClass.prototype = Object.create(superClass.prototype)
  // subClass.prototype。constructor = subClass
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: { value: subClass, writable: true, configurable: true },
  })
  // 让子类继承父类的静态方法,即subClass.__proto__ = superClass
  if (superClass) Object.setPrototypeOf(subClass, superClass)
}

var Parent = (function () {
  'use strict' // 类声明和类表达式的主体都执行在严格模式下'
  function Parent(options) {
    // 判断当前this是否属于构造函数Parent的一个实例
    _classCallCheck(this, Parent)

    this.name = options.name || ''
    this.age = options.age || 20

    return '53443'
  }

  _createClass(
    Parent,
    [
      {
        key: 'find',
        value: function (v) {
          return ''.concat(v, '慢慢慢慢慢慢')
        },
      },
      {
        key: 'info',
        get: function () {
          return 'name is '.concat(this.name).concat(',age is ', this.age)
        },
      },
    ],
    [
      {
        key: 'eat',
        value: function () {
          return ''.concat(this.name, ' eat apple')
        },
      },
    ]
  )

  return Parent
})()

var Child = function(Parent) {
  _inherits(Child, Parent) // 继承父类方法

  function Child(options) {
    _classCallCheck(this, Child)
    const val = Parent.call(this, options)
    // 如果父级返回了一个对象类型,则把this指向为这个返回的对象
    if(typeof val === 'object') return val
    return this
  }
  return Child
}(Parent)


const parent = new Parent({ name: '流了颗星' })

console.log(parent)
console.log(parent.find('666')) // 666慢慢慢慢慢慢
console.log(parent.info) // name is 流了颗星,age is 20
console.log(Parent.eat()) // Parent eat apple

const c = new Child({ name: '六六六' })
console.log('c----', c.info) // name is 六六六,age is 20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant