js原型和原型链

128 阅读4分钟

面向对象编程

面向对象

在java的世界里,一切皆为对象,对象则是一类事物的抽象统称,对象具有自己的属性和方法,状态及属性,行为及方法。

//简单的对象
const person ={
name:"张三",
age:"18",
eat:function(){
console.log('张三喜欢吃')
}
}
//js中的函数对象
function person(){
this.name='张三'
this.age=12
this.eat=function(){
console.log('张三喜欢吃')
}
}

构造函数生成对象

//构造函数生成对象,其实就是通过构造函数抽象出一个对象的模板然后通过实例化出对象,在es6中的class中也是此类的构造,其本质也是通过构造函数和原型对象的方式去创建对象,既  consturctor+prototype的方式
function Person(){
this.name='张三'
this.age=12
this.eat=function(){
console.log('张三喜欢吃')
}
}

//实例化构造函数 生成对象
const person=new Person()

注意:构造函数不能直接调用,或者作为普通函数使用

原因:

  1. this指向实例对象
  2. 生成的对象必须实例
  3. 初始化的时候可以传递参数 如果我们需要使用的时候,或者在编写底层api的时候需要的话,此时就用到了单例的设计模式去创建
function Person(){
//进行this实例的验证,如果存则返回如果不存在则创建
if(!this instanceof Person){
  return new Person() //创建实例并返回。
}
this.name='张三'
this.age=12
this.eat=function(){
console.log('张三喜欢吃')
}
}
//使用
const person = Person()

new 的创建过程

1.创建一个空对象,将它的引用赋给this,继承函数的原型
2.通过this将属性和方法添加至创建的空对象中
3.最后返回this指向的新对象,也就是实例

不同实例之间的属性是不进行数据共享的,当改变其中一个实例的属性或者方法的时候,其他实例的属性或者方法是不会去改变的。

constructor

constructor 名为构造器,是每个对象在创建的时候,自动拥有的构造函数的属性,constructor 继承自原型对象,指向构造函数

function   Person(){
this.name='test'
this.age=12
this.eat=function(){
console.log('测试')
}
}
const test = new Person() //实例化的时候会自动拥有一个constructor属性 指向的是Person构造函数

使用构造函数创建对象(缺点)

通过构造函数创建的对象 会拥有好多重复的属性或者方法 ,造成资源的浪费

function   Person(name){
this.name=name
this.age=12
this.eat=function(){
console.log('测试')
}
}
const test1 = new Person()
const test2 = new Person()
//在上面的例子中 test1和test2 创建出来的对象除了 名称不一样外,其他都一样  则会出现属性或者方法的重复造成资源的浪费


//在es5中可通过构造函数的原型对象实现,解决上述问题
function   Person(name){
this.name=name
}
Person.prototype.age=12
Person.prototype.eat=function(){
console.log('测试')
}
const test1 = new Person()
const test2 = new Person()
//es6
class Person{
constructor(name){
this.name=name
}
age=12
eat(){
console.log('测试')
}
}

原型对象

构造函数

用来初始化对象的函数。 构造函数的声明的时候,会自动的注入一个prototype属性,该属性等于实例对象的原型对象 实例.proto=构造函数.prototype

实例对象

由构造函数new出来的对象 每个实例对象都有一个__proto__指向构造函数的原型对象;每个实例对象都有一个constructor属性指向构造函数(继承而来)

原型对象

每个构造函数都有一个prototype属性指向 构造函数的原型对象

继承

原型链继承

缺点:创建的对象都共享属性和方法,单个对象没有自己私有属性

 function Game() {
        this.name = 'lol'
    }
    Game.prototype.getName = function() {
        return this.name;
    }
    // LOL类
    function LOL() {}
    LOL.prototype = new Game();
    LOL.prototype.constructor = LOL;
    const game = new LOL();
    // 本质:重写原型对象方式,将父对象的属性方法,作为子对象原型对象的属性和方法

构造函数继承

优点:解决了原型继承不能传参的问题 缺点:每一个对象中的值都是私有的,不存在共享属性或者方法,造成资源浪费

function Game(arg) {
        this.name = 'lol';
        this.skin = ['s'];
    }
    Game.prototype.getName = function() {
        return this.name;
    }

    // LOL类
    function LOL(arg) {
        Game.call(this, arg);
    }

    const game3 = new LOL('arg');
    // 解决了共享属性的问题 + 子向父传参问题

组合继承(原型+构造函数)

优点:实现了参数传递和数据共享 缺点:无论那种场景,父类的构造函数都会调用两次,一次是构造函数继承调用,一次是原型继承调用

 function Game(arg) {
        this.name = 'lol';
        this.skin = ['s'];
    }
    Game.prototype.getName = function() {
        return this.name;
    }

    // LOL类
    function LOL(arg) {
        Game.call(this, arg);
    }
    LOL.prototype = new Game();
    LOL.prototype.constructor = LOL;

    const game3 = new LOL();

寄生继承

优点:结局了组合继承父类构造函数调用两次的问题,通过原型指向的方式改变的

function Game(arg) {
        this.name = 'lol';
        this.skin = ['s'];
    }
    Game.prototype.getName = function() {
        return this.name;
    }

    // LOL类
    function LOL(arg) {
        Game.call(this, arg);
    }
    LOL.prototype = Object.create(Game.prototype); //通过原型创建对象 来改变LOL的原型对象指引
    LOL.prototype.constructor = LOL;
  

多重继承

    function Game(arg) {
        this.name = 'lol';
        this.skin = ['s'];
    }
    Game.prototype.getName = function() {
        return this.name;
    }

    function Store() {
        this.shop = 'steam';
    }
    Store.prototype.getPlatform = function() {
        return this.shop;
    }

    function LOL(arg) {
        Game.call(this, arg);
        Store.call(this, arg);
    }
    LOL.prototype = Object.create(Game.prototype); //通过原型创对象修改LOL的原型对象执行 改变LOL的原型指向
    Object.assign(LOL.prototype, Store.prototype);//通过对象合并的方式实现多重继承
    LOL.prototype.constructor = LOL;
    // LOL继承两类
    const game3 = new LOL();

原型链

image.png