zoukankan      html  css  js  c++  java
  • JS 语法之--对象类型(构造器,class,this),高阶对象(高阶类,Minix模式)

    1、JS 对象类型

      JavaScript 是一种基于原型(prototype)的面向对象语言,而不是基于类的面向对象语言

      C++, Java 有类Class 和实例Instance 的概念,类是一类事物 的抽象,而实例则是类的实体。

      JS是基于原型的语言,它只有原型对象的概念,原型对象就是一个模板,新的对象从这个模板构建从而获取最初的属性,任何对象在运行的时候可以动态的增加属性,而且,任何一个对象都可以作为另一个对象的原型,这样后者就可以共享前者的属性。

    2、定义类 

      字面式声明方式

        

         这种方法也称为 字面值创建对象。JS 1.2 开始支持

      ES6之前--构造器

        1、应以一个函数(构造器)对象,函数名首字母大写

        2、使用this 的定义属性

        3、使用new 和构造器创建一个新对象

        测试:
     1 // 定义类,构造器
     2 function Point(x, y) {
     3     this.x = x;
     4     this.y = y;
     5     this.show = () => {console.log(this, this.x, this.y)}
     6     console.log('======================')
     7 }
     8 
     9 //继承
    10 function Point3D(a, b, z) {
    11     Point.call(this,a,b)
    12     this.z = z;
    13     console.log('print3d')
    14 }
    15 
    16 console.log(Point3D)
    17 p2 = new Point3D(1,2,3)
    18 console.log('******************')
    19 console.log(p2)
    20 console.log('******************')
    21 p2.show()
    
    
    

           结果:

    1 Info: Start process (19:52:17)
    2 [Function: Point3D]
    3 ======================
    4 print3d
    5 ******************
    6 Point3D { x: 1, y: 2, show: [Function], z: 3 }
    7 ******************
    8 Point3D { x: 1, y: 2, show: [Function], z: 3 } 1 2
    9 Info: End process (19:52:17)

         new 构建一个新的通用对象,new操作符会将新对象的this 值传递给Point3D 构造器函数,函数为这个对象创建 z 属性

         从上句话知道,new 后得到一个对象,使用这个对象的this 来调用构造器,那么如何执行‘基类’的构造方法

         使用Point3D 对象的this来执行Point 的构造器,所以使用call 方法,传入子类的this

        最终,构造完成后,将对象赋值给 p2

        注意:如果不使用new 关键字,就是一个普通函数的函数调用,this不代表实例。

       

      ES6 中的class

         从ES 6开始,新提供了class 关键字,使得创建对象更加简单,清晰。

      1. 类定义使用了class 关键字,创建的本质上海市函数,是一个特殊的函数
      2. 一个类只能拥有一个名为constructor 的构造方法,如果没有显式的定义一个构造方法,则会添加一个默认的constructor 方法
      3. 继承使用extends 关键字
      4. 一个构造器可以使用super 关键字来调用一个父类的构造函数
      5. 类没有私有属性。

         测试:

     1 // 基类定义
     2 class Point {
     3     constructor(x, y) /*构造器 */{
     4         this.name = x
     5         this.age = y
     6     }
     7     show() /* 方法 */ {
     8         console.log(this.name, this.age)
     9     }
    10 }
    11 
    12 
    13 let p1 = new Point('tom', 12)
    14 p1.show()
    15 console.log(p1) // 可以看到对象的属性
    16 
    17 //继承
    18 class Point3D extends Point {
    19     constructor (a,b,c) {
    20         console.log('---------------------------')
    21         super(a, b)
    22         this.password = c
    23     }
    24 }
    25 
    26 let p2 = new Point3D('jack',18,'123456')
    27 p2.show()
    28 console.log(p2)

         结果

    1 Info: Start process (20:11:33)
    2 tom 12
    3 Point { name: 'tom', age: 12 }
    4 ---------------------------
    5 jack 18
    6 Point3D { name: 'jack', age: 18, password: '123456' }
    7 Info: End process (20:11:33)

       重写方法:

         子类Point3D 的show方法,需要重写

         

         子类中直接重写父类的方法即可

        如果需要使用父类的方法,使用super.method() 的方式调用

        使用箭头函数重写上面的方法   

     1 // 基类定义
     2 class Point {
     3     constructor(x, y) /*构造器 */{
     4         this.name = x
     5         this.age = y
     6         // this.show =  function () {console.log(this.name, this.age)}
     7         this.show = () => console.log(this.name, this.age)
     8     }
     9 
    10 }
    11 
    12 
    13 let p1 = new Point('tom', 12)
    14 console.log(p1.show())
    15 console.log(p1) // 可以看到对象的属性
    16 
    17 //继承
    18 class Point3D extends Point {
    19     constructor (a,b,c) {
    20         console.log('---------------------------')
    21         super(a, b)
    22         this.password = c
    23         // this.show = function () {console.log(this, this.name, this.age, this.password)}
    24         this.show = () => console.log(this, this.name, this.age, this.password)
    25     }
    26 }
    27 
    28 let p2 = new Point3D('jack',18,'123456')
    29 p2.show()
    30 console.log(p2)

          结果:从运行结果看,箭头函数也支持子类的覆盖

    1 Info: Start process (20:24:52)
    2 tom 12
    3 undefined
    4 Point { name: 'tom', age: 12, show: [Function] }
    5 ---------------------------
    6 Point3D { name: 'jack', age: 18, show: [Function], password: '123456' } 'jack' 18 '123456'
    7 Point3D { name: 'jack', age: 18, show: [Function], password: '123456' }
    8 Info: End process (20:24:53)

        测试:shou方法的调用次序

     1 // 基类定义
     2 class Point {
     3     constructor(x, y) /*构造器 */{
     4         this.name = x
     5         this.age = y
     6         // this.show =  function () {console.log(this.name, this.age)}
     7         // this.show = () => console.log(this.name, this.age,'===1')
     8     }
     9     show() {console.log(this.name, this.age,'===2')}
    10 
    11 
    12 }
    13 
    14 let p1 = new Point('tom', 12)
    15 console.log(p1.show())
    16 console.log(p1) // 可以看到对象的属性
    17 
    18 //继承
    19 class Point3D extends Point {
    20     constructor (a,b,c) {
    21         console.log('---------------------------')
    22         super(a, b)
    23         this.password = c
    24         // this.show = function () {console.log(this, this.name, this.age, this.password)}
    25         // this.show = () => console.log(this, this.name, this.age, this.password,'===3')
    26     }
    27     // show(){console.log(this, this.name, this.age, this.password,'===4')}
    28 
    29 }
    30 
    31 let p2 = new Point3D('jack',18,'123456')
    32 p2.show()
    33 console.log(p2)

        通过测试,p2.show() 先调用自己类的对象 show,再 到父类的对象的show,在自己所属类的show在到父类的show

       静态属性:

        静态属性目前还没有很好的支持

      静态方法;

        在方法名前加上 static ,就是静态方法   

     1 class Add{
     2     constructor(x, y) {
     3         this.x = x;
     4         this.y =y;
     5     }
     6     static point() {
     7         console.log(this.x)
     8     }
     9 }
    10 
    11 add = new Add(20,40)
    12 console.log(Add)
    13 Add.point()
    14 //add.point() 实例不能直接访问惊天方法,java 和C++ 一样
    15 add.constructor.point();// 对象通过 constructor 访问静态方法

      结果:

    [Function: Add]
    undefined
    undefined

        静态方法中的this 是Add类, 不是Add的实例

        注:静态的概念不同于python的静态

      this 的坑

        虽然JS 和C++ java 一样有this,但是JS 的变现是不同的

        原因在于c++ java 是静态编译语言,this是编译期间绑定,而js 是动态,运行期绑定   

        * 普通函数调用, this就是全局对象

        测试

        

        前提:

          函数执行的时候,会开启新的执行上下文环境ExecutionContext

          创建this 属性,但是this 是什么 就要看函数怎么调用。

      1. myFunction(1,2,3)普通函数调用方式,this 指向全局对象 ,全局对象是node.js的global或者浏览器中的window
      2. myObject.myFunction(1,2,3) 对象方法的调用方式,this指向包含该方法的对象
      3. call 和apply 方法调用,要看第一个参数是谁

        分析上例:

            

        解决方式 1:显式传入

          

          通过主动传入对象,这样就避开了 this 问题

        解决方式2: ES3(ES-262第三版),引入了apply,call方法

          

            apply,call方法都是函数对象的方法,第一参数都是传入对象引入的

            

            apply 传其他参数需要使用数组

            call 传其他参数需要使用可变参数收集

            

        解决方式 3 ES5引入了bind方法       

          

      

       解决方式 4:ES6 支持this 箭头函数

          ES6 新技术,就不需要兼容this 问题

          

          ES6 新的定义方式如下;

            

          最常用的就是bind()

    7、高阶对象,高阶类,或称为Mixin模式

      Mixin模式。混合模式,这是一种不用继承 就可以 复用的技术,主要还是为了解决多重继承的问题,

      多继承的继承路径是个问题

      JS 是基于对象,类,和对象都是对象模板

      混合Mixin 指的是,将一个对象的全部或者部分拷贝到另一个对象上去,其实就是属性了

      可以将多个类或者对象混合成一个类或对象

      继承的实现:

        先看一个继承实现的例子:

          

        父类构造函数中,要求具有属性 stringify 的序列化函数,如果没有则抛出异常      

     1 class Serillization {
     2     constructor(){
     3         console.log('serialization constructor ------')
     4         if (typeof(this.stringify) !== 'function') {
     5             throw new ReferenceError('should define stringify')
     6         }
     7     }
     8 }
     9 
    10 class Point extends Serillization {
    11     constructor(x, y) {
    12         console.log('point constructor -------')
    13         super();// 继承必须调用 super()
    14         this.x = x
    15         this.y = y
    16     }
    17     stringify() {
    18         return `<Point x=${this.x}, y=${this.y}>`
    19     }
    20 }
    21 
    22 class Point3D extends Point{
    23     constructor(x, y, z){
    24         super(x, y)
    25         this.z = z
    26     }
    27     stringify (){
    28         return `<Point x=${this.x}, y=${this.y}, z=${this.z}>`
    29     }
    30 }
    31 
    32 p = new Point(4,5)
    33 console.log(p.stringify())
    34 p3d = new Point3D(7,8,9)
    35 console.log(p3d.stringify())

        结果:  

    1 Info: Start process (21:53:17)
    2 point constructor -------
    3 serialization constructor ------
    4 <Point x=4, y=5>
    5 point constructor -------
    6 serialization constructor ------
    7 <Point x=7, y=8, z=9>
    8 Info: End process (21:53:18)

       高阶对象的实现:

          将类的继承构建成箭头函数  

     1 // 普通的继承
     2 class A extends Object{}; // 大写O
     3 console.log(A)
     4 
     5 // 匿名类
     6 const A1 = class {
     7     constructor(x) {
     8         this.x = x
     9     }
    10 }
    11 
    12 console.log(A1)
    13 console.log(new A1(100).x)
    14 
    15 console.log('--------------------------------------------')
    16 
    17 // 匿名类继承
    18 const B = class extends Object { // 这里返回的是一个类
    19     constructor(){
    20         super()
    21         console.log('B constructor')
    22     }
    23 }
    24 console.log(B)
    25 b = new B()
    26 console.log(b) // B {}     B 是?
    27 
    28 
    29 console.log('--------------------------------------------')
    30 const C = Sup => class extends Sup { // 这里返回的是一个函数
    31     constructor(){
    32         super()
    33         console.log('C constructor')
    34     }
    35 }
    36 
    37 
    38 
    39 cls = new C(Object) // 不可以new 因为返回的是一个普通函数
    40 
    41 
    42 obj2 = new (C(Object))()
    43 
    44 cls = C(Object) // 返回来,调用一次,才能用// 返回一个类 
    45 obj = new cls()
    46 console.log(obj)
    47 
    48 // cls = C(A)
    49 // console.log(cls)
    50 // c = new cls()
    51 // console.log(c)
    52 
    53 // c1 = new (C(Object))()

        改造上面序列化的例子:

           

     1 const Serialication = Sup => class extends Sup{
     2     constructor(...args) {
     3         console.log('seroalization ------')
     4         super(...args)
     5         if (typeof(this.stringify) !== 'function') {
     6             throw new ReferenceError('should define stringify')
     7         }
     8     }
     9 }
    10 
    11 class Point {
    12     constructor(x, y) {
    13         console.log('point constructor -------')
    14         this.x = x
    15         this.y = y
    16     }
    17 }
    18 
    19 class Point3D extends Serialication(Point){
    20     constructor(x, y, z){
    21         super(x, y) // super 是 Serialication(Point) 包装过的新类型
    22         this.z = z
    23     }
    24     stringify (){
    25         return `<Point x=${this.x}, y=${this.y}, z=${this.z}>`
    26     }
    27 }
    28 
    29 let p3d = new Point3D(70,80,90)
    30 console.log(p3d.stringify())
    代码
    为什么要坚持,想一想当初!
  • 相关阅读:
    Spring 中的邮件任务
    Spring 定时任务
    java中同步交互 与 异步交互
    Springboot 版本包冲突
    Derby 配置环境变量
    Springboot中的Web服务Tomcat改为Jetty
    二叉树中和为某一值的路径
    0-Java中this和super的用法总结
    树9:二叉搜索树的后序遍历
    位运算-输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9971411.html
Copyright © 2011-2022 走看看