构造函数,类,继承

98 阅读3分钟

构造函数

通过new关键字,也就是通过构造函数来创建对象。

Person.prototype==p.__proto__  // 构造函数的原型等于他实例的原型
/* 
每个实例都可以访问到其对应构造函数的原型,所以我们可以把实例共有的属性和方法
放到原型中,减少共有属性和方法的重复声明
构造函数只负责初始化
*/

function Person(options){
    this.name=options.name;
    this.age=options.age;
    this.sex=options.sex;
    this.init();
}
Person.prototype.init=function(){
  console.log("构造函数执行");
}
Person.prototype.say=function(){
  console.log("你好"+this.name);
}
var p=new Person({
    name:"小米",
    age:10,
    sex:"男"
});
p.say(); 

/*
当实例调用方法或属性中,先到this中找,再到原型链中找,最后是object
object.__proto__=null 结束
*/

判断某个属性是否是this的

// hasOwnProperty() 或 Object.hasOwnProperty(object,key)
p.hasOwnProperty("name")   // true
p.hasOwnProperty("init")   // false
p.hasOwnProperty("hasOwnProperty")   // false

Object.hasOwnProperty(p,key);    // 也可以判断

最后当你不需要使用对象时,设置为null,可以被GC回收

对于每个函数都有一个属性prototype,每个对象({},[])都有属性__proto__

new X()做了什么?

自动创建空对象 
自动为空对象关联原型,原型地址指定为 X.prototype 
自动将空对象作为 this 关键字运行构造函数 
自动 return this
每当创建一个实例的时候,就会创建一个新的内存空间(p1),创建 p1的时候,函数体内部的 this指向 p1

ES6中可以使用class定义对象了,可以看成是构造函数的语法糖

每个类中包含了一个特殊的方法 constructor(),它是类的构造函数,这种方法用于创建和初始化一个由 class 创建的对象。

class Person{
  constructor(options){
    this.name=options.name;
     this.age=options.age;
     this.sex=options.sex;
     this.init();
  }
}

// 方法还是定义再原型上
Object.assign(Person.prototype,{
  init(){
    console.log("构造函数执行");
  },
  say(){
    console.log("你好"+this.name);
  },
  toString(){
    return "";
  }
})
// 定义好类后,我们就可以使用 new 关键字来创建对象:创建对象时会自动调用构造函数方法 constructor()
var p=new Person({
    name:"小米",
    age:10,
    sex:"男"
});
p.say();  

继承

  1. 基于原型的继承
    子类型的原型为父类型的一个实例对象,子类继承父类的属性和方法是将父类的私有属性和公有方法都作为自己的公有属性和方法。这个继承方式是通过proto建立和子类之间的原型链,当子类的实例需要使用父类的属性和方法的时候,可以通过proto一级级向上找
function Animal(name) {
    this.name = name; 
}
Animal.prototype.eat= function () {
    console.log(this.name + '正在吃东西')
};
function Cat(color,call){ 
    this.color = color ;
    this.call = call
};
Cat.prototype = new Animal();
let tom = new Cat('black','miao');
tom.name = 'lucky';
console.log(tom)
  • 特点:
    父类新增原型方法/原型属性,子类都能访问到
    简单,易于实现
  • 缺点:
    无法实现多继承
    来自原型对象的所有属性被所有实例共享
    创建子类实例时,无法向父类构造函数传参
    要想为子类新增属性和方法,必须要在Student.prototype = new Person() 之后执行,不能放到构造器中
  1. 基于 class 的继承
    class可以通过extends关键字实现继承,还可以通过static关键字定义类的静态方法.实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

    class Person {
    //调用类的构造方法
    constructor(name, age) {
     this.name = name
     this.age = age
    }
    //定义一般的方法
    showName () {
     console.log("调用父类的方法")
     console.log(this.name, this.age);
    }
    }
    let p1 = new Person('kobe', 39)
    console.log(p1)
    //定义一个子类
    class Student extends Person {
    constructor(name, age, salary) {
     super(name, age)//通过super调用父类的构造方法
     this.salary = salary
    }
    showName () {//在子类自身定义方法
     console.log("调用子类的方法")
     console.log(this.name, this.age, this.salary);
    }
    }
    let s1 = new Student('wade', 38, 1000000000)
    console.log(s1)
    s1.showName()