原型与原型链学习小结

构造函数与原型

JavaScript为了看起来比较像java,再声明一个实例中也加入了new操作符

var obj = new f()

但是与java不同的是,JavaScript中的new操作符后面跟的并非类名而是函数名。

例如:

function dog() {
    this.name = "wangcai"
    this.bark = () => {
        console.log('wangwang~')
    }
}

var dog1 = new dog()
var dog2 = new dog()

上面就是JavaScript的一个构造函数,dog1,dog2分别是声明的dog实例。
但是上面有很大的问题每次创建一个实例,总是要重新创建bark函数,这无疑浪费了很多的空间,这个时候就引用了原型prototype.
先看一段原型的官方解释:

每一个构造函数都拥有一个prototype属性,这个属性指向一个对象,也就是原型对象。当使用这个构造函数创建实例的时候,prototype属性指向的原型对象就成为实例的原型对象。
原型对象默认拥有一个constructor属性,指向指向它的那个构造函数(也就是说构造函数和原型对象是互相指向的关系)。
每个对象都拥有一个隐藏的属性[[prototype]],指向它的原型对象,这个属性可以通过
Object.getPrototypeOf(obj) 或 obj.proto 来访问。
实际上,构造函数的prototype属性与它创建的实例对象的[[prototype]]属性指向的是同一个对象,即 对象.proto === 函数.prototype 。
如上文所述,原型对象就是用来存放实例中共有的那部分属性。
在JavaScript中,所有的对象都是由它的原型对象继承而来,反之,所有的对象都可以作为原型对象存在。
访问对象的属性时,JavaScript会首先在对象自身的属性内查找,若没有找到,则会跳转到该对象的原型对象中查找。

可以了解到原型是为了解决同一方法不同实例而出现的,把上面的代码进行改进一下。

function dog() {
    this.name = "wangcai"
}

Dog.prototype.bark = () => {
    console.log('wangwang~')
}

这样将实例中共有的属性放到原型对象中,让所有实例共享这部分属性。如果想要统一修改所有实例继承的属性,只需要直接修改原型对象中的属性即可。而且每个实例仍然可以重写原型中已经存在的属性来覆盖这个属性,并且不会影响到其他的实例。

原型链

JavaScript中所有的对象都是由它的原型对象继承而来。而原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,这就是原型链(prototype chain)
所有原型链的终点都是Object函数的prototype属性,因为在JavaScript中的对象都默认由Object()构造。Objec.prototype指向的原型对象同样拥有原型,不过它的原型是null,而null则没有原型。

例如继承就是由原型链衍生出来的:

// call继承
    // 特点:只能继承父的私有属性
    // Parent.call(this);
    function Parent() {  // 父类
        this.x = 100;
    }
    Parent.prototype.getX = function () { // 子类
        return this.x;
    }
    function Child() {
        // 1) 让this指向一个空对象
        // 2)this.xx = xx;
        // 3)返回这个空对象
        Parent.call(this);
        this.y = 200;
    }
    var c1 = new Child();
    console.log(c1.x);

这里利用了call改变了Parent的this指针,并成功调用了其方法,即时原型链的一种使用方式。
当然还有组合式继承等:

    // 组合式继承:
    //   1)Parent.call(this); // 继承父的私有属性
    //   2)Child.prototype = Object.create(Parent.prototype);  子类继承父类的公有属性
    function Parent() {  // 父类
        this.x = 100;
    }
    Parent.prototype.getX = function () { // 子类
        return this.x;
    }
    function Child() {
        Parent.call(this); // 继承父的私有属性
        this.y = 200;
    }
    // Child.prototype = Parent.prototype;  不好
    // 为什么?如果再你写了Child.prototype.xx = function(){}
    // 意味着父中也可以访问xx   说白了 子类可以影响父类
    // 想法:把Parent.prototype对象copy一份  让它俩的原型是彼此独立
    // Child.prototype = Parent.prototype;

    // 为了不影响父类的原型对象  copy一份赋值给了Child.prototype
    Child.prototype = Object.create(Parent.prototype);
    // 最好手动的修改一个Child原型对象上constructor指向
    Child.prototype.constructor = Child;  // 手动修改constructor的指向
    var c = new Child();
    console.log(c.x);
    console.log(c.getX())

结语

原型和原型链密不可分。只要理解prototype这一属性,并仔细掌握mdn上的其使用情形,相信不是太难。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
原型原型链JavaScript 中的重要概念,用于实现对象的继承和属性访问。 在 JavaScript 中,每个对象都有一个隐式的属性__proto__,它指向该对象的原型prototype)。原型是一个普通的对象,它包含共享的属性和方法。当我们访问一个对象的属性时,如果该对象本身没有该属性,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或到达原型链的末尾。 原型链就是这种沿着__proto__指针链进行属性查找的过程。一个对象的原型可以通过 Object.getPrototypeOf() 方法获取。 当我们创建一个新的对象时,可以使用构造函数或者字面量来创建。构造函数可以通过使用 new 关键字来创建新的对象,并且每个构造函数都有一个 prototype 属性,该属性指向新创建的对象的原型。字面量创建的对象的原型是 Object.prototype。 通过设置构造函数的 prototype 属性,我们可以实现对象之间的继承。子对象将继承父对象原型上的属性和方法。当我们访问子对象的属性时,如果子对象本身没有该属性,会沿着原型链向上查找。 需要注意的是,原型链是一个单向的链式结构,如果在原型链上层级相同的位置存在同名属性,那么只会返回第一个找到的属性值。 总结起来,原型原型链JavaScript 中实现对象继承和属性访问的重要机制,通过原型链,我们可以共享属性和方法,并且实现对象之间的继承关系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值