🔒 面向对象初级知识

面向对象基础知识(概念、特点)
构造函数
用new命令
构造函数的缺陷(浪费内存) –> 解决方法:公有方法放到原型prototype上
原则上,构造函数内放私有属性,原型上放公有方法
如果在构造函数内找不到,就会自动顺着原型链找【test.age === test.proto.age === Person.prototype.age】

面向对象的概念

面向对象:只关心对象的使用,不关心内部的实现原理。
比如数组Array的.sort()方法可以对数组进行排序,我们不需要知道它的内部实现原理,只要会用它的这个方法就行了。

jQuery就是面向对象。

面向对象编程(OOP)

特点:

  • 抽象:人有许多特性,如果写一个员工管理系统,只需要将姓名、工作时长、工资等关键特性抽出来就行了;如果写一个医疗系统,就需要将身高、体重、血型等抽出来。
  • 封装:无需知道内部实现原理,就能使用对象的属性和方法
  • 继承:var arr = [1,2,3]继承了数组Array的所有属性和方法,Array继承了Object的所有属性和方法;因此arr具有Array和Object的所有属性和方法,并且arr具有自己的一些新特性
    • 多重继承:大箱子 + 卡车 = 集装箱货车
    • 多态

this

当前函数/方法属于谁,this就是谁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
oDiv.onclick = function(){
console.log(this);
}
onclick方法属于oDiv,所以this指向oDiv
------------
function x(){
console.log(this);
}
x();
函数x属于window【等同于window.show=function(){console.log(this)}】,所以this指向window
---------------
var obj = {
a:12,
show:function(){
console.log(this.a);
}
}
obj.show(); //12
show()这个方法属于obj,所以this指向obj,因此this.a就是12

构造函数(大写)

典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念。“类”就是对象的模板,对象就是“类”的实例。

但是,JavaScript,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。

JavaScript 使用构造函数(constructor)作为对象的模板。”构造函数”就是用来生成实例对象的函数。它是对象的模板,给实例对象内置一些属性和方法。一个构造函数,可以生成多个实例对象,这些实例对象都内置相同的属性和方法。

1
2
3
var Vehicle = function () {
this.price = 1000;
};

为了与普通函数区别,构造函数名字的第一个字母通常大写。

构造函数生成实例对象的时候,必须使用new命令。

new

1
2
var v = new Vehicle();
v.price // 1000

用new命令时,默认给构造函数的起始位置加上var this = {},结尾默认return this

1
2
3
4
5
function x(){
console.log(this);
}
x(); //window
new x(); //对象{}

new做了些什么

  1. var this = {} 产生一个空对象,且this指向这个空对象
  2. this.proto = 构造函数.prototype【举例:var stage = new Human(‘stage’),则stage.proto === Human.prototype】
  3. 执行构造函数.call(this,参数1,参数2...)
  4. return this(生成的对象)

工厂模式()

  • 原料
  • 加工
  • 怵场
1
2
3
4
function Vehicle() { //默认内部有一个var this = {} 作为原料
this.price = 1000; //加工
//默认最终将this return出去
}

原型对象prototype

作用:将一模一样的属性和方法放到原型对象prototype上,构造函数内留私有方法

构造函数的缺陷

1
2
3
4
5
6
7
8
9
10
11
12
13
function Cat(name, color) {
this.name = name;
this.color = color;
this.meow = function () {
console.log('喵喵');
};
}
var cat1 = new Cat('大毛', '白色');
var cat2 = new Cat('二毛', '黑色');
cat1.meow === cat2.meow
// false 系统资源浪费

上面代码中,cat1和cat2是同一个构造函数的两个实例,它们都具有meow方法。由于meow方法是生成在每个实例对象上面,所以两个实例就生成了两次。也就是说,每新建一个实例,就会新建一个meow方法。这就造成了系统资源浪费,因为所有meow方法都是一模一样的,完全可以共享。

这个问题的解决方法,就是 JavaScript 的原型对象(prototype)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Animal(name) {
this.name = name;
}
Animal.prototype.color = 'white';
Animal.prototype.walk = function () {
console.log(this.name + ' is walking');
};
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
cat1.walk(); //大毛 is walking
cat1.color // 'white'
cat2.color // 'white'
cat1.color === cat2.color //true 节省资源

当实例对象本身没有某个属性或方法的时候,它会到原型对象去寻找该属性或方法。如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。

1
2
3
4
cat1.color = 'black';
cat1.color // 'black'
cat2.color // 'white'

如果构造函数里找不到,就会顺着原型链一步步找下去

test.age === test.proto.age === Person.prototype.age

1
2
3
4
5
6
7
8
9
10
function Person(name){
this.name=name;
}
Person.prototype.age='18岁';
var test = new Person('stage');
console.log(tset.name); //stage
console.log(test.age); //18岁 【在它的原型上找到了属性age】
test.age === test.__proto__.age === Person.prototype.age

类与实例对象

类:模子 -> 植入默认的属性和方法
实例对象:产品 -> 使用默认的属性和方法

总结

原则:

  • 构造函数用来加私有属性
  • 原型用来加公有方法
  • 如果构造函数里找不到,就会顺着原型链一步步找下去【test.age === test.proto.age === Person.prototype.age】

补充

实例属性和静态属性

ES5:

1
2
3
4
5
6
7
8
function Person(name){
this.name = name; //实例属性,可以被生成的实例访问到
}
Person.xxx = 'hello'; //静态属性,只能被构造函数访问到
var whh = new Person('王花花');
whh.name //实例属性
Person.xxx //静态属性

ES6:

1
2
3
4
5
6
7
8
9
10
class Person {
constructor(name){
this.name = name; //实例属性
}
static xxx = 'hello'; //静态属性,写在class内部,前面用static关键字修饰
}
const whh = new Person('王花花');
whh.name //实例属性
Person.xxx //静态属性

实例方法和静态方法

ES5:

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name){
this.name = name;
}
Person.xxx = function(){
console.log('静态方法,只能被构造函数调用')
}
Person.prototype.say = function(){
console.log('实例方法,可以被生成的实例调用')
}
var whh = new Person('王花花');

ES6:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person {
constructor(name){
this.name = name;
}
say(){
console.log('实例方法,可以被生成的实例调用')
}
static xxx(){
console.log('加上static关键字,变成静态方法,只能被构造函数调用')
}
}
const whh = new Person('王花花');

-------------本文结束感谢您的阅读-------------