几分钟带你理解原型链

目录

1 对象

2 原型

3 原型链

 

对象

讲到原型链,那么我们要先认识javascript里面的对象,那么什么是对象?

所谓万物皆对象,这句话是不是很抽象,抽象就对了,这是一个很广的概念;对象指的是一类具体的事物;里面封装了属性(property)和方法(method);

 

例如:

张三是一个对象,

那么张三的属性就有:身高、体重、肤色等等;

而对应的方法(或者是行为)就有:吃饭、睡觉、打豆豆等等

在程序员的世界里,万事万物我们都可以封装成为对象;了解到了对象,那么我们如何在代码中创建一个对象呢?

 

创建对象的三种方式

1.1 字面量形式创建

var hero = {

     name:'德玛西亚',

     attack:function(){}

}

 

1.2 new空构造形式创建

var hero = new Object();

hero.name = '德玛西亚';

hero.attack =function(){};

 

1.3 自定义构造函数

function Hero(name,attack){

     this.name= name;

     this.attack= attack;

}

var hero = newHero('德玛西亚',function(){});

 

1.4 使用构造函数与实例对象的关系

使用构造函数的好处不仅仅在于代码的简洁性,更重要的是我们可以识别对象的具体类型。

在每一个实例对象中同时有一个 constructor 属性,该属性指向创建该实例的构造函数:

 

 

var hero1 = new Hero('德玛西亚', function () { });

var hero2 = new Hero('德莱文', function () { });

console.log(hero1.constructor ===Hero);//true

console.log(hero2.constructor ===Hero);//true

console.log(hero1.constructor===hero2.constructor);//true

 

•   构造函数是根据具体的事物抽象出来的抽象模板

•   实例对象是根据抽象的构造函数模板得到的具体实例对象

•   每一个实例对象都具有一个 constructor 属性,指向创建该实例的构造函数

•   可以通过实例的 constructor 属性判断实例和构造函数之间的关系

 

了解到了构造函数与实例对象的关系后,下面我们来看原型

 

原型

为什么会有原型?

我们在使用构造函数的时候,一般都会声明方法,那么就会存在每次实例化一个对象的时候,都会为这些相同的方法创建一块内存区域去存储,这样就会导致内存的浪费;为了解决这个问题,就有了原型 prototype

原型与构造函数和示例对象的关系

 

•   任何函数都具有一个 prototype 属性,该属性是一个对象

•   构造函数的 prototype 对象默认都有一个 constructor 属性,指向 prototype 对象所在函数

•   通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 __proto__

•  所有实例都直接或间接继承了原型对象的成员

 

function Hero() {

//定义空的构造函数

}

  Hero.prototype.sayHi = function() {   

       console.log('你好');

}

var hero = new Hero();

hero.sayHi();

 

上面代码在Hero里面没有定义sayHi的方法,而是在Hero构造函数的prototype属性(得到的是原型对象)里定义的sayHi(),在调用的时候让实例对象进行的调用,那么输出结果如下:

 

 

原型链

什么是原型链?

方法和属性的搜索原则,用白话来讲,就是我们实例化对象在使用属性,或者调用方法的时候,系统是如何帮我们去查找的

 

如何去搜索的

•   搜索首先从对象实例本身开始,例如hero实例对象

•   如果在hero实例中找到了具有给定名字的属性,则返回该属性的值

•   如果没有找到,则继续搜索hero指针hero.__proto__指向的原型对象,在原型对象中查找具有给定名字的属性

•   如果在原型对象中找到了这个属性,则返回该属性的值,如果还没有找到,那么会从hero的原型对象里面的指针hero原型对象.__proto__上继续寻找

•   依次类推,一直向上找,当向上找到Object的原型的时候,这条原型链就算到头了

 

 

实例:

function Hero() {

//定义空的构造函数

}

//给原型对象定义方法

Hero.prototype.sayHi = function() {

    console.log('你好');

}

//在原型对象上定义属性

Hero.prototype.name = '我是一个英雄';

var hero = new Hero();

hero.sayHi();

console.log(hero.name);
 

输出结果如下:

 

 

 

注意事项

接着上面例子,不管创建多少个实例对象,如果构造函数里面没有定义属性和方法,是享有的原型对象的,那么它们获取的属性和方法都是同一个

function Hero() {

//定义空的构造函数

}

//给原型对象定义方法

Hero.prototype.sayHi = function() {

    console.log('你好');

}

//在原型对象上定义属性

Hero.prototype.name = '我是一个英雄';

//第一个对象

var hero = new Hero();

console.log('我是第一个创建的:' + hero.name);

hero.sayHi();

//第二个对象

var hero1 = new Hero();

console.log('我是第二个创建的:' + hero1.name);

hero1.sayHi();

输出结果

如果获取的属性或者是方法,通过原型链的寻找都没有找到,那么就会出现以下问题

实例代码

function Hero() {

//定义空的构造函数

}

var hero = new Hero();

console.log(hero.name);

hero.sayHi();

 

输出结果

 

 

如果获取的属性或者是方法,通过原型链的寻找都没有找到,那么就会出现以下问题

 

实例代码

function Hero() {

//定义空的构造函数

}

var hero = new Hero();

console.log(hero.name);

hero.sayHi();

 

输出结果

 

 

出现这个结果很好理解,name属性是我们自己定义的,通过原型链向上搜寻原则,找到Object的原型对象,里面还没有,那么就是undefined 未定义的;而方法不一样,当我们找到Object的原型对象,里面没有sayHi()方法,那么就会抛出异常,sayHi不是一个函数;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值