js面向对象编程/原型链/继承 —— javascript

  • 2022-10-04 11:38:52

目录

 

js面向对象编程

js面向对象编程不同于 java 的类和对象

javascript 不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。

js声明的构造函数,类似于普通函数的声明,但又不同,

实例对象时,如果不写new,就是一个普通函数,它返回 undefined。

但是,如果写了new,它就变成了一个构造函数,它绑定的 this 指向新创建的对象,

并默认返回 this,也就是说,不需要在最后写return this;。

 

js原型链

 代码段一:

function student(name){
    this.name = name;
    this.say = function(){
        console.log('my name:', this.name);
    }
}

let student1 = new student('student1');
let student2 = new student('student2');

js面向对象编程/原型链/继承 —— javascript

console.log(student1.constructor === student.prototype.constructor)        // true 

橙色箭头表示原型链,其原型链为:

student1 --> student.prototype --> object.prototype --> null

当我们用 obj.xx 访问一个对象的属性时,javascript引擎先在当前对象上查找该属性,

如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到object.prototype对象,

最后,如果还没有找到,就只能返回undefined

 

共享方法

代码段二:

function student2(){
    this.say = function(){
        console.log('hi')
    }
}
console.log(new student2().say === new student2().say)

 结果:

false

实例化的对象方法,虽然方法名称和代码完全一样,但是不同对象指向的不是同一个方法

需要创建一个共享的方法,

根据原型链图,需要将这个共享方法声明在 student2 的原型对象上,

xxx.prototype.xxx = function(){}

function student2(){
    this.say = function(){
        console.log('hi')
    }
}

student2.prototype.publicsay = function(){
    console.log('public say');
}

console.log(new student2().say === new student2().say)
console.log(new student2().publicsay === new student2().publicsay)

 结果:

false
true

 

原型继承

学过 java 的都知道,类的继承通过 extends 会很容易实现,

但是 javascript原型继承有点麻烦,不过 class继承就很方便

function father(name){
    this.say = function(){
        console.log(name)
    }
}
function son(name){
    father.call(this, name)
}

console.log(son.prototype.__proto__)   // object

这样看似继承了,但是其原型链的指向并没有改变

其原型链图为:

js面向对象编程/原型链/继承 —— javascript

要实现原型继承,看图的话很容易,只需要将 son 的原型对象的原型指向 father 的原型对象

 js面向对象编程/原型链/继承 —— javascript

要实现原型继承,这里有三种方法,

 法一:

这个方法简介明了,但是不推荐直接通过 __proto__ 直接改变原型

function father(name){
    this.say = function(){
        console.log(name)
    }
}
function son(name){
    father.call(this, name)
}

son.prototype.__proto__ = father.prototype;
console.log(son.prototype.__proto__)    // father

 

法二:

通过实例化 father 生成一个对象,

new father() 的原型会默认指向 father 的原型

通过修改 sonprototype 属性和 new father()constructor 属性,

来绑定 sonnew father() 之间的关系

js面向对象编程/原型链/继承 —— javascript

function father(name){
    this.say = function(){
        console.log(name)
    }
}
function son(name){
    father.call(this, name)
}

son.prototype = new father();
son.prototype.constructor = son;

console.log(son.prototype.__proto__)    // father

 

法三:

 类似法二,声明一个中间对象来改变指向

js面向对象编程/原型链/继承 —— javascript

mid.prototype = father.prototype;
son.prototype = new mid();
son.prototype.constructor = son;

第一步,将 mid 的原型对象指向 father 的原型对象,

第二步,将 son 的属性 prototype 指向 mid

  此时代码上的 new mid(),实际上是 new father()

第三步,将 son.prototype.constructor 也就是 mid.prototype.constructor 指向 son

js面向对象编程/原型链/继承 —— javascript

看起来有点乱,看数字步骤,方便理解

function father(name){
    this.say = function(){
        console.log(name)
    }
}
function son(name){
    father.call(this, name)
}

mid.prototype = father.prototype;
son.prototype = new mid();
son.prototype.constructor = son;

console.log(son.prototype.__proto__)  // father

class继承

es6 提供了关键字 class,定义类变得更便捷

共享方法

class father{
    // 构造方法
    constructor(name){
        this.name = name;
    }
    hello(){
        console.log("hello", this.name)
    }
}

console.log(new father("f").hello === new father("f").hello)
// true,共享方法

class继承

class father{
    // 构造方法
    constructor(name){
        this.name = name;
    }
    hello(){
        console.log("hello", this.name)
    }
}

class son extends father{
    constructor(name){
        super(name);
    }
}

console.log(son.prototype.__proto__)    // father

 

猜你喜欢