JS系列——js原型链

一、js的数据类型

js的数据类型分为基本数据类型和引用数据类型,其中基本数据类型有:Undefined、Null、Boolean、String、Number;引用数据类型:Object、Array、Function,其中要注意的是:typeof(null)的值为object,而typeof(undefined)的值为undefined

console.log(undefined==null) // true
console.log(undefined===null) // false

null表示一个空对象的引用指针,所以用typeof检测的类型是object,实际上undefined的值是派生自null的值的,所以可以看出两者是值相等,类型不相等。从以上数据类型,我们需要明白一个js的基本观点:万物皆对象,从而可得知数据类型这样的一个关系:所有对象的祖宗就是Object,这对我们理解原型链有很大帮助。

window对象:浏览器的顶级对象,暴露给开发者操作浏览器行为的对象,Object是js中语言类型,若非要说两者的关系,那就是各个浏览器制造团队(谷歌)在开发的浏览器(chrome)里实现BOM(浏览器对象模型)的时候创造了window对象,并且这个对象是ECMAScript语言规范中的数据类型Object类型的一个实例。Window是window对象的构造器,Window是Function的实例,是一个函数,Function类型本身就是Object类型的实例,所以Window构造函数是Function的实例,也就是Object的实例

console.log(window.constructor)
console.log(Window instanceof Function) // true
console.log(Function instanceof Object) // true
console.log(Window instanceof Object) // true

 二、定义变量

我们通常定义变量有两种方式:var obj = {} 或者var o = new Object();var  arr = []或者 var arr = new Array(),即字面量和new的方式,其中我们要理解new的方式定义的原理:

var o = new Object()
var obj = {}
console.log('obj',obj.__proto__===Object.prototype) // true,相当于new Object()创建
console.log(o.__proto__===Object.prototype) // true

// 构造函数
function Person(name) {
   this.name = name
}
var p = new Person('张三')

由上可知,new的方式创建变量,不管是js提供的构造器,如Function,Object,Array...,还是自己创建的构造函数,去定义一个实例,实际内部是分为以下几部分实现:

(1)创建一个空对象:var obj= {}

(2)把空对象与构造函数的原型建立联系:obj.__proto__ = Object.prototype

(3)创建作用域,p.call(this),把构造函数的作用域绑定给新对象,这样构造函数中的this就指向了新对象,即this.name就取值传入的参数“张三”

new方式通过构造函数定义变量实例,其实就是原型绑定的过程,加上第一部分说的数据类型的父子级关系,才形成了下面部分的原型链

三、原型链

            var A = function (name) {
				this.name = name
			}
			A.prototype.age = '24'
			var b = new A('艾伦')
			// 可继承父级属性和使用自己的属性方法
			console.log('名字', b.name, '年龄', b.age) // 名字:艾伦,年龄:24
			console.log(b.__proto__===A.prototype) // true
			console.log(b.__proto__.__proto__===Object.prototype) // true
			console.log(b.__proto__.__proto__.__proto__) // null
			console.log(A.__proto__===Function.prototype) // true
			console.log(A.__proto__.__proto__===Object.prototype) // true

从以上两部分我们可以知道有这几部分的概念:

构造函数:可以是自己创建的构造函数也可以是js提供的构造器(如Object,Function),不仅有__proto__属性,还有prototype属性,都指向该方法的原型对象

实例:由构造函数构造的实例对象,对象既可以是构造函数也可以创建实例(js万物皆对象),就像JS提供的Function对象,他自己是由object构造的实例,自己也可以成为构造器,构造出普通函数,通俗理解就是(男人既可以是别人儿子,也可以自己当爸爸)

原型prototype:所有的函数对象都有的原型属性,指向prototype对象,使之有能力往里面添加对象和方法

constructor:构造器,该属性返回对创建此对象的数组函数的引用,指向的是constructor对象,存在于prototype对象中

console.log('constructor',A.prototype.constructor) // 指向A函数: var A = function (name) {this.name = name}

 

__proto__:对象有的属性,指向该对象的原型对象 

由上图我们可以总结以下几点:

1.所有的对象都有__proto__属性,该属性指向该对象的原型对象

2.函数对象不仅仅有__proto__属性,还有prototype属性,两个属性都指向该函数的原型对象

3.constructor存在于该函数的原型对象中,指向该构造函数,函数和原型对象就是通过constructor和prototype相互关联的。

4.数据类型之间存在的关系,从构造函数创建一个实例开始:

Person.__proto__===Function.prototype

Person.__proto__.__proto__ === Object.prototype

Person.__proto__.__proto__.__proto__ === null

可以理解为:Person本身就是一个自定义的构造函数,是属于Function对象的,而Function的本质是对象,属于Object对象的,而Object为顶级对象,他的原型指向就为null了。

5.我们在创建的实例取值会通过这条父子之间形成的原型链去查找属性和方法,如果本身不存在,就往父级的原型中查找,知道查到该元素或者查到顶级为止

其实以上图我们可以用通俗的话去理解原型和原型链的原理:

我们把构造函数(如function Person(){}或者function Object(){})比作是父亲的角色,把通过这些构造函数创造的实例(如var p1 =  new Person() 或者 var obj = new Object())比作是儿子的角色,然后把原型对象比作是基因库(如:Person.prototype或者Object.prototype),父亲创造出来了儿子,但是两者之间的联系是通过原型对象联系的,如父亲的身高、染色体、肤色这些基因都存在基因库,基因就好比构造函数的属性或者方法,父亲会把这些基因遗传给儿子,儿子也可能有自己独有的基因,而这个基因库和父亲的关系是通过prototype或者constructor建立的,通过Person.prototype告诉你父亲的基因库是哪个,而基因库通过constructor告诉你,这个基因库的主人是属于谁的,而实例(儿子)和父亲(构造器或者构造函数)的基因库是通过__proto__告诉你,儿子你继承了哪位父亲基因库的基因

总结:学习无非就是一个把难的、官方语言理解为能自己用通俗语言表现出来的过程,其中可能加上了自己的见解和独特的发现和意外的收获

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值