JavaScript 面向对象(一)
数据类型
JavaScript 中有 8 种数据类型,分别是:
简单基本类型
string
字符串类型number
数字类型boolean
布尔值类型undefined
未定义类型null
空类型bigint
范围更大的整型值symbol
独一无二的值
引用数据类型
Object
对象类型
其中 7 种简单基本类型的变量直接存储值,而应用数据类型存储地址,对象的值存储于堆中。
可以使用 tyeof
来判断变量的数据类型,其中 typeof null
输出为 Object
是因为在 JavaScript 中二进制前三位为 0
则会被判断为 Object
类型,而 null
的二进制全是 0
,所以这是一个 JavaScript 的 bug 。
简单基本类型是值类型,不具有属性,但是我们依然可以使用 'abc'.length
,这是因为进行了封箱和拆箱的处理,在执行这句代码时会自动将 'abc'
进行封箱操作,自动生成一个 new String('abc')
对象,并调用打印其 length
属性,执行完毕则进行拆箱,回到字面量 'abc'
。而 null
和 undefined
没有对应的内置对象,所以无法进行封箱操作,也无法调用任何方法或属性。
对象的定义
对象可以通过两种方式定义: 声明形式和构造形式
// 声明形式
var obj1 = {
name: 'knight1',
age: 18
};
// 构造形式
var obj2 = new Object();
obj2.name = 'knight2';
obj2.age = 19;
对象是引用类型,变量存储对象的引用,而对象的属性如果也是对象,则存储的也是对象的引用
属性描述符
上面这个例子向我们展示了通过 Object.getOwnPropertyDescriptor()
来获取属性的属性描述符,并通过 Object.defineProperty()
来设置属性描述符
属性描述符分为两类,
- 数据描述符:
{
configurable: true,
enumerable: true,
value: "knight2",
writable: true
}
- 访问描述符:
{
configurable: true,
enumerable: true,
get(){console.log('get')},
set(){console.log('set')}
configurable
设置属性是否是可配置,若为 false
无法通过 Object.defineProperty()
修改属性描述符,默认为 true
注意: 若我们将 configurable
设置为 false
,而 writable
为 true
时,我们还可以调用一次 Object.defineProperty()
用于将 wirtable
修改为 false
enumberable
是否可被枚举,若为 false
则属性不会出现在对象的属性枚举种,如 for of
中,默认为 true
value
属性的值
writable
决定是否可以修改属性的值,若为 false
则属性只可被读取而无法被写入
get
/set
重写属性的 get
和 set
操作,若只定义其中一个,则另一个什么都不执行,如只定义 get
,则无法修改属性值
原型
如图所示,其中 person
和 Person.protype
是对象,而 Person
为函数,我们通过 Person
构造函数实例化 person
对象,然后会将 Person()
的 prototype
对象作为 person
的原型,在浏览器中国,我们可以通过 person.__proto__
属性来访问这个原型对象,而 Personprototype.constructor
指向 Person()
函数。
原型链
刚才已经说了, person
和 Person.protype
是对象,所以 Person.protype
也有 __proto__
属性,然后如果我们依次向上寻找原型的话,大部分时候都会找到 Object.prototype
对象,而这个对象的原型指向 null
。
当我们访问 person
中的属性时,若该属性在 person
中没有,则会向原型中寻找,然后依次向上寻找,如果找到原型的尽头依然找不到的话,就会返回 undefined
。
而如果我们找到了则会返回该属性,并停止寻找,这也会造成属性的屏蔽,就是原型链下端的属性会屏蔽上端的属性。
如果属性不在对象中,而在对象的原型中则会出现下面三种情况
- 如果原型中存在该属性,且违背标记为只读,则会在对象中添加一个同名属性,他就是屏蔽属性
- 如果原型中存在该属性,但被标记为只读,则无法被修改,也不会在对象中添加一个同名属性
- 如果原型中存在该属性,但是是一个
setter
,则会调用该setter