ES5继承
对象上的方法
公有属性/方法
设置给实例对象的属性和方法被称作公有属性和公有方法
私有属性/方法
声明在构造函数中的变量或函数,被称作为私有属性和私有方法
静态属性/方法
js中无需实例化就可以调用的方法或属性叫做静态方法和静态属性
特权方法
在构造函数中给实例对象绑定的方法被称为特权方法
示例
function Car(color,speed){
// 私有属性
let num = 0
// 私有方法
function fn(){
console.log("fn")
}
// 公有属性---这个属性是设置给所有实例化对象的
this.color = color
this.speed = speed
// 特权方法---在构造函数中给实例化对象设置的方法被称为特权方法
this.getColor = function(){
console.log("特权方法")
}
}
// 公有方法---这个方法是设置给所有实例化对象的
Car.prototype.run = function(){
console.log("驾");
}
// 静态属性/静态方法---就是简单的把Car当做一个对象(函数对象),扩展的属性和方法
Car.title = "造车"
Car.do = function(){
console.log("doit");
}
继承
当一个对象能够使用另一个对象的属性和方法的时候,被称为继承
简单继承
let obj = {
name:"rolls",
do:function(){
console.log("ghost")
}
}
let obj1 = Object.create(obj)
obj1.name = "G63"
// obj1可以使用obj的属性和方法,称为继承
console.log(obj1,obj)
// { name: 'G63' } { name: 'rolls', do: [Function: do] }
console.log(obj1.name)
// G63
借用构造函数继承
- 只能继承构造函数中添加的属性和方法
- 思路
1.定义父类构造函数
2.定义子类构造函数
3.在子类型构造函数中调用父类型构造(call)
// 封装一个父类
function Animal(name,age){
this.name = name
this.age = age
}
Animal.prototype.say = function(){
console.log("吼吼吼")
}
// 封装一个子类
function Cat(color,name,age){
/*
本来Animal的this指向的是Animal的实例对象
现在让Animal的this指向Cat的实例对象,并且才传参给Animal
*/
Animal.call(this,name,age)
this.color = color
}
Cat.prototype.do = function(){
console.log("玩红外线")
}
let cat1 = new Cat("white","baozi",2)
let cat2 = new Cat("coffce","wanan",3)
console.log(cat1,cat2);
// Cat { name: 'baozi', age: 2, color: 'white' }
// Cat { name: 'wanan', age: 3, color: 'coffce' }
// cat1.say()
// cat2.say()
// cat1.say is not a function
cat1.test() // 456
cat2.test() // 456
原型链继承
- 只能继承原型对象上的方法
- 思路
1.定义父类型构造函数
2.给父类型的原型添加方法
3.定义子类型的构造函数
4.创建父类型的对象赋值给子类型的原型
5.将子类型原型的构造函数属性设置为子类型
6.给子类型原型添加方法
7.创建子类型的对象:可以调用父类型的方法
8.子类型的原型为父类型的一个实例对象
function Animal(name, age) {
this.name = name;
this.age = age;
}
Animal.prototype.say = function () {
console.log("吼~")
}
function Cat(color, name, age) {
this.color = color;
}
/*
Cat的实例化对象想要使用Animal的原型对象上的方法,需要修改Cat的原型链
千万不要把Animal的原型对象直接赋值给Cat的原型对象,否则修改Cat Animal也修改了,因为赋值是地址值的赋值
Cat.prototype = Animal.prototype;
*/
//再次考虑,还有谁可以访问Animal的原型对象?Animal的实例化对象
//把父类的实例化对象 赋值给 子类的原型对象 此时可以实现原型链继承
Cat.prototype = new Animal();
//如果重新设置了原型对象,那么新的原型对象的constructor就可能出问题
//为了保证程序合理,要把constructor指向修改正确
Cat.prototype.constructor = Cat; //修正constructor
Cat.prototype.do = function () {
console.log("玩红外线");
}
var cat1 = new Cat("white");
console.log(cat1)
// Cat { color: 'white' }
cat1.say()
// 吼
console.log(cat1.constructor)
// [Function: Cat]
console.log(Cat.prototype.constructor)
// [Function: Cat]
原型链+构造函数继承
function Animal(name, age) {
this.name = name;
this.age = age;
}
Animal.prototype.say = function () {
console.log("吼~")
}
function Cat(color, name, age) {
this.color = color;
// 构造函数继承
Animal.call(this,name,age)
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
Cat.prototype.do = function () {
console.log("玩红外线");
}
var cat1 = new Cat("white","wanan",2);
console.log(cat1)
// Cat { color: 'white', name: 'wanan', age: 2 }
cat1.say()
// 吼
console.log(cat1.constructor)
// [Function: Cat]
console.log(Cat.prototype.constructor)
// [Function: Cat]
ES6 class
class
class Person{
/*
当new的时候,会自动调用constructor这个方法,必须存在(书写公有属性)
书写在构造函数中的属性 都放在了constructor
*/
constructor(name,age){
this.name = name
this.age = age
}
// 直接书写在class中的方法 其实就是原型对象上的公有方法
eat(){
console.log("吃饭")
}
// 如果直接在class中书写属性,则还是实例化对象所有的(这样写无法传参)
sex = "男"
// static 定义的属性和方法其实都是静态属性和方法 是构造函数上的
static hi = "hello"
}
// 也可以通过原型对象扩展原型方法
Person.prototype.drink = function(){
console.log("大乌苏")
}
const p1 = new Person("laowang",20)
const p2 = new Person("xiaowang",10)
console.log(p1,p2)
// Person { sex: '男', name: 'laowang', age: 20 }
// Person { sex: '男', name: 'xiaowang', age: 10 }
console.log(p1.eat === p2.eat)
// true
console.dir(Person)
// [class Person] { hi: 'hello' }
extends
- ES6中继承的子类中,如果使用构造函数constructor()那么就必须使用super()方法初始化,这样下面才可以调用this关键字。super()只能用在子类的构造函数之中,用在其他地方就会报错,这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
eat() {
console.log("吃饭")
}
sex = "男"
static hi = "hello"
}
Person.prototype.drink = function () {
console.log("大乌苏")
}
// 定义一个Student类 继承 Person类
class Student extends Person {
constructor(project, name, age) {
super(name,age)
this.project = project
}
study(){
console.log("我最喜欢ES6了");
}
}
const s1 = new Student("nodejs","xiaozhang",19)
console.log(s1)
// Student { sex: '男', name: 'xiaozhang', age: 19, project: 'nodejs' }
s1.eat()
// 吃饭