我们已经描述了对象的创建,那么接下来主要讲解对象的结构和对象的属性。
首先我们先看下对象和类的结构图
Person类
person的一个实例
那么在上面,我们称变量 p 是 Person类的一个实例(大家在学习或者其他的视频教学时经常听到 创建一个实例对象就是这么来的)。
在p和Person之间,通过在创建new Person的时候为对象p添加了两个主要的属性。
constructor:构造器 用来指向当前对象创建时,所调用的函数。
__proto__:原型指针属性.通常用来指向当前构造函数的prototype属性(Object.create的指向会有所趋避=>其实我不想写的 就怕有人纠结这个问题).
ok~那么我们在上面已经简单看到了constructor的指向,就可以知道p是哪个函数创建的
那__proto__属性是干什么的呢?
我们来看下面两个例子
我们以Person为构造函数分别创建两个实例,并且在zhang的时候传入对应的属性参数,在li的时候不传入参数,并做打印。
在看到结果的时候我们很明显的能发现两个小的问题.
1.new Person时 ,this对象会每次进行调用创建属性和方法,性能差
2.我们的两个对象都是person类所创建的,缺少共有的方法和属性。
补:比如每个人都会想··人应该有眼睛鼻子耳朵,那么这些东西我们不用特定的给予也应该存在,俩耳朵一个鼻子俩眼睛(特殊情况就算了)
所以我们需要使用原型模式来创建对象的共有属性和方法。
下面我们单独使用原型方式来创建一个人的类
最终的结果我们发现两者完全一样
这是因为js中创建对象,如果当前对象缺少私有属性的时候,如上面z和s本身是没有name属性的,name就会通过__proto__寻找构造函数的prototype对象下对应的属性或方法(对象本身是可以继承的,如果Person的原型也没有name属性,就会通过Person函数的__proto__去寻找,以此类推,因为js中所有的类最终都会指向Object对象,所以我们经常看到创建一个对象会默认携带.toString、length、name和其他的属性方法)。
那如果当前对象有私有的属性和方法会怎么办呢?我们是不是只要用prototype就好了,不需要在使用this创建了呢?
也不是的,来看下面的两个例子(为了保持代码的完整性,我的代码结构可能贴的比较多 大家忍耐下)
代码:
输出:
在这里有两个小小的问题:
1.使用prototype添加属性和方法时,代码量明显争夺
2.如果大家在认真看对比数据的情况下就能很明显有些数据结构不太明确了
那对于这里的解释··其实我也很无力,毕竟面向对象,不是补基础课程,我简单说下,理解不了的就死记硬背吧。
1.通过z.name=是重新赋值,添加的是私有属性,而name属性是值类型,会单独创建一块空间数据结构。
2.z.girlFriends.push 是调用属性增加数据结构的变量,那z本身是没有girlFriends的属性的,所以会通过__proto__默认指向Person.prototype下的girlFriends并在尾部追加一个变量。那当我们调用s.girlFriends的时候,因为本身没有对应的属性和方法,所以就会通过__proto__指向Person.prototype下的属性,该死的Person.prototype.girlFriends呗z给更改了,所以最后s和z的girlFriends就会是一样的。
3.那大家说··如果我使用z.girlFriends = "";会怎么样的?那z会和Person.prototype下的girlFriends脱节,因为 = 代表的是添加私有属性 重新赋值.
注:建议大家好好看看值类型和引用数据类型的区别与概念,还是蛮有用的
所以根据__proto__的特性和代码复用的原则,我们一般使用组合模式用来创建一个对象的构造函数。
那么我们再看看对象的一些其他属性:
this:在使用new关键字时,this会更改上下文指向当前我们新创建的实例。
isPrototypeOf:判断对象A是否为对象B的原型对象(B.__protot__是否指向A)。
如上面代码格式应该为(好好读代码):
hasOwnerPrototype:判断当前实例对象是否存在自己的私有属性
in:判断一个对象中是否包含属性或函数(通过__proto__指向的也包含在内)