JS原型和原型链

通过今天一天的学习,让我对Javascript的认识从陌生到熟悉,其中我很难理解的是原型和原型链,看了很多资料终于理解了,下面是我的总结。
为什么会有原型呢?
这是因为JavaScript 没有类,但 JavaScript 是面向对象的语言。JavaScript 只有对象,对象就是对象,不是类的实例。因为绝大多数面向对象语言中的对象都是基于类的,所以经常有人混淆类的实例与对象的概念。对象就是类的实例,这在大多数语言中都没错,但在 JavaScript 中却不适用。JavaScript 中的对象是基于原型的,打个比方来说,基于类的语言中类就像一个模具,对象由这个模具浇注产生,而基于原型的语言中,原型就好像是一件艺术品的原件,我们通过一台 100% 精确的机器把这个原件复制出很多份。
什么是原型?
在JavaScript 中,每当定义一个对象(函数)时候,对象中都会包含一些预定义的属性。其中函数对象的一个属性就是原型对象 prototype。
下面通过一段代码使用原型初始化对象:

function Person() {
    Person.prototype.name = 'BYVoid';
    Person.prototype.showName = function () {
        console.log(this.name);
    }
};
var person = new Person();
person.showName();     //BYVoid

与构造函数内定义属性不同:
构造函数内定义的属性继承方式与原型不同,子对象需要显式调用父对象才能继承构造函数内定义的属性。
构造函数内定义的任何属性,包括函数在内都会被重复创建,同一个构造函数产生的两个对象不共享实例。
构造函数内定义的函数有运行时闭包的开销,因为构造函数内的局部变量对其中定义的函数来说也是可见的。

function Foo() {
    var innerVar = 'hello';
    this.prop1 = 'BYVoid';
    this.func1 = function(){
        innerVar = '';
    };
}
Foo.prototype.prop2 = 'Carbo';
Foo.prototype.func2 = function () {
    console.log(this.prop2);
};
var foo1 = new Foo();
var foo2 = new Foo();
console.log(foo1.func1 == foo2.func1); // 输出 false
console.log(foo1.func2 == foo2.func2); // 输出 true

尽管如此,并不是说在构造函数内创建属性不好,而是两者各有适合的范围。那么我们
什么时候使用原型,什么时候使用构造函数内定义来创建属性呢?

  • 除非必须用构造函数闭包,否则尽量用原型定义成员函数,因为这样可以减少开销。
  • 尽量在构造函数内定义一般成员,尤其是对象或数组,因为用原型定义的成员是多个实例共享的。

什么是原型链?
在 JavaScript 中,继承是依靠一套叫做原型链(prototype chain)的机制实现的。属性继承的本质就是一个对象可以访问到它的原型链上任何一个原型对象的属性。
JavaScript 中有两个特殊的对象: Object 与 Function,它们都是构造函数,用于生成对象。Object.prototype 是所有对象的祖先,Function.prototype 是所有函数的原型,包括构造函数。我把 JavaScript 中的对象分为三类,一类是用户创建的对象,一类是构
造函数对象,一类是原型对象。用户创建的对象,即用 new 语句显式构造的对象。构造函数对象指的是普通的构造函数,即通过 new 调用生成普通对象的函数。原型对象特指构造函数 prototype 属性指向的对象。这三类对象中每一类都有一个 proto 属性,它指向该对象的原型,从任何对象沿着它开始遍历都可以追溯到 Object.prototype。构造函数对象有 prototype 属性,指向一个原型对象,通过该构造函数创建对象时,被创建对象的 proto 属性将会指向构造函数的 prototype 属性。原型对象有 constructor属性,指向它对应的构造函数。

function Foo() {
}
Object.prototype.name = 'My Object';
Foo.prototype.name = 'Bar';
var obj = new Object();
var foo = new Foo();
console.log(obj.name); // 输出 My Object
console.log(foo.name); // 输出 Bar
console.log(foo.__proto__.name); // 输出 Bar
console.log(foo.__proto__.__proto__.name); // 输出 My Object
console.log(foo. __proto__.constructor.prototype.name); // 输出 Bar

上面的代码是不是没怎么看懂,下面通过结构图就能看懂了:
这里写图片描述

上例的foo 对象,它拥有 foo. proto 和 foo. proto.proto所有属性的浅拷贝(只复制基本数据类型,不复制对象)。所以可以直接访问foo.constructor(来自foo.proto,即Foo.prototype),foo.toString(来自foo. proto.proto,即Object.prototype)。
总结
1.原型和原型链是JS实现继承的一种模型。
2.原型链的形成是真正是靠proto 而非prototype

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值