关于javascript:javascript高级程序设计学习笔记-84类

6次阅读

共计 14385 个字符,预计需要花费 36 分钟才能阅读完成。

关注前端小讴,浏览更多原创技术文章

  • ES6 新引入 class 关键字具备正式定义类的能力,其背地应用的依然是 原型 构造函数 的概念

相干代码 →

类定义

  • 与函数类型相似,定义类也有 2 种次要形式:类申明 类表达式 ,2 种形式都是用class 关键字加大括号
class Person {} // 类申明
var animal = class {} // 类表达式
  • 类表达式在 被求值前不能引用 (同函数表达式),类定义 不能申明晋升(与函数表达式不同)
console.log(FunctionDeclaration) // [Function: FunctionDeclaration],函数申明提前
function FunctionDeclaration() {}
console.log(ClassDeclaration) // ReferenceError: Cannot access 'ClassDeclaration' before initialization,类没有申明提前
class ClassDeclaration {}
  • 类受 块级作用域 限度(函数受 函数作用域 限度)
{function FunctionDeclaration2() {}
  class ClassDeclaration2 {}}
console.log(FunctionDeclaration2) // [Function: FunctionDeclaration2]
console.log(ClassDeclaration2) // ReferenceError: ClassDeclaration2 is not defined

类的形成

  • 类能够蕴含 构造函数办法 实例办法 获取函数 设置函数 动态类办法 ,也能够 空类定义
  • 默认状况下,类定义中的代码都在 严格模式 下执行
  • 类名 倡议 首字母大写(与构造函数一样),以区分类和实例
class Foo {} // 空类定义
class Bar {constructor() {} // 构造函数
  get myBaz() {} // 获取函数
  static myQux() {} // 静态方法
}
  • 把类表达式赋值给变量后,能够在 类表达式作用域外部 拜访类表达式,并通过 name 属性获得 类表达式的名称
var Person2 = class PersonName {identify() {console.log(PersonName) // 类表达式作用域外部,拜访类表达式
    console.log(Person2.name, PersonName.name) // 类表达式作用域外部,拜访类表达式的名称
    /* 
      [class PersonName]
      PersonName PersonName
    */
  }
}
var p = new Person2()
p.identify()
console.log(Person2.name) // PersonName
console.log(PersonName) // ReferenceError: PersonName is not defined,类表达式作用域内部,无法访问类表达式

类构造函数

  • 在类定义块外部用 constructor 关键字创立 类的构造函数

    • 应用 new 操作符创立 类的实例 时,调用 constructor 办法
    • 构造函数的定义 非必须 不定义 构造函数相当于将构造函数定义为 空函数

实例化

  • 应用 new 操作符调用 类的构造函数 会执行如下操作(同构造函数):

    • 创立了一个新对象(实例)
    • 新对象外部的 [[Prototype]] 个性被赋值为构造函数的 prototype 属性(独特指向原型)
    • 将构造函数的作用域(即 this)赋给新对象
    • 执行构造函数中的代码(即:为这个对象增加新属性)
    • 返回新对象或非空对象
class Animal2 {}
class Person3 {constructor() {console.log('person ctor')
  }
}
class Vegetable {constructor() {this.color = 'orange'}
}
var a = new Animal2()
var p = new Person3() // 'person ctor'
var v = new Vegetable()
console.log(v.color) // 'orange'
  • 类实例化时,传入的参数 会用做 构造函数的参数(无参数则类名后可不加括号)
class Person4 {constructor(name) {console.log(arguments.length)
    this.name = name || null
  }
}

var p1 = new Person4() // 0,无参数,Person4 后的括号也可省略
console.log(p1.name) // null
var p2 = new Person4('Jake') // 1
console.log(p2.name) // 'Jake'
  • 默认状况下,类构造函数会在执行后 返回 this 对象 (类实例),如果 返回的不是 this 对象 ,则该对象用instanceof 操作符检测时 与类无关联
