新手理解的JS原型链

栏目: JavaScript · 发布时间: 5年前

内容简介:一直以来对于JavaScript 的原型链的概念,始终有些东西有一种模糊感,最近刚好有时间就塌下心认真的把《JavaScript高级程序设计》中相关内容认真读了一遍,也查看了很多网上很多资料,以前很多不明白的地方也渐渐明白了起来。写一篇文章记录一下最近学习的感悟。我们通常创建一个对象无非就两种方式:

一直以来对于JavaScript 的原型链的概念,始终有些东西有一种模糊感,最近刚好有时间就塌下心认真的把《JavaScript高级程序设计》中相关内容认真读了一遍,也查看了很多网上很多资料,以前很多不明白的地方也渐渐明白了起来。

写一篇文章记录一下最近学习的感悟。

字面量创建对象

我们通常创建一个对象无非就两种方式:

1. var obj= new Object();//new 一个Object的实例
 2. var obj= {};//对象字面量

使用对象字面量 和使用new的方式是一样的。

为了简便,一般推荐使用使用字面量: var o= {};

构造函数创建对象

当我们想要创建自定义的对象时,需要用到构造函数。

构造函数和普通函数有两个区别:

1. 便于和普通函数区分,函数名首字母大写。    
2. 使用 `new` 操作符调用,返回一个实例对象。

除此之外和普通函数一摸一样。

我们使用构造函数 Person 来创建两个实例对象:

function Person(name){
    this.name = name;
    this.sayName= function (){ alert(this.name) }
 }
var person1 = new Person('小明');
var person2 = new Person('小红');
console.log(person1);//{name: "小明", sayName: fun}
console.log(person2);//{name: "小红", sayName: fun}

上面的例子不难理解,虽然这两个实例对象都有 sayName 方法,而且他们两个的作用也是一样的,但却是两个方法,只是名字和作用一样。

画个图表示一下:

新手理解的JS原型链

如果还不明白,我在打个比喻:就像A街上有一间麦当劳,在B街上也开了一间麦当劳,它们都叫麦当劳,作用也是一样的。但是你总不能说他们是一间麦当劳吧?

person1.sayName === person2.sayName;//false

如果这样的话,我们每构造出来一个对象,都要单独为这个对象创建出一个专属于它自己使用的 sayName ,这是很占用内存的。

那我们能不能让所有的实例对象都共同使用一个 sayName 方法,来节省内存,提升效率呢?这需要我们先理解原型对象的概念。

原型对象

我们先了解原型对象的概念。

每个对象都有原型对象(null除外),我们用 __proto__ 表示,每个函数都有 prototype 属性,指向实例的原型对象。

对照这句话,按照我们上面的例子,也就是说 Person.prototype 指向 person1 的原型对象( __proto__ ),

Person.prototype === person1.__proto__; // true

为了便于理解,来看一张图。

新手理解的JS原型链

恩~他们的关系大概就是这样。

原型链

原型链简单用一句话概括就是:

原型链就是 对象的 __proto__ 所连接的链状结构

为了方便我们理解原型链,举一个简单的例子:

function F(){
    this.a = 1;
    this.b = 2;
}
F.prototype.b = 3;
F.prototype.c = 4;
var o = new F();// {a: 1, b: 2}
//原型链:
//o --> o.__proto__ --> o.__proto__.__proto__ --> null
// 其中的 --> 就表示 __proto__ 也就是原型链
console.log(o.a); // 1
// o上有a这个属性吗?有的,该属性的值为1

console.log(o.b); // 2
// o上有b这个属性吗?有的,该属性的值为2
// 原型上也有一个'b'属性,但是它不会被访问到.这种情况称为"属性遮蔽 "

console.log(o.c); // 4
// o上有c这个属性吗?没有,那看看原型上有没有
// o.__proto__上有c这个属性吗?有的,该属性的值为4

console.log(o.d); // undefined
// o上有d这个属性吗?没有,那看看原型上有没有
// o.__proto__ 上有d这个属性吗?没有,那看看它的原型上有没有
// o.__proto__.__proto__ 为 null,停止搜索
// 没有找到d属性,返回undefined。

我们画张图来表示:

新手理解的JS原型链

图中这条红色的线就是原型链。

由此可见, 实例对象可访问自己原型对象上的属性和方法 ,额..准确来说是:

__proto__
undefined

我们先回顾一下那个 sayName 的问题:

怎么让所有的实例对象都是用一个 sayName 方法呢 。

现在我们可以使用原型对象来解决这个问题了。

我们把 sayName 方法放到实例的原型对象上面,也就是 Person.prototype 上面来供所有实例使用:

function Person(name){
    this.name = name;
 }
Person.prototype.sayName=function (){
    alert(this.name);
}
var person1 = new Person('小明');
var person2 = new Person('小红');
person1.sayName === person2.sayName;//true

用图表示:

新手理解的JS原型链

补充

constructor

说一下我的经历,一开始理解原型链时,一直在 prototype__proto__constructor 在这个三个属性中绕来绕去,为了便于理解,我把 constructor 放在最后了。

constructor 字面意思就很容易理解,构造函数的意思。

一句话解释:

每个原型对象都有一个 constructor 属性指向 关联的构造函数。

还是上面那个例子:

console.log(Person.prototype.constructor);//Person(){ fun }

需要注意的一点是,实例对象上没有 constructor 属性。

但是:

console.log(person1.constructor) ;//Person(){ fun }

得出这个结果很简单:

实例上查找不到 constructor 属性 --> 顺着 __proto__ 在原型对象上找 --> 找到并返回。

Object.prototype

刚才我们说了创建对象的两种方式:字面量创建对象和使用 new 操作符创建对象。

这两种方式创建出来的对象都会继承 Object.prototyoe 上的方法。

比如,我们使用字面量新创建一个对象 o :

var o = {value: 1};
o.toString();//"[object Object]"
//查找过程: o --> o.__proto__ 找到返回
o.__proto__ === Object.prototype;//true

o 这个的对象本身并没有 toString 这个方法,但它却可以使用 toString 方法。

因为它继承了 Object.prototyoe 上的 toString 的方法。

null既然对象都会继承自 Object.prototype 上面的方法,那它自己的原型又是什么呢。答案是 null

Object.prototype.__prototype__ === null;//true

以上仅自己学习所得,如有不当之处 望指出。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Bulletproof Web Design

Bulletproof Web Design

Dan Cederholm / New Riders Press / 28 July, 2005 / $39.99

No matter how visually appealing or packed with content a Web site is, it isn't succeeding if it's not reaching the widest possible audience. Designers who get this guide can be assured their Web site......一起来看看 《Bulletproof Web Design》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具