Javascript中的面向对象

什么是面向对象?

面向对象其实是代码整理的一种范式,方便我们开发时候去维护,和复用,当然,现在很多人都把它给哲学化了。
还是举例,是先有人还是先有人类呢?
如果从女娲造人的角度来说,当然是现有人类的概念,比如,我要造的这个人,应该有手,有脚,有身子,然后依据这些基本特征,发展成各种各样的人,这是面向对象语言,比如PHP,JAVA这种面向对象的一个基本逻辑,就是先创造类,然后基于类,去创造,比如手、脚这样的局部特征,唱歌,跳舞这些行为。专业点的说法,就是,属性方法
但是,从事实发展的角度,这样的逻辑,显然又不对,比如说,地球上的生物,是单细胞生物演化的,然后有了其他的各种各样的多细胞生物,或者说猴子吧,某个倒霉的猴子,被雷劈了下,但是因祸得福,被打通了智慧根,那么它的后代,跟一般的猴子不一样,给他们总结归类,叫他们人类。
Java或者PHP,通过类造的对象,都是一个模板,比如能哭,会笑,如果类改变了,所有对象的方法,都会改变。
那么Javascript呢,就很自然。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

let obj = {}; //造对象
let c = {cell:1};

let bird = {
leg:2;
song:function() {
alert('我是吴万海');
}
}

//访问属性

bird.leg;
bird.song;

构造方法

构造方法就是 new 方法。

1
2
3
4
5
6
7
8
9

function Dog(name,yellow) {
this.name = name;
this.yellow = yellow;
}

var dog = new('小狗','黄色');
console.log(dog);

这里有一点问题,就是JavaScript的对象属性,可以随意改动,增加减少,读取,这样显然不够严谨,而且封装性不够,那么怎么解决呢?

私有属性

JavaScript的私有属性是基于闭包实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

function Girl(name,lover) {
var nm = name;
var love = lover;

this.getName = function() {
return nm;
}

this.getLove = function() {
return love;
}
}

var girl = new Girl('黛玉','宝玉');
console.log(girl);

console.log(girl.getLove()); //宝玉

原型继承

所谓原型继承,就是让本来没有该属性或者该方法的函数对象,从一个有该属性的函数对象里获得。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

function Cat() {
this.climb = function() {
alert('爬树');
}
}

function Tiger() {
this.hunt = function() {
alert('打猎');
}
}

var tiger = new Tiger();
tiger.hunt(); //打猎
tiger.climb(); //报错

// 因为老虎的技能里并没有这个 hunt 这个方法。
//稍加改动

function Cat() {
this.climb = function() {
alert('爬树');
}
}

function Tiger() {
this.hunt = function() {
alert('打猎');
}
}

Tiger.prototype = new Cat(); // 让老虎的设计图,以一种小猫为原型,继承

var tiger = new Tiger();
tiger.hunt(); //打猎
tiger.climb(); //爬树


proto 属性

如果说,我们要知道,一个对象,它的原型链上有那些原型,应该怎么找呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

function Cat() {
this.climb = function() {
alert('爬树');
}
}

function Tiger() {
this.hunt = function() {
alert('打猎');
}
}

Tiger.prototype = new Cat(); // 让老虎的设计图,以一种小猫为原型,继承

var tiger = new Tiger();
// tiger.hunt(); //打猎
// tiger.climb(); //爬树

console.log(tiger.__proto__); // Cat;
console.log(tiger.__proto__.__proto__); //constructor

这里,我们再进一步,比如,我们给这只老虎,再添加飞的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

function Cat() {
this.climb = function() {
alert('爬树');
}
}

function Bird() {
this.fly = function() {
alert('飞翔');
}
}

function Tiger() {
this.hunt = function() {
alert('打猎');
}
}

Tiger.prototype = new Cat();
var tiger = new Tiger();
tiger.climb(); //爬树
tiger.hunt(); //打猎

Tiger.prototype = new Bird();
tiger = new Tiger(); // 这里如果不 new 一次,将不能继承 Bird 的属性。
tiger.fly(); //飞翔

原型链的顶部是一个对象,那么如果,我们在这个根对象里,添加一个方法,会怎么样呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

function Cat() {
this.climb = function() {
alert('爬树');
}
}

function Bird() {
this.fly = function() {
alert('飞翔');
}
}

function Tiger() {
this.hunt = function() {
alert('打猎');
}
}


Tiger.prototype = new Cat();
var tiger = new Tiger();
tiger.climb(); //爬树
tiger.hunt(); //打猎

Tiger.prototype = new Bird();
tiger = new Tiger(); // 这里如果不 new 一次,将不能继承 Bird 的属性。
tiger.fly(); //飞翔

Object.prototype.say = function () {
alert('say...');
}

var dt = new Date();
dt.say(); //事实就是,原型链上,所有 new 出来的新对象,都有了 say() 方法

原型冒充

比如说,邻居家有个小孩,非常聪明,智商很高,你的父母觉得,那么才能把人家的机智聪瑾给 copy 过来就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

function Good() {
this.iq = 240;
this.study = function() {
alert('学习聪明');
}
}

function Bad() {
this.play = function() {
alert('只会玩');
}
}

怎么做呢?

function Bad() {
Good.call(this); // 只要把 Good 的 this 通过 call 方法改变它的指向,就可以
this.play = function() {
alert('只会玩');
}
}
var bad = new Bad();
console.log(bad);

//打印结果

Bad {iq: 240, study: ƒ, play: ƒ};

这里就有了,Good的相关属性。

复制继承

有时候,我们希望简单粗暴一点的,获得前面对象的所有属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function Good() {
this.iq = 240;
this.study = function() {
alert('学习聪明');
}
}

function Bad() {
this.play = function() {
alert('只会玩');
}
this.extend = function(obj) {
for (var k in obj) {
this[k] = obj[k];
}
}
}

var good = new Good();
var bad = new Bad();

bad.extend(bad); //继承
console.log(bad);

// 打印结果

Bad {play: ƒ, extend: ƒ};

函数也是对象

使用过jQuery的人,可能会熟悉jQuery的 $ 符号,**$** 后面是一个括号,说明它是一个函数,但是,我们用ajax的时候,又是用的 $.ajax,这说明什么呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

//字符串是对象

var str = 'hello world!';
str.substr(2,3);

//函数也是对象

var func = function (num1 , num2) {
return num1 + num2;
}

// 是对象当然有属性

console.log(func.length); //2,形参数量



//添加一个属性

func.ajax = function() {
alert('发送ajax请求!');
}