JavaScript原型链的学习

了解原型对象(prototype)

1.每个函数都有一个prototype属性,这个属性默认指向一个Object空对象[^1]。
[^1]在这里,空对象指没有我们定义的属性。但是我们可以自己为其添加属性/方法

console.log(typeof(Date.prototype));//object
console.log(Date.prototype);
function Fun()
{

}
console.log(Fun.prototype);
//为原型添加方法
Fun.prototype.test = function()
{
	console.log("实例可以访问到这个test方法");
}
console.log(Date.prototype.constructor===Date);
console.log(Fun.prototype.constructor===Fun);
var f1 = new Fun();
f1.test();//实例可以访问到这个test方法

prototype属性为一个空对象
2.给原型对象添加的属性,可以被实例对象访问。

var f1 = new Fun();
f1.test();//实例可以访问到这个test方法

实例对象访问prototype对象的方法
3.原型对象中有一个属性叫constructor,它指向函数对象。

console.log(Fun.prototype);
console.log(Fun.prototype.constructor===Fun)

空函数的prototype
constructor指向函数对象

显式原型(prototype)和隐式原型(_proto_)

1.每个实例对象都有一个__proto__,称为隐式原型。
对象(实例)的隐式原型的值为其构造函数的显式原型的值。

	function Fun()
	{

	}
	console.log(Fun.prototype);//显式原型
	//为Fun创建一个实例
	var fun1 = new Fun();
	console.log(fun1.__proto__);//隐式原型
	console.log(fun1.__proto__ === Fun.prototype);//true

显式原型(prototype)和隐式原型(__proto__)
2.即显式原型属性和隐式原型属性都保存的是一个地址值,指向一个空的Object对象(原型对象)。
3.内存结构如下所示:

4.总结
(1)函数的prototype属性,在定义函数时自动添加。默认值为空object对象。
(2)对象的__proto__属性,在创建对象时自动添加。默认值为构造函数的prototype属性值。
(3)ES6之前,我们只能直接操作显式原型,不能直接操作隐式原型。

原型链

	function Fn()
	{
		this.test1 = function()
		{
			console.log("test1方法");
		}
	}
	Fn.prototype.test2 = function()
	{
		console.log("test2方法");
	}
	var fn = new Fn();
	console.log(typeof(Fn.prototype));
	console.log(Fn.prototype)//这个空对象是Object构造函数的一个实例,也具有__proto__属性。
	console.log(Object.prototype.__proto__);//null
	fn.test1();//test1方法
	fn.test2();//test2方法
	fn.test3();//fn.test3 is not a function->undefined

1.每个(构造)函数的prototype属性为一个空对象,而这个空对象是Object的实例,所以也具有__proto__属性。

	console.log(typeof(Fn.prototype));
	console.log(Fn.prototype)//这个空对象是Object构造函数的一个实例,也具有__proto__属性。
	console.log(Fn.prototype.__proto__ === Object.prototype);//true

在这里插入图片描述
2.所以通过原型链,我们可以找到Object构造函数的原型对象。在这上面有一些我们常用的方法。如toString() hasOwnProperty() 等等。

3.上面的语句的原型链如下图所示:
在这里插入图片描述
4.从上面的图可以发现

	fn.test1();//test1方法
	fn.test2();//test2方法
	fn.toString();
	fn.test3();//fn.test3 is not a function->undefined

fn.test1()可以直接在实例对象中找到;
fn.test2()可以在实例对象的隐式原型所指的原型对象中找到。
fn.toString()的寻找路线为:Fn的实例对象–>__proto__所指的原型对象(Object实例)–>Object实例对象的__proto__属性所指的原型对象中找到;
fn.test3()直到寻找到Object原型对象为止(尽头),无法寻找到该方法。

5.原型链的尽头
Object的原型对象是原型链的尽头。

console.log(Object.prototype.__proto__);//null

在这里插入图片描述

console.log(Object.prototype instanceof Object); //false

6.原型链
1)访问一个对象的属性时:
(1)现在自身属性中查找,找到返回。
(2)如果没有,再沿着__proto__这条链向上查找,找到返回。
(3)如果最终没有找到,返回undefined。
2)所以可以说查找时是沿着隐式原型链去寻找的。

7.Function和Object在原型链中的关系
在这里插入图片描述
(1)Function的实例的__proto__属性都指向Function的显式原型prototype。
(2)Function本身就是 Function的一个实例对象,所以它具有一个隐式原型__proto__指向显式原型prototype。(即构造函数Function的显式原型和隐式原型指向同一个对象)。

console.log(Function.prototype === Function.__proto__);//true

(3)Object是由Function创建出来的,所以Object构造函数的隐式原型也指向Function的显式原型。

一些例子

	function Fn()
	{
	
	}
	Fn.prototype.a = 'XXX';
	var fn1 = new Fn();
	console.log(fn1.a);// XXX -> 查找这个a时通过原型链寻找的

	var fn2 = new Fn();
	fn2.a = 'YYY';//这个语句直接在fn2上定义了a的方法	
	console.log(fn1.a,fn2.a);/XXX YYY

(1)读取对象的属性值时,会自动到原型链中查找。
(2)设置对象的属性值时,不会查找原型链。如果当前对象中没有此属性,直接添加此属性并设置其值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值