class类和构造函数

 

 

 

实例属性、静态方法和静态属性

 

 

 

extends

使用extends可以实现继承

可以改写继承到的属性或方法 同名覆盖

 

 

super

作为函数调用

作为对象使用

使用super的时候,必须显示指定作为函数还是作为对象使用

 

 

super 作为函数调用

 super 代表父类的构造方法,只能用在子类的构造方法中  内部的 this 指向子类的实例 

 

 

super 作为对象使用

 在构造方法和一般方法中使用  super 代表父类的原型对象

 通过 super 调用父类的方法时,方法的 this 指向当前的 子类实例 

 

 

 

 

super 作为对象使用

 在静态方法中使用  super 代表父类

 通过 super 调用父类的方法时,方法的 this 指向当前的 子类 

 

super 作为函数调用
当super 作为函数调用时, 它代表的指向的是父类的构造函数,在子类的构造函数必须执行一次 super 函数
也就是说,在子类继承父类中,如果super作为函数调用,只能写在子类的构造函数(constructor)里面,super代表的是父类的构造函数
class A {          // class关键字声明了一个类A
  constructor() {
  }
}

class B extends A { // class关键字声明了B继承自A类
  constructor() {   // constructor构造器函数
    super();        // 调用super()
  }
}

new A() // A
new B() // B
复制代码在上面的代码中,子类 B 的构造函数之中的super(),它代表调用父类的构造函数。这是必须的,否则 JavaScript 引擎会报错。
注意
super虽然代表了父类 A 的构造函数,但是返回的是子类 B 的实例,即 super 内部的 this 指的是 B 的实例
这里的super相当于 A 类的constructor构造函数,会执行 A 的constructor,但是此时的this指向的是 B,所以打印出 B
换一种理解是:在执行super时,A 把 constructor 方法给了 B,此时 B 有了 A 的功能,但是执行的是 B 的内容,也就是 es5 的A.prototype.constructor.call(this)
而作为函数调用:它必须只能在子类的构造器函数(constructor)中进行调用的,如果放在其他地方,则是会报错的,如下所示:
class A {}

class B extends A {
  fun() {
    super(); // 报错,super()不能放置在函数内调用
  }
}
复制代码在上面代码中,super()用在 B 类的fun方法之中,就会造成语法错误
super 作为对象使用
super作为对象使用时,分为在普通方法中使用和在静态方法中使用

普通方法使用:super指向父类的原型,即A.prototype,可以访问到原型上的方法和属性,也就是指向它父类的原型对象

class Animal {     // class关键字声明了一个Animal类
    constructor() {
    }
    parent(){  // 类Animal的一个方法
        console.log('我是父类Animal的普通方法... ...');
    }
}

class Dog extends Animal {   // class关键字定义了Dog继承自Animal类
    constructor() {
        super()
    }
   watchHome(){            // 子类watchHome为Dog的方法
       super.parent() // 我是父类的普通方法
       // 等价于Animal.prototype.parent() // // 我是父类的普通方法
   }
}
const dog = new Dog()
dog.watchHome()
复制代码在上面代码中,子类 Dog 当中的 super.parent(), 就是将 super 当做一个对象使用, 此时, super在普通方法之中, 指向A.prototype, 所以super.parent()就相当于 Animal.prototype.parent()
注意
由于 super 指向父类的原型对象, 所以定义在父类实例上的方法或属性, 是无法通过super 调用的
class Animal {
    constructor() {
        this.name = '父类上的实例上的属性'
    }
}

class Dog extends Animal {
   watchHome(){
       return super.name
   }
}
const dog = new Dog()
console.log(dog.watchHome()); // undefined,定义在父类实例上的属性, 无法通过super调用
复制代码在上面代码中 name 是父类Animal实例的属性, super.name 就引用不到它
但如果属性是定义在父类的原型对象上,super就可以取到,如下所示
class Animal {

}

Animal.prototype.name = 'super实例上的属性'

class Dog extends Animal {
    watchHome() {
        return super.name
    }
}

const dog = new Dog()
console.log(dog.watchHome()); // super实例上的属性,可以拿到父类中原型下的name属性,定义在原型下的属性和方法都是公有的
复制代码而在ES6中规定, 在子类普通方法中, 通过 super 调用父类的方法时, 方法内部的 this 指向当前子类的实例.
class A {
  constructor() {
    this.name = "itclanCoder";   // 定义在A类的私有属性
  }
  print() {   // 定义在A类的print私有方法
    console.log(this.name);
  }
}

class B extends A {  // 类B继承自类A
  constructor() {
    super();         // 调用父类的super
    this.name = "随笔川迹";     // 子类B的私有属性
  }
  m() {
    super.print();
  }
}

let b = new B();
b.m() // 随笔川迹

