面向对象思想,围绕对象、类、实例的概念与关系展开~
对象、类、实例的概念可以按照自然界中类别和个体的概念进行理解。
至于对象——万物皆对象~
JS中的内置类
- 数据类型类:每种数据类型都有一个自己对应的类
- Number类:每个数字(包括NaN/Infinity)都是它的一个实例。
- String类:每个字符串都是它的一个实例。
- Boolean类
- Null&Undefined类:浏览器保护了这两个类。
- Symbol类:不可被new。
- BigInt类
- Object类:Array、RegExp、Date…都是它的子类 ( 类比人类和男人类的关系 ) 。
- Function类
- DOM元素类:每一个DOM元素对象也有自己的类和祖先类
- DIV -> HTMLDivElement -> HTMLElement -> Element -> Node -> EventTarget -> Object
- ……
查看DOM元素对象的类和祖先类,可以在控制台dir(获得的元素对象),沿着原型链__proto__查看。
自定义类
真实开发中,为实现需求,还需要自己构建一些自定义类。
自定义类是啥呢?其实就是一个函数,创建的时候和普通函数没啥差别,我们把它当作构造函数执行,这个函数就称为一个"类"了。
function Func(x,y){ // 类名通常首字母大写
let num = x + y;
this.x = x;
this.y = y;
}
let f1 = Func(10,20); // 当作普通函数执行
let f2 = new Func(10,20); // 当作构造函数执行
我们在之前已经了解了普通函数执行的底层机制,我们通过上面的例子简单回顾一下:
- 形成私有上下文 EC(Func)
- 初始化作用域链 <EC(Func),EC(G)>
- 初始化this指向 this->window
- 初始化实参集合arguments [10,20]
- 形参赋值 x = 10, y = 20
- 变量提升 - -
- 代码执行
构造函数执行与普通函数执行有啥不一样的喃?
大部分流程都是一样的,毕竟构造函数也是函数嘛;只不过构造函数的执行多了那么几个步骤:
1. 初始化作用域链之后,默认创建一个对象,这个对象就是当前类的一个实例。
2. 让this指向这个实例。
3. 函数没有返回值的情况下,默认把创建的实例返回;若返回值为基本类型(没啥用),仍然返回创建的实例;返回值为引用类型值,它将把创建的实例覆盖掉并且返回自己写的这个结果。
在例子中,需要注意以下几点:
- Func函数执行形成私有上下文,这个上下文中创建的一个对象(当前类的实例)被当作返回值,赋值给了全局变量f2。形成了一个不销毁的上下文。
- 函数内部的代码执行过程中,x、y、num是其私有变量,其中x、y是通过形参赋值,num则是在代码执行过程中计算得到。
this.x = x; this.y = y
这两句代码是给实例对象设置私有属性。因为this指向实例对象f2,注意:只有this才与实例有关,否则只是上下文中的私有变量而已。