JavaScript学习系列之初识原型继承和原型链

我们将JavaScript对象分为函数对象和普通对象。

函数对象

用function关键字定义的对象或者对其使用typeof运算符返回"function"的对象。

  • JavaScript引擎内置的函数对象(构造器)
typeof Array//"function"
typeof Number//"function"
typeof Boolean//"function"
typeof String//"function"
typeof Object//"function"
typeof Function//"function"
  • 自定义的函数对象
function Animal(name){
    this.name = name;
}
typeof Animal//"function"
普通对象

除了函数对象之外的其他对象都是普通对象。一般是大括号{}定义的对象或者new关键字返回的对象。

typeof new Array();//"object"
typeof new String();//"object"
typeof {};//"object"
function Animal(name){
    this.name = name;
}
typeof new Animal('kitty');//"object"
函数对象与普通对象的异同
  • 相同点
    1. 它们都是JavaScript中的的对象
    2. 它们都有一个默认的__proto__属性(原型链的关键,后面详细解释)。
  • 不同点
    1. 创建方式不同。函数对象需要用function关键字去定义。而普通对象一般由{}或new关键字来创建。
    2. 函数对象实际上是对象构造器,可以new一个函数对象返回一个普通对象。
    3. 对函数对象使用typeof运算符会返回function,而对普通对象使用的话返回object。
    4. 每一个函数对象都有一个原型对象(prototype)与之关联,而普通对象没有。

1.对象的prototype属性

原型对象只有函数对象才有,普通对象一般是没有的。且每一个函数对象都有一个原型对象(prototype)与之相关联,一些常用的方法都保存在函数的原型对象中。如Array.prototype中就包含一些数组中常用的concat()、push()…等方法。我们首先需明确,原型对象本身是一个普通对象。
要注意的一点是,函数的原型对象除包含一些对象的公有方法之外,它还包含一个constructor属性,它指向与原型对象相关联的函数对象。

  • JavaScript引擎内置的函数对象(构造器)
console.log(Array.prototype);//输出对应的原型对象,包含数组的常用方法。
console.log(Array.prototype.constructor===Array);//true
console.log(String.prototype.constructor===String);//true
  • 自定义的函数对象
function Animal(name){
    this.name = name;
}
Animal.prototype.getName = function(){
    return this.name;
}
typeof Animal//"function"
console.log(Animal.prototype.constructor===Animal);//true

2.对象的__proto__属性

当我们访问普通对象的属性object.xxx时,如果object自己没有xxx属性,则向上延原型链查找,如果找到,则返回,没找到,则返回undefined。原型链通过什么来实现这种向上查找呢?没错,就是__proto__属性。
每一个对象都有__proto__属性,它在对象创建时默认存在,但一般我们都不去使用或者改变它。
#### 函数对象与其__proto__属性
所有函数(构造器)的__proto__都指向Function.prototype,它是一个空函数(Empty function)。

Array.__proto__===Function.prototype//true
Number.__proto__===Function.prototype//true
String.__proto__===Function.prototype//true
...
普通对象与其__proto__属性

普通对象的__proto__指向函数对象(构造器)的原型对象(prototype)。
JavaScript引擎的内置构造函数生成的对象

var obj = {name: 'tea'};//相当于new Object(obj)
var array = [1,2,3];//相当于new Array(1,2,3)
var reg = /hello/g;//相当于new RegExp('hello','g');
var date = new Date();
var err = new Error('exception');
 
console.log(obj.__proto__ === Object.prototype) // true
console.log(array.__proto__ === Array.prototype)  // true
console.log(reg.__proto__ === RegExp.prototype) // true
console.log(date.__proto__ === Date.prototype)  // true
console.log(err.__proto__ === Error.prototype)  // true

自定义构造函数生成的对象

function Person(name) {
    this.name = name
}
var p = new Person('jack')
console.log(p.__proto__ === Person.prototype) // true

3.原型继承

要想理解JavaScript的继承,必须先区分实例与构造器的区别。首先,实例对象是普通对象,而构造器是函数对象。

function Person(name) {
    this.name = name
}
var p = new Person('jack')

Person是构造器,也就是函数对象,它具有Person.prototype原型对象与之对应,它的__proto__属性值为Function.prototype。而p是实例,它是普通对象且没有原型,它的__proto__属性值为Person.prototype。
想要实现继承,最简单的方法就是让子类的原型指向父类的实例。

function Animal(name){
    this.name = name;
}
Animal.prototype.getName = function(){
    return this.name;
}
function Dog(name){
    this.name = name;
}
Dog.prototype = new Animal('test');

var animal = new Animal('animal');
var dog = new Dog('dog');
console.log(animal.getName());//输出animal
console.log(dog.getName());//输出dog

4.原型链

在了解上述各种属性之后,我们来看一个关于原型链的图。
这里写图片描述
当在对象的域中没有找到我们想要的属性时,js引擎会访问_proto__指针指向的对象,并从中寻找要访问的属性,若找到,则返回属性。若没有找到,则继续访问当前__proto__指向的对象。以此类推,直到访问到Object.prototype.__proto__指向的对象(空对象)才停止。最后都没找到的话返回undefined。
所以真正形成原型链的是是每个对象的__proto__属性,而不是函数的prototype属性

接下来,我们看一下3中继承的例子的原型链是怎样的。
这里写图片描述
从图中可以知道

var dog = new Dog();
dog.__proto__ === Dog.prototype;//true
Dog.prototype.__proto__ === Animal.prototype;//true
dog.constructor === Animal;

只要理解了javascript的两个基本指针(也就是__proto__和prototype)之后,理解javascript原型链也就不难了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值