面向对象
JS本身就是一门基于面向对象编程的语言
- 对象:泛指,一切我们需要研究的东西都是对象
- 类:把这么多东西按照特点进行分组分类(大类和小类)
- 实例:某一个类别中具体的某个事物
反推:通过对某一个实例的研究,我们会发现一些实例私有的特征,以及当前类下每一个实例都具备的公共特征
/*
* arr1、arr2都是Array数组类的实例
* 数组中的每一项内容都是当前实例私有的属性方法
* 像push、pop等这些方法,都是每一个实例共同具备的公共的属性和方法(Array.prototype)
*/
let arr1 = [10, 20, 30];
let arr2 = [40, 50];
arr1.push(100);
arr2.push(100);
面向对象要掌握的能力
- 掌握面向对象编程的本质(类和实例之间的操作和构建)
- 以后在学习前端开发的时候,培养自己按照面向对象编程思想去研究和学习的思维
- 以后在开发的时候(尤其是组件、插件封装),我们应该基于面向对象思想去实现(创建类,并且创建类的不同实例,这样既可以保证每个实例的独立,也可以让实例之间具备共同的属性方法)
JS本身是基于面向对象编程的,所以JS的底层就是基于类和实例处理的,而且V8引擎默认就给JS这门语言设计了很多内置的类
- 数据类型的内置类
- Number 每一个数字都是它的实例
- String
- Boolean
- Null、Undefined
- Symbol、Bigint (特殊:不能被new)
- Object 每一个对象都是Object类的实例
- Object
- Array
- RegExp
- Date
- ...
- Function 每一个函数都是Function类的实例
- DOM操作的内置类
- 每一个元素标签都有一个自己所属的类 (例如:HTMLDivElement -> HTMLElement -> Element -> Node -> EventTarget -> Object)
- HTMLCollection
- NodeList
- ...
- ...
构造函数
构造函数执行 new Xxx()
构造函数执行就是创建自定义类和类所对应的实例
=> Func被称为类, f1被称为当前类的一个实例
1.像普通函数执行一样,把函数执行,并且私有上下文和形参赋值等都操作一遍
2.特殊的操作
-> 在形成私有上下文之后,首先默认会创建一个对象(实例对象)
-> 让当前上下文中的THIS指向创建的这个对象
-> 接下来代码执行过程中所有的 this.xxx=xxx 都是给实例对象设置私有的属性和方法
-> 代码执行完成后,看是否有返回值。没有返回值默认返回创建的实例对象。如果有返回值,看返回值的类型,如果返回的是基本类型值,那么最后返回的还是实例对象。如果返回的是引用类型值,以自己返回的值为主。
因为构造函数执行既有普通函数执行的一面,也有自己特殊的一面,所以在所属私有上下文中,只有this.xxx=xxx才和实例对象有直接关系,而上下文中的私有变量等和实例对象没有必然的联系
/* 普通函数执行
1.形成一个私有的上下文 EC(FUNC),并且进栈执行(AO:name/age/n)
2.作用域链<EC(FUNC),EC(G)> ,初始this: window, 初始ARGUMENTS,形参赋值,变量提升
3.代码执行 window.name/age = 'xxx'/20
4.是否出栈释放
*/
function Func(name, age) {
var n = 10;
this.name = name;
this.age = age;
}
/* 构造函数执行 new Xxx() */
var f1 = new Func('xxx', 20);
console.log(f1);
/* 普通函数执行 */
var f = Func('xxx', 20);
console.log(f); // => undefined
// =======================================
function Func(name, age) {
var n = 10;
this.name = name;
this.age = age;
// 如果上下文中有返回值
// 返回基本类型:最后返回的是实例对象
// 返回引用类型:最后以自己返回的为主(不在是返回实例对象)
return function anonymous() { };
}
var f1 = new Func('xxx', 20);
console.log(f1); // => anonymous
// --------------------------
function Func() {
this.name = 'xxx';
this.age = 20;
}
//构造函数执行,在new的时候,类后面的小括号是没必要非要加的,不加也会当做构造函数执行,加或者不加的区别:
// => 不加小括号就没办法传递实参
// => 运算优先级的问题 new Func()【19】 new Fun【18】 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
var f1 = new Func;
console.log(f1);
Func(); // 普通函数执行
Func; // 这是函数本身,函数没有执行
// --------------------------
function Func() {
this.name = 'xxx';
this.age = 20;
this.say = function say() {
console.log(`my name is ${this.name},i'm ${this.age} years old!`);
};
}
var f1 = new Func;
var f2 = new Func;
console.log(f1 === f2); // false
console.log(f1.say === f2.say); // false
console.log(f1.name === f2.name); // true
// 检测当前实例是否率属于这个类
console.log(f1 instanceof Func); // true
// 检测某个对象是否具备这个属性【in】,再以及是否为私有属性【hasOwnProperty】
console.log('say' in f1); // true
console.log(f1.hasOwnProperty('say')); // true