您的位置:首页 > Web前端 > JavaScript

JavaScript 原型链

2016-08-06 19:56 459 查看
君子生非异也,善假于物也。

——《荀子·劝学》

JavaScript 中关于类的继承是一个原型继承的方式,总结起来其精髓就在于“”这个字。

JavaScript 中,对于一个对象,它所能访问的属性,不一定全是它自己的属性,也有可能是它原型的属性,甚至是原型的原型的属性……

__proto__
是一个属性,除了
null
undefined
没有以外,其他的都具有这个属性。用于指向对象的原型,是一个引用(指针)。

"123".__proto__ === String.prototype; // true
(1).__proto__ === Number.prototype; // true
(function A(x){return x;}).__proto__ === Function.prototype; // true


constructor 与 prototype

对象的构造器(constructor) 是一个函数。

函数的原型是一个原型对象(prototype)。

从一个函数(类)能构造出很多对象,但一个函数只有对应的一个原型。从某种意义上来说,这个原型对象也是函数的实例之一,不过这是一个特殊的实例。

假设有一个函数
A


function A(){};


对于其原型(prototype)对象
obj
来说,构造器就是
A


var obj = A.prototype;
obj.constructor === A; // true


但对于一般的f实例化对象
x


var x = new A();
x.hasOwnProperty('constructor'); // false
x.constructor === A; // true


x
是不具有
constructor
属性的,但
x.constructor
依然能访问,并且指向的也是
A
。这是因为
x.constructor
沿着原型链进行了回溯搜索,实际上
x.constructor
就是
x.__proto__.constructor
,而
x.__proto__
就是
A.prototype


构造过程

function A(){this.key = 1;};
A.prototype.val = 1;
var x = new A();


对于这样一个基本的构造。我们可以发现,
x
可访问的属性如下

x.__defineGetter__
x.__defineSetter__
x.__lookupGetter__
x.__lookupSetter__
x.__proto__
x.constructor
x.hasOwnProperty
x.isPrototypeOf
x.propertyIsEnumerable
x.toLocaleString
x.toString
x.valueOf
x.val
x.key


实际上真正属于
x
自己的属性有什么呢?

只有
x.key
是真正属于
x
的,这两个都是在
new A()
的调用过程中产生的。

其他的,就连
x.val
都是属于
A.prototype
而不属于
x


x.__proto__ === A.prototype; // true
x.__proto__.__proto__ === Object.prototype; // true
x.__proto__.__proto__.__proto__ === null; // true

x.hasOwnProperty('__proto__'); // false
x.__proto__.hasOwnProperty('__proto__'); // false
x.__proto__.__proto__.hasOwnProperty('__proto__'); // true


实际上我们可以看到,
x
能访问的属性,除了
__proto__, key
这样自身的属性之外,还有
A.prototype, Object.prototype
的。

总结:那么现在我们可以知道在构造过程究竟发生了什么:

构造对象

原型链接

应用构造函数

function myNew(f) {
// create new object
var obj = {};
// link to prototype chain
obj.__proto__ = f.prototype;
// apply constructor to the object
f.apply(obj, Array.prototype.slice.call(arguments, 1));
// return the object
return obj;
}


这个过程也可以手动地操作一下。

function f() { this.key = 1; };
f.prototype.val = 2;
var x = {};
x instanceof f; // false
x.val; // undefined
x.key; // undefined

x.__proto__ = f.prototype;
x instanceof f; // true
x.val; // 2
x.key; // undefined

f.call(x); // same as f.apply(x, []);
x instanceof f; // true
x.val; // 2
x.key; // 1


原型继承

类的继承其实很简单:

function A(){};
function B(){};
// B inherits A
B.prototype.__proto__ = A.prototype;


这样就完成了类的继承,如果理解了最终的实例对象的寻找属性的方式,那么这种做法是显而易见的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息