Fork me on GitHub

Javascript 笔记(4)----继承与原型链

转载自:https://developer.mozilla.org/zh-CN/docs/JavaScript/Guide/Inheritance_and_the_prototype_chain

对于那些熟悉基于类的面向对象语言(java或者c++)的开发者来说,JavaScript的语法是比较怪异的, 这是由于javascript是一门动态语言,而且它没有类的概念 (虽然class是个保留字,不能作为变量名来使用).

继承方面,javascript中的每个对象都有一个内部私有的链接指向另一个对象 (或者为 null),这个对象就是原对象的原型. 这个原型也有自己的原型, 直到对象的原型为null为止. 这种一级一级的链结构就称为原型链.

基于原型链的继承

继承属性

javascript对象有两种不同的属性,一种是对象自身的属性,另外一种是继承于原型链上的属性.下面的代码演示了当访问一个对象的属性时,到底发生了什么.

 1 // 假定我们有个对象o,并且o所在的原型链如下:
 2 // {a:1, b:2} ---> {b:3, c:4} ---> null
 3 // 'a'和'b'是o自身的属性.
 4 
 5 // 该例中,用"对象.[[Prototype]]"来表示这个对象的原型.
 6 // 这只是一个纯粹的符号表示(ECMAScript标准中也这样使用),不能在实际代码中使用.
 7 
 8 console.log(o.a); // 1
 9 // a是o的自身属性吗?是的,该属性的值为1
10 
11 console.log(o.b); // 2
12 // b是o的自身属性吗?是的,该属性的值为2
13 // o.[[Prototype]]上还有一个'b'属性,但是它不会被访问到.这种情况称为"属性遮蔽".
14 
15 console.log(o.c); // 4
16 // c是o的自身属性吗?不是,那看看o.[[Prototype]]上有没有.
17 // c是o.[[Prototype]]的自身属性吗?是的,该属性的值为4
18 console.log(o.d); // undefined
19 // d是o的自身属性吗?不是,那看看o.[[Prototype]]上有没有.
20 // d是o.[[Prototype]]的自身属性吗?不是,那看看o.[[Prototype]].[[Prototype]]上有没有.
21 // o.[[Prototype]].[[Prototype]]为null,原型链已到顶端,没有d属性,返回undefined

继承方法

JavaScript并没有真正的"方法". JavaScript只有函数,而且一个对象的属性值可以为一个函数. 属性为函数的情况和属性为其他值的情况基本没有差别, 包括"属性遮蔽" (这种情况相当于其他语言的方法重写).

一个函数作为对象的属性和独立使用的主要区别是,当函数被调用时, this的值不同.

 1 var o = {
 2   a: 2,
 3   m: function(b){
 4     return this.a + 1;
 5   }
 6 };
 7 
 8 console.log(o.m()); // 3
 9 // 当调用 o.m 时,'this'指向了o.
10 
11 var p = Object.create(o);
12 // p是一个对象, p.[[Prototype]]是o.
13 
14 p.a = 12; // 创建p的自身属性a.
15 console.log(p.m()); // 13
16 // 调用p.m时, 'this'指向 p. 'this.a'则是12.

 

使用不同的方法来创建对象和生成原型链

使用普通语法创建对象

 1 var o = {a: 1};
 2 
 3 // o这个对象继承了Object.prototype上面的所有属性
 4 // 所以可以这样使用 o.hasOwnProperty('a').
 5 // hasOwnProperty 是Object.prototype的自身属性.
 6 // Object.prototype的原型为null,如下:
 7 // o ---> Object.prototype ---> null
 8 
 9 var a = ["yo", "whadup", "?"];
10 
11 // 数组都继承于Array.prototype (indexOf, forEach,等方法都是从它继承而来).
12 // 原型链如下:
13 // a ---> Array.prototype ---> Object.prototype ---> null
14 
15 function f(){
16   return 2;
17 }
18 
19 // 函数都继承于Function.prototype(call, bind,等方法都是从它继承而来):
20 // f ---> Function.prototype ---> Object.prototype ---> null

 

使用构造方法创建对象

在javascript中,构造方法其实就是一个普通的函数.当使用new 操作符来作用这个函数时,它就可以被称为构造方法(构造函数).

 1 function Graph() {
 2   this.vertexes = [];
 3   this.edges = [];
 4 }
 5 
 6 Graph.prototype = {
 7   addVertex: function(v){
 8     this.vertexes.push(v);
 9   }
10 };
11 
12 var g = new Graph();
13 // g是生成的对象,他的自身属性有'vertexes'和'edges'.
14 // 在g被实例化时,g.[[Prototype]]指向了Graph.prototype.

 

使用Object.create创建对象

ECMAScript 5中引入了一个新方法: Object.create. 可以调用这个方法来创建一个新对象. 新对象的原型就是调用create方法时传入的第一个参数:

 1 var a = {a: 1}; 
 2 // a ---> Object.prototype ---> null
 3 
 4 var b = Object.create(a);
 5 // b ---> a ---> Object.prototype ---> null
 6 console.log(b.a); // 1 (继承而来)
 7 
 8 var c = Object.create(b);
 9 // c ---> b ---> a ---> Object.prototype ---> null
10 
11 var d = Object.create(null);
12 // d ---> null
13 console.log(d.hasOwnProperty); // undefined, 因为d没有继承Object.prototype

 

posted @ 2013-03-31 11:06  Poised_flw  阅读(423)  评论(0编辑  收藏  举报