复制代码super.print()虽然调用的是A.prototype.print(),但是A.prototype.print()内部的this指向子类 B 的实例
导致输出的是"随笔川迹",而不是"itclanCoder"。也就是说,实际上执行的是super.print.call(this)
这个特性很有用,可以用于重写(覆盖)父类的私有属性
由于this此时指向子类实例,所以如果通过super对某个属性赋值,这时 super 就是 this,赋值的属性会变成子类实例的属性
class A {
  constructor() {
    this.name = "itclanCoder";
  }
}

class B extends A {
  constructor() {
    super();
    this.name = "itclan";     // 子类B的私有属性
    super.name = "川川";
    console.log(super.name);  // undefined,super是父类,而name是父类的私有属性,无法直接访问
    console.log(this.name);   // 川川
  }
}

let b = new B();
复制代码在上面面示例代码中,super.name赋值为"川川",这时等同于对this.name赋值为川川。而当读取super.name的时候,它读的是A.prototype.name,所以返回undefined

如果用在静态方法之中

如果 super作为对象,用在静态方法之中,这时super将指向父类 , 而不是父类的原型对象
class Parent {
    static myMethod(msg) {  // 父类的方法之前加静态static关键字
        console.log('static1', msg);
    }

    myMethod(msg) {            // 父类的私有普通方法
        console.log('instance2', msg);
    }
}

class Child extends Parent {  // 类child继承自篇Parent
    static myMethod(msg) {    // 子类的私有myMethod方法前声明static
        super.myMethod(msg); // super在静态方法中指向父类, 而不是父类的原型
    }

    myMethod(msg) {
        super.myMethod(msg); // super在普通方法中指向父类的原型
    }
}

Child.myMethod(1); // static1 1

var child = new Child();
child.myMethod(2); // instance2 2
复制代码上面代码中,super 在静态方法之中指向父类,在普通方法之中指向父类的原型对象
另外,在子类的静态方法中通过 super 调用父类的方法时,方法内部的 this 指向当前的子类而不是子类的实例
如下代码所示
class A {
  constructor() {
    this.x = 1;
  }
  static print() {
    console.log(this.x);
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
  }
  static m() {
    super.print();
  }
}

B.x = 3;
B.m() // 3
复制代码上面代码中,静态方法B.m里面,super.print指向父类的静态方法。这个方法里面的this指向的是 B,而不是 B 的实例
注意
当使用 super 的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错
class A {}

class B extends A {
  constructor() {
    super();
    console.log(super); // 报错
  }
}

复制代码在上面代码中,console.log(super)当中的super,是无法看出是作为函数使用,还是作为对象使用,所以 JavaScript 引擎解析代码的时候就会报错。这时,如果你能清晰地表明 super 的数据类型,就不会报错
class A {}

class B extends A {
  constructor() {
    super();
    console.log(super.valueOf() instanceof B); // true
  }
}

let b = new B();
复制代码在上面代码中,super.valueOf()表明 super 是一个对象,因此就不会报错。同时,由于 super 使得 this 指向 B 的实例,所以super.valueOf()返回的是一个 B 的实例
instanceof:的作用是A instanceof B,A 是否是由 B 实例化出来的,若是则为true,若不是则为false

 

 

new 构造函数

1 内存中创建一个新的空对象{}

2 让函数中的this指向空对象 this === {}

3 开始执行函数体  { age: 22 , name: "小明' }

4 返回该对象 (构造函数中不需要写return) 

 

自定义构造函数和简单工厂函数的对比

1.函授首字母大写用于区别构造函数和普通函数

2.创建对象的过程是由new关键字实现

3.在构造函数内部会自动的创建新对象,并赋值给this指针

4.自动返回创建出来的对象

function Person(name, age, sex) {
    // 1.自动创建一个空对象,把这个对象的地址 this --> 新对象
    // var this = new Object()
    
    // 2.this给空对象 绑定属性 和行为
    
    this.name = name
    this.age = age
    this.sex = sex
    
    // 3. 返回this
    // return this;
  }
  
  var p = new Person()


var obj = {name: "张三"}
console.log('obj.toString------', obj.toString()) // [object Object]

var arr = [1, 2, 3]
console.log('arr.toString()------', arr.toString()) // 1,2,3

 

 

 

 

 



in:检测某一个属性是否属于这个对象(attr in object),不管是私有的属性还是公有的属性,只有存在用in来检测都是true

// console.log(''getX'' in f1) // true 是它的一个属性

 

hasOwnProperty:用来检测某一个属性是否为这个对象的私有属性,这个方法只能检测私有的属性

(思考:检测一个属性是否为该对象的 '' 公有属性 '')

function hasPubProperty(attr, obj){

  // 首先保证是它的一个属性并且还不是私有的属性,那么只能是公有的属性了

  return (attr in obj) && (!obj.hasOwnProperty(attr))

}

posted @ 2019-02-15 15:03  慕斯undefined  阅读(210)  评论(0编辑  收藏  举报