class Person5 {constructor() {this.foo = 'foo'}
}
var p3 = new Person5()
console.log(p3) // Person5 {foo: 'foo'},类实例
console.log(p3.__proto__) // {},类原型
console.log(p3.constructor) // [class Person5],类自身当作构造函数
console.log(Person5 === p3.constructor) // true
console.log(Person5.prototype === p3.__proto__) // true
console.log(p3 instanceof Person5) // true,p3 是 Person5 的实例(Person5.prototype 在 p3 的原型链上)class Person6 {constructor() {
    return {bar: 'bar', // 返回一个全新的对象(不是该类的实例)}
  }
}
var p4 = new Person6()
console.log(p4) // {bar: 'bar'},不是 Person6 的类实例
console.log(p4.__proto__) // {},Object 原型
console.log(p4.constructor) // [Function: Object],Object 构造函数
console.log(Object === p4.constructor) // true
console.log(Object.prototype === p4.__proto__) // true
console.log(p4 instanceof Person6) // false,p4 不是 Person6 的实例(Person6.prototype 不在 p4 的原型链上)
  • 类构造函数 构造函数 次要区别 是:类构造函数必须应用 new 操作符,一般构造函数能够不应用 new 操作符(当作一般函数调用)
function Person7() {} // 一般构造函数
class Animal3 {} // 类构造函数
var p5 = Person7() // 构造函数不应用 new 操作符,当作一般函数调用
var a1 = Animal3() // TypeError: Class constructor Animal3 cannot be invoked without 'new',类构造函数必须应用 new 操作符实例化
var a2 = new Animal3()
  • 类构造函数 实例化后 ,会成为一般的 实例办法 ,能够应用new 操作符 在实例上援用
class Person8 {constructor() {console.log('foo')
  }
}
var p6 = new Person8() // 'foo'
// p6.constructor() // TypeError: Class constructor Person8 cannot be invoked without 'new'
new p6.constructor() // 'foo'

把类当成非凡函数

  • 类是一种 非凡函数 ,可用typeof 操作符检测
console.log(typeof Person8) // function
  • 类标识具备 prototype 属性(指向原型),原型的 constructor 属性(默认)指向 类本身
console.log(Person8.prototype) // {},原型
console.log(Person8.prototype.constructor) // [class Person8],类本身
console.log(Person8.prototype.constructor === Person8) // true
  • 能够应用 instanceof 操作符查看 prototype指向的对象 是否存在于 类实例 的原型链中
