简介:js的每个对象都继承另一个对象,后者称为原型对象
。一方面,任何对象都可以充当其他对象的原型,另一方面,原型对象也是对象,所以它有自己的原型,null
也可以充当原型,区别在于它没有自己的原型对象。
复习js中的类型
js的每一个值,都属于某一种数据类型,共有六中数据类型:
- 数值(number):小数和整数
- 字符串(string):字符组成的文本
- 布尔值(boolean):true和false
- undefined:未定义或不存在,即由于没有定义,暂时没有任何值
- null:无值
- 对象(object):各种值组成的集合
通常将数值、字符串、布尔值称之为原始类型的值,而将对象称之为合成类型。
对象又分为三个子类型:
- 狭义对象(object)
- 数组(array)
- 函数(function)
typeof 运算符
typeof
运算符可以返回一个值的数据类型。运算结果可能有下面三种情况
- 原始类型:数值、字符串、布尔值分别返回
number
、string
、boolean
- 函数:函数返回
function
- undefined:undefined返回undefined(利用这一点可以用来检查一个没有声明的变量而不报错)
- 其他的返回object:
window
、{}
、[]
、null
可以看到数组也是特殊的对象。
null
的类型也是object
,是由于当初设计的时候没考虑到null
,只把它当做object
的一个特殊值(32位全部为0),这是历史原因,本质上null
是一个类似于undefined
的特殊值。
null 和 undefine的区别
和Java类似,null
是可以转换为0的,js的设计者觉着用一个对象类型的null
表达无
这个值很不好,最好是可以区分,所以就设计了undefined
。null
是一个表示无
的对象,可以转换为0
,undefined
是一个表示无的原始值,转换为数值时为NaN
。
1 | 5 + null // 5 |
原型链
js的每个对象都继承另一个对象,后者称为原型对象
。一方面,任何对象都可以充当其他对象的原型,另一方面,原型对象也是对象,所以它有自己的原型,null
也可以充当原型,区别在于它没有自己的原型对象。
每一个构造函数都有一个prototype
属性,这个属性会在生成实例的时候,称为实例对象的原型对象。
函数在js中是很特殊的存在,是所谓的一等公民
。当创建函数的时候,js会为这个函数自动添加protrotype
属性,值是空对象。而一旦你把这个函数当做构造函数constructor
调用(即通过new
关键字调用)时,那么js就会帮你创建该构造函数的实例,实例继承构造函数prototype
的所有属性和方法(实例通过设置自己的__prototype__
指向构造函数的prototype
来实现这种继承)。
1 | // 声明函数F1和F2 |
这个实例着重来解释实例通过设置自己的__proto__
指向构造函数的prototype
来实现原型继承,继承所有的属性和方法
构造函数通过prototype
来存储需要共享的属性和方法,也可以设置prototype
执行现存的对象来继承该对象。
也即是说,当实例对象本身没有某个属性或方法的时候,它会到构造函数的prototype
属性指向的对象寻找改属性或方法。这就是原型对象的特殊之处。
原型对象的作用,就是定义所有实例对象共享的属性和方法。这也就是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出的子对象。
如果一层层往上追溯,所有对象最终都可以追溯到Object.prototype
,即Object
构造函数的prototype
属性。相应的,Object
对象有没有它的原型呢?有的,就是没有任何属性和方法的null
对象,而null
对象没有自己的原型。
原型链
的作用是,读取到对象的某个属性时,js引擎先寻找对象本身属性,如果找不到,就到它的原型中去找,如果还找不到,就到原型的原型中去找,直到最顶层的Object.prototype
还是找不到,就返回undefined
。
如果对象自身和原型都定义了同名属性,那么优先读取对象自身的属性。
Object.getPrototypeOf() 获得一个对象的原型
Object.getPrototypeOf()
方法返回一个对象的原型,这是获取原型对象的标准方法
创建个Person类,并实例化
1 | function Person(){this.name='';this.age = 0} |
检测p对象的原型:
1 | Object.getPrototypeOf(p); |
发现创建的实例对象p
有属性constructor
:
1 | p.constructor.name // "Person" |
其实实例对象p
自身没有contructor
属性,改属性其实是读取原型链上Peson.prototype.constructor
属性。
1 | p.hasOwnProperty('constructor') // false |
constructor
属性的作用,是分辨原型对象到底属于哪个构造函数。constructor
属性表示原型对象与构造函数之间的关联关系,如果修改了原型对象,一般也会同事修改constructor
属性,防止引用时出错。
总结:作为构造函数的Person
有属性prototype
,prototype
里面有构造函数的属性constructor
。作为实例对象p
没有prototype
属性,但是可以调用原型链上的constructor
属性,这个应该是继承在属性__proto__
上,和p.__proto__.constructor.name
一个效果。
参考博客:
https://github.com/mqyqingfeng/Blog/issues/2
http://yujiangshui.com/javascript-prototype-and-create-object/
https://github.com/creeperyang/blog/issues/9