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
= new sum(10,20);
console
.log(res
);
// ================== 分界线 =======================
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
);
console
.log(f1
.say
);
console
.log(f1
.str
);
let f2
= new Fn;
console
.log(f1
=== f2
);
+ 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
);
console
.log(f1
.getY
=== f2
.getY
);
console
.log(f1
.__proto__
.getY
=== Fn
.prototype
.getY
);
console
.log(f1
.__proto__
.getX
=== f2
.getX
);
console
.log(f1
.getX
=== Fn
.prototype
.getX
);
console
.log(f1
.constructor
);
console
.log(Fn
.prototype
.__proto__
.constructor
);
f1
.getX();
f1
.__proto__
.getX();
f2
.getY();
Fn
.prototype
.getY();
* 所有的类都是函数类型的(内置类、自定义类)
所有的函数都天生自带一个属性: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();
my_fun
.c();
my_fun
.c() 执行:
先看一下自己私有的里面有没有函数 c,如果没有就沿着 __proto__ 往原型链上查找,my_fun
.__proto__ 值为 fun
.prototype
, 在这里找到了函数 c,执行该函数,此时函数中的
this指向的是实例 my_fun,
=> this.a
=== my_fun
.a
=> 30