console.log(p6 instanceof Person8) // true,p6 是 Person8 的实例
  • 应用 new 操作符调用 类自身 时,类自身 被当成构造函数,类实例的 constructor 指向类自身
  • 应用 new 操作符调用 类构造函数 时,类构造函数(constructor()被当成构造函数,类实例的 constructor 指向 Function 构造函数
class Person9 {}
console.log(Person9.constructor) // [Function: Function],指向 Function 原型的 constructor,即 Function 构造函数

var p7 = new Person9() // new 调用类自身,类自身被当作构造函数
console.log(p7.constructor) // [class Person9],constructor 指向构造函数,即类自身
console.log(p7.constructor === Person9) // true
console.log(p7 instanceof Person9) // true,p7 是 Person9 的实例

var p8 = new Person9.constructor() // new 调用类构造函数,类构造函数(constructor())被当作构造函数
console.log(p8.constructor) // [Function: Function],constructor 指向构造函数,即 Function 构造函数
console.log(p8.constructor === Function) // true
console.log(p8 instanceof Person9.constructor) // true,p8 是 Person9.constructor 的实例
  • 能够 把类当作参数 传递
let classList = [
  class {constructor(id) {
      this._id = id
      console.log(`instance ${this._id}`)
    }
  },
]
function createInstance(classDefinition, id) {return new classDefinition(id)
}
var foo = new createInstance(classList[0], 3141) // 'instance 3141'
  • 类能够 立刻实例化
var p9 = new (class Foo2 {constructor(x) {console.log(x) // 'bar'
  }
})('bar')
console.log(p9) // Foo2 {},类实例
console.log(p9.constructor) // [class Foo2],类自身

实例、原型和类成员

  • 类的语法能够十分不便定义应该存在于 实例上 原型上 类自身 的成员

实例成员

  • 类的构造函数(constructor())外部 ,能够为实例增加 自有属性
  • 每个实例对应 惟一 的成员对象,所有成员 不会 在原型上共享
class Person10 {constructor() {this.name = new String('Jack')
    this.sayName = function () {console.log(this.name)
    }
    this.nickNames = ['Jake', 'J-Dog']
  }
}
var p10 = new Person10()
var p11 = new Person10()

console.log(p10.name) // [String: 'Jack'],字符串包装对象
console.log(p11.name) // [String: 'Jack'],字符串包装对象
console.log(p10.name === p11.name) // false,非同一个对象(不共享)console.log(p10.sayName) // ƒ () { console.log(this.name) },function 对象
console.log(p11.sayName) // ƒ () { console.log(this.name) },function 对象
console.log(p10.sayName === p11.sayName) // false,非同一个对象(同理,不共享)console.log(p10.nickNames === p11.nickNames) // false,同理↑

p10.name = p10.nickNames[0]
p11.name = p10.nickNames[1]
p10.sayName() // 'Jake',实例成员互不影响
p11.sayName() // 'J-Dog',实例成员互不影响

原型办法与拜访器

  • 类块({})中 定义的办法作为 原型办法
class Person11 {constructor() {
    // 实例办法
    this.locate = () => {console.log('instance')
    }
  }
  locate() {
    // 原型办法
    console.log('prototype')
  }
  locate2() {
    // 原型办法
    console.log('prototype2')
  }
}
var p12 = new Person11()
p12.locate() // 'instance',实例办法遮蔽原型办法
p12.__proto__.locate() // 'prototype'
p12.locate2() // 'prototype2'
  • 办法 能够定义在 类的构造函数 类块 中,属性 不能定义在 类块中
class Person12 {name: 'jack' // Uncaught SyntaxError: Unexpected identifier}
  • 能够应用 字符串 符号 计算的值 ,作为 类办法的键
const symbolKey = Symbol('symbolKey')
class Person13 {stringKey() {
    // 字符串作为键
    console.log('stringKey')
  }
  [symbolKey]() {
    // 符号作为键
    console.log('symbolKey')
  }
  ['computed' + 'Key']() {
    // 计算的值作为建
    console.log('computedKey')
  }
}
  • 类块({})中 定义 获取和设置拜访器
class Person14 {set setName(newName) {this._name = newName}
  get getName() {return this._name}
}
var p13 = new Person14()
p13.setName = 'Jake'
console.log(p13.getName) // 'Jake'

动态类办法

  • 类块({})中 定义动态类办法,办法存在于 类自身
  • 每个类 只能有一个 动态类成员
class Person15 {constructor() {
    // 增加到 this 的内容存在于不同实例上
    this.locate = () => {console.log('instance', this) // 此处的 this 为类实例
    }
  }
  locate() {
    // 定义在类的原型对象上
    console.log('prototype', this) // 此处的 this 为类原型
  }
  static locate() {
    // 定义在类自身上
    console.log('class', this) // 此处的 this 为类自身
  }
}
var p14 = new Person15()

p14.locate() // 'instance' Person15 { locate: [Function (anonymous)] }
p14.__proto__.locate() // 'prototype' {}
Person15.locate() // 'class' [class Person15]
  • 动态类办法非常适合作为 实例工厂
class Person16 {constructor(age) {this._age = age}
  sayAge() {console.log(this._age)
  }
  static create() {return new Person16(Math.floor(Math.random() * 100))
  }
}
console.log(Person16.create()) // Person16 {_age: ...}

非函数原型和类成员

  • 能够在 类定义内部 ,手动地在 原型 类上 增加成员数据
  • 类定义 没有显示反对增加数据成员的办法 ,实例应该单独领有通过this 援用的数据
class Person17 {sayName() {console.log(`${Person17.greeting} ${this.name}`)
  }
}
var p15 = new Person17()
Person17.greeting = 'My name is' // 在类上定义数据
Person17.prototype.name = 'Jake' // 在原型上定义数据
p15.sayName() // 'My name is Jake'

迭代器与生成器办法

  • 可在 原型 类自身 上定义 生成器办法
class Person18 {*createNicknameIterator() {
    // 在原型上定义生成器办法
    yield 'Jack'
    yield 'Jake'
    yield 'J-Dog'
  }
  static *createJobIterator() {
    // 在类自身定义生成器办法
    yield 'Butcher'
    yield 'Baker'
    yield 'Candlestick maker'
  }
}

var jobIter = Person18.createJobIterator() // 调用生成器函数,产生生成器对象
console.log(jobIter.next().value) // 'Butcher'
console.log(jobIter.next().value) // 'Baker'
console.log(jobIter.next().value) // 'Candlestick maker'

var p16 = new Person18()
var nicknameIter = p16.createNicknameIterator() // 调用生成器函数,产生生成器对象
console.log(nicknameIter.next().value) // 'Jack'
console.log(nicknameIter.next().value) // 'Jake'
console.log(nicknameIter.next().value) // 'J-Dog'
  • 生成器办法 可作为 默认迭代器,把类实例变成可迭代对象
class Person19 {constructor() {this.nickNames = ['Jack', 'Jake', 'J-Dog']
  }
  *[Symbol.iterator]() {
    // 生成器函数作为默认迭代器
    yield* this.nickNames.entries()}
}

var p17 = new Person19()
for (let [i, n] of p17) {console.log(i, n)
  /* 
    0 'Jack'
    1 'Jake'
    2 'J-Dog'
  */
}
  • 可间接 返回迭代器实例
class Person20 {constructor() {this.nickNames = ['Jack', 'Jake', 'J-Dog']
  }
  [Symbol.iterator]() {
    // 返回迭代器实例
    return this.nickNames.entries()}
}
var p18 = new Person20()
for (let [i, n] of p18) {console.log(i, n)
  /* 
    0 'Jack'
    1 'Jake'
    2 'J-Dog'
  */
}

继承

  • ES6 反对 类继承 机制,应用的仍旧是 原型链

继承根底

  • ES6 类反对 单继承 ,应用extends 关键字能够继承任何领有 [[Construct]] 和原型的对象(可继承 一般构造函数
class Vehicle {}
class Bus extends Vehicle {} // 继承类
var b = new Bus()
console.log(b instanceof Bus) // true
console.log(b instanceof Vehicle) // true

function Person21() {}
class Engineer extends Person21 {} // 继承构造函数
var p19 = new Engineer()
console.log(p19 instanceof Engineer) // true
console.log(p19 instanceof Person21) // true
  • extends关键字可在类表达式中应用
var Bus2 = class extends Vehicle {}
  • 子类通过原型链拜访 父类 父类原型 上定义的办法,this值反映调用相应办法的 实例
class Vehicle2 {identifyPrototype(id) {
    // 父类原型上定义的办法
    console.log(id, this)
  }
  static identifyClass(id) {
    // 父类自身定义的办法
    console.log(id, this)
  }
}
class Bus3 extends Vehicle2 {}

var v = new Vehicle2()
var b2 = new Bus3()

v.identifyPrototype('v') // 'v' Vehicle2 {},this 为父类实例
b2.identifyPrototype('b') // 'b' Bus3 {},this 为子类实例
v.__proto__.identifyPrototype('v') // 'v' {},this 为父类原型
b2.__proto__.identifyPrototype('b') // 'b' Vehicle2 {},this 为子类原型,即父类实例
Vehicle2.identifyClass('v') // v [class Vehicle2],this 为父类自身
Bus3.identifyClass('b') // b [class Bus3 extends Vehicle2],this 为子类自身

构造函数、HomeObject 和 super()

  • 子类构造函数 中,能够通过 super() 调用 父类构造函数
class Vehicle3 {constructor() {this.hasEngine = true}
}
class Bus4 extends Vehicle3 {constructor() {super() // 调用父类构造函数 constructor
    console.log(this) // Bus4 {hasEngine: true},子类实例,已调用父类构造函数
    console.log(this instanceof Vehicle3) // true
    console.log(this instanceof Bus4) // true
  }
}
new Bus4()
  • 子类静态方法 ,能够通过super() 调用 父类静态方法
class Vehicle4 {static identifyV() {
    // 父类静态方法
    console.log('vehicle4')
  }
}
class Bus5 extends Vehicle4 {static identifyB() {
    // 子类静态方法
    super.identifyV() // 调用父类静态方法}
}
Bus5.identifyB() // 'vehicle4'
  • ES6 给 类构造函数 静态方法 增加了外部个性 [[HomeObject]],指向 定义该办法的对象 super 始终会定义为 [[HomeObject]] 的原型
  • 应用 super 需注意几个问题:

    • super只能在 子类构造函数 子类静态方法 中应用
    • 不能独自援用 super 关键字,要么 调用构造函数 ,要么 援用静态方法
    • 调用 super()调用父类构造函数,并将返回的实例赋值给this
    • 调用 super() 时如需给父类构造函数传参,需手动传入
    • 子类未定义构造函数 ,则其实例化时 主动调用 super() 并传入所有传给父类的参数
    • 调用 super() 前,不能 在子类构造函数或静态方法里 先援用this
    • 子类显式定义构造函数 ,则要么 在其中调用 super(),要么 在其中返回新对象
class Vehicle5 {constructor(id) {// super() // SyntaxError: 'super' keyword unexpected here,super 只能在子类构造函数和子类静态方法中应用
    this.id = id
  }
}
class Bus6 extends Vehicle5 {constructor(id) {// console.log(super) // SyntaxError: 'super' keyword unexpected here,不能独自援用 super
    // console.log(this) // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor,调用 super()之前不能引用 this
    super(id) // 调用父类构造函数,手动给父类构造函数传参,并将返回的实例赋给 this(子类实例)console.log(this) // Bus6 {id: 5},子类实例
    console.log(this instanceof Vehicle5) // true
    console.log(this instanceof Bus6) // true
  }
}
new Bus6(5)

class Bus7 extends Vehicle5 {} // 子类未定义构造函数
console.log(new Bus7(6)) // Bus7 {id: 6},实例化时主动调用 super()并传参

class Bus8 extends Vehicle5 {// constructor() {} // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
  constructor(id) {super(id) // 子类显式定义构造函数,要么调用 super()}
}
class Bus9 extends Vehicle5 {// constructor() {} // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
  constructor(id) {return {} // 子类显式定义构造函数,要么返回其余对象
  }
}
console.log(new Bus8(7)) // Bus8 {id: 7},子类实例
console.log(new Bus9(8)) // {},返回新对象

形象基类

  • 可设置父类 仅供子类继承 ,自身 不会被实例化 ,通过new.target 检测是否为形象基类
  • 可在父类要求 子类必须定义某办法 ,通过this 查看相应办法是否存在
class Vehicle6 {constructor() {console.log(new.target)
    if (new.target === Vehicle6) {
      // 阻止形象基类被实例化
      throw new Error('Vehicle6 cannot be directly instantiated')
    }
    if (!this.foo) {// 要求子类必须定义 foo()办法
      throw new Error('Inheriting class must define foo()')
    }
  }
}
class Bus10 extends Vehicle6 {} // 子类未定义 foo()办法
class Bus11 extends Vehicle6 {// 子类定义了 foo()办法
  foo() {}
}

// new Vehicle6() // [class Vehicle6],Error: Vehicle6 cannot be directly instantiated
// new Bus10() // [class Bus10 extends Vehicle6],Error: Inheriting class must define foo()
new Bus11() // [class Bus11 extends Vehicle6]

继承内置类型

  • 能够应用类继承 扩大内置类型
class SuperArray extends Array {
  // 在子类原型上追加办法:任意洗牌
  shuffle() {for (let i = this.length - 1; i > 0; i--) {const j = Math.floor(Math.random() * (i + 1))
      ;[this[i], this[j]] = [this[j], this[i]]
    }
  }
}
var a = new SuperArray(1, 2, 3, 4, 5)
console.log(a instanceof Array) // true,a 是 Array 的实例
console.log(a instanceof SuperArray) // true,a 是 SuperArray 的实例
console.log(a) // SuperArray(5) [1, 2, 3, 4, 5]
a.shuffle()
console.log(a) // SuperArray(5) [3, 1, 2, 5, 4]
  • 内置类型的 有些办法返回新实例 ,默认状况下返回实例类型 与原始实例类型统一
var a1 = new SuperArray(1, 2, 3, 4, 5)
var a2 = a1.filter((x) => !!(x % 2)) // filter 办法返回新的实例,实例类型与 a1 的统一
console.log(a1) // SuperArray(5) [1, 2, 3, 4, 5]
console.log(a2) // SuperArray(3) [1, 3, 5]
console.log(a1 instanceof SuperArray) // true
console.log(a2 instanceof SuperArray) // true
  • 能够用 Symbol.species 定义 动态获取器 getter 办法 笼罩内置类型的办法新创建实例时返回的类
class SuperArray2 extends Array {
  // Symbol.species 定义动态获取器办法,笼罩新创建实例时返回的类
  static get [Symbol.species]() {return Array // 内置类型的办法新创建实例时,返回 Array 类型}
}
var a3 = new SuperArray2(1, 2, 3, 4, 5)
var a4 = a3.filter((x) => !!(x % 2)) // filter 办法返回新的实例,实例类型已被笼罩(Array)console.log(a3) // SuperArray(5) [1, 2, 3, 4, 5]
console.log(a4) // [1, 3, 5]
console.log(a3 instanceof SuperArray2) // true
console.log(a4 instanceof SuperArray2) // false

类混入

  • extends关键字前面除了能够是父类,还能够是 任何能够解析为一个类或构造函数的表达式
class Vehicle7 {}
function getParentClass() {console.log('evaluated expression')
  return Vehicle7 // 表达式被解析为 Vehicle7 类
}
class Bus12 extends getParentClass {}
new Bus12() // 'evaluated expression'
  • 能够通过 混入模式 ,在 一个表达式 连缀多个混入元素 ,该表达式最终 解析 为一个 能够被继承的类
class Vehicle8 {}
let FooMixin = (SuperClass) =>
  // 表达式接管超类作为参数,返回子类
  class extends SuperClass {
    // 子类原型追加办法
    foo() {console.log('foo')
    }
  }
let BarMixin = (SuperClass) =>
  // 表达式接管超类作为参数,返回子类
  class extends SuperClass {
    // 子类原型追加办法
    bar() {console.log('bar')
    }
  }

class Bus13 extends BarMixin(FooMixin(Vehicle8)) {} // 嵌套逐级继承:FooMixin 继承 Vehicle8,BarMixin 继承 FooMixin,Bus13 继承 BarMixin
var b3 = new Bus13()
console.log(b3) // Bus13 {},子类实例
b3.foo() // 'foo',继承了超类原型上办法
b3.bar() // 'bar',继承了超类原型上办法
  • 通过写一个 辅助函数 ,把 嵌套调用开展
function mix(BaseClass, ...Mixins) {
  /* 
    reduce 接管 2 个参数:对每一项都会运行的归并函数、归并终点的初始值(非必填)归并函数接管 4 个参数:上一个归并值、以后项、以后索引、数组自身
  */
  return Mixins.reduce((pre, cur) => cur(pre), // 归并办法:执行以后项办法,参数为上个归并值
    BaseClass // 归并初始值
  )
}
class Bus14 extends mix(Vehicle7, FooMixin, BarMixin) {}
var b4 = new Bus14()
console.log(b4) // Bus14 {}
b4.foo() // 'foo'
b4.bar() // 'bar'

总结 & 问点

  • 如何定义 JS 的类?类和函数有哪些异同?
  • 类能够蕴含哪些内容?如何拜访类表达式及其名称?
  • 类实例化时外部历经哪些步骤?类构造函数默认返回什么?若返回一个新对象会有什么印象?
  • 类构造函数与一般构造函数的次要区别是什么?
  • 类属于什么数据类型?其 prototype 和 constructor 别离指向什么?应用 new 操作符调用类自身和类构造函数有什么区别?
  • 写 2 段代码,别离表述“类当作参数”及“类立刻实例化”
  • 如何定义类的实例成员、原型办法、拜访器办法、动态类办法?其又别离定义在类的什么地位(实例 / 原型 / 类自身)?
  • 写 1 段代码,应用动态类办法作为实例工厂
  • 如何手动增加类成员数据?为什么类定义中不显示反对增加数据成员?
  • 生成器办法能够定义在类的什么地位?写 1 段代码,在类定义时增加生成器办法,并将其作为默认迭代器
  • 类能够通过 extends 关键字继承哪些对象?extends 前面能够是哪些元素?子类通过原型链能够拜访父类哪里的办法?
  • super 关键字的作用和用法是什么?其应用时有哪些留神点?
  • 如何定义形象基类?其作用是什么?
  • 写一段代码,用类继承扩大内置对象 Array,且子类调用 concat()办法后返回 Array 实例类型
  • 写一段代码,用混入模式的嵌套调用实现多个类的逐级继承,再用辅助函数实现嵌套开展

正文完
 0