JavaScript高级手记(面向对象、原型、原型链)
----------面向对象编程--------------
* OOP (Object Oriented Programming): 面向对象编程
+ java
+ javascript
+ c#
+ python
+ ...
* POP (Procedure Oriented Programming): 面向过程编程
+ c
+ ...
=====================================================
* 面向对象编程语言中的三大概念
+ 对象:泛指(万物皆对象)
+ 类:对象的细分
+ 实例:某一个类别中具体的事物
JS本身是面向对象编程的:JS这门语言的创建过程就是按照类和实例来创建的,JS有很多的类
数组类:Array(内置类)
+ 每一个数组都是它的实例
+ 每一个实例都是独立的个体,又自己私有的,也有一些Array提供给每一个实例的公共属性和方法
数据类型类:见到的数据值都是其所属类的一个实例
+ Number
+ String
+ Boolean
+ Symbol
+ BigInt
+ Object
+ Object
+ Array
+ Date
+ RegExp
+ ...
+ Function
DOM对象/节点或元素集合/样式对象或者集合等
+ HTMLDivElement/ HTMLAnchorElement/ HTMLUListElement ... 每一种元素对象都有一个自己的所属类
+ HTMLElement/ XMLElement ...
+ ELement/ Text/ Document ...
+ Node 节点类
+ EventTarget
+ Object
+ HTMLCollection(通过document.getElementByTagName('*')获取)/ NodeList(通过 document.querySelectorAll('*')获取) ...
+ CSSStyleDeclaration(样式类)
+ ......
--------------------------------------------------------
* 学习JS基础知识,尤其是API层面的
+ 类.prototype:存放的是给当前类的实例调用的公共属性和方法
+ 类.xxx:把其当做对象设定的静态私有属性或方法
+ ...
document.getElementById(ID)
+ 获取上下文只能是 document?
+ getElementById是在Document类原型上提供的方法,所以只有Document的实例才可以调用(document是它的实例)
[context].getElementByTagName(Tag)
+ Element类的原型上提供getElementByTagName方法
+ 每一个元素标签都是Element类的实例
+ Document的原型上也有这个方法,所以document也可以调用
+ ...
function sum(x, y) {
let total = x + y;
this.total = total;
console.log(this)
return total;
}
// let res = sum(10, 20); // window
// console.log(res); // 30
let res = new sum(10,20); // {total: 30}
console.log(res); // {total: 30} */
// new 执行:sum不再称为函数,而叫做构造函数或者类(自定义类),处理过程中创建的对象,是当前类的一个实例
/*
* new 函数执行:
+ 形成一个私有上下文
+ 创建一个对象(这个对象是当前类的一个实例)
+ 初始化作用域链
+ 初始化this指向:让this指向创建的这个对象
+ 形参赋值
+ 变量提升
+ 代码执行
代码执行中遇到的 this.xxx = xxx 都是给创建的对象设置私有的属性或方法
如果没有没有写 return 或者 return 的是一个基本类型值,则返回的是创建的这个对象;如果 return 的是引用类型值,则以返回的值为主
*/
// ================== 分界线 =======================
// 内置类:首字母大写,所以自己创建的类的首字母也会大写
// 所有的类都是一个函数类型值(构造函数):内置类/ 自定义类
function Fn(x, y) {
let str = "自定义类";
this.total = x + y;
this.say = function(){
console.log('OK');
};
}
let f1 = new Fn(10,20);
console.log(f1.total); // 30
console.log(f1.say); // 函数
console.log(f1.str); // undefined str是上下文中的私有变量,跟实例没有关系
let f2 = new Fn; // 这样Fn也和上面的 Fn(10,20) 一样执行了,只是没有传实参而已
console.log(f1 === f2); // false 每一次new类创建的实例都是“独立的实例对象”,new类的实例也称为“构造函数模式”
+ new Fn(); 带参数列表的new 优先级19
+ new Fn; 不带参数列表的new 优先级18
相同点:最后Fn都会执行,也都会创建Fn类的实例
区别:是否传参,以及运算优先级不一样(带参数列表的高于不带参数列表的)
-----------------面向对象之原型和原型链------------------
function Fn(){
this.x = 100;
this.y = 200;
this.getX = function(){
console.log(this.x);
}
}
// 在原型上扩展公用方法
Fn.prototype.getX = function(){
console.log(this.x);
}
Fn.prototype.getY = function(){
console.log(this.y);
};
let f1 = new Fn;
let f2 = new Fn;
console.log(f1.getX === f2.getX); // false
console.log(f1.getY === f2.getY); // true
console.log(f1.__proto__.getY === Fn.prototype.getY); // true
console.log(f1.__proto__.getX === f2.getX); // false
console.log(f1.getX === Fn.prototype.getX); // false
console.log(f1.constructor); // Fn
console.log(Fn.prototype.__proto__.constructor); //Object
f1.getX(); // 100 this=> f1
f1.__proto__.getX(); // undefined this=> f1.__proto__
f2.getY(); // 200
Fn.prototype.getY(); // undefined this=> Fn.prototype */
* 所有的类都是函数类型的(内置类、自定义类)
所有的函数都天生自带一个属性:prototype(原型,也叫显示原型)
+ prototype的属性值默认是一个对象类型值【堆】
+ 对象中存储的是供实例调用的公共属性和方法
+ 并且在prototype对象上,默认有一个属性:constructor(构造函数),属性值是当前类本身
所有的对象数据类型值也天生自带一个属性:__proto__(原型链,也叫隐式原型)
+ __proto__属性的值:当前实例所属类的prototype(原型)
+ 哪些值是对象数据类型值:
+ 普通对象、数组对象、日期对象、正则对象...
+ 类的原型 prototype
+ 大部分实例对象(除基本数据类型外)
+ 函数也是对象
* 如果不知道某个对象是通过哪个类new出来的,那就统一看成是通过Object内置类new出来的,将将该对象看成是Object的一个实例
* Object是所有对象数据类型的“基类”,Object.prototype也是一个类,但是不知道是哪个具体类new出来的,所以看做是Object的实例,但是Object.prototype.__proto__ 指向自己没有意义,所以 Object.prototype.__proto__ 的值为 null
function fun() {
this.a = 0;
this.b = function(){
alert(this.a);
}
}
fun.prototype = {
b: function(){
this.a = 20;
alert(this.a);
},
c: function(){
this.a = 30;
alert(this.a);
}
}
var my_fun = new fun();
my_fun.b(); // '0'
my_fun.c(); // '30' */
my_fun.c() 执行:
先看一下自己私有的里面有没有函数 c,如果没有就沿着 __proto__ 往原型链上查找,my_fun.__proto__ 值为 fun.prototype, 在这里找到了函数 c,执行该函数,此时函数中的this指向的是实例 my_fun,
=> this.a === my_fun.a => 30