一般面向对象包含:继承,封装,多态,抽象
对象形式的继承
浅拷贝
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
|
var Person = {
name:
'allin',
age:
18,
address: {
home:
'home',
office:
'office',
}
sclools: [
'x',
'z'],
};
var programer = {
language:
'js',
};
function extend(p, c){
var c = c || {};
for(
var prop
in p){
c[prop] = p[prop];
}
}
extend(Person, programer);
programer.name;
// allin
programer.address.home;
// home
programer.address.home =
'house';
//house
Person.address.home;
// house
|
- 从上面的结果看出,浅拷贝的缺陷在于修改了子对象中引用类型的值,会影响到父对象中的值,因为在浅拷贝中对引用类型的拷贝只是拷贝了地址,指向了内存中同一个副本
深拷贝
1
2
3
4
5
6
7
8
9
10
11
|
function extendDeeply(p, c){
var c = c || {};
for (
var prop
in p){
if(
typeof p[prop] ===
"object"){
c[prop] = (p[prop].constructor ===
Array)?[]:{};
extendDeeply(p[prop], c[prop]);
}
else{
c[prop] = p[prop];
}
}
}
|
- 利用递归进行深拷贝,这样子对象的修改就不会影响到父对象
1
2
3
|
extendDeeply(Person, programer);
programer.address.home =
'allin';
Person.address.home;
// home
|
利用call和apply继承
1
2
3
4
5
6
7
8
|
function Parent(){
this.name =
"abc";
this.address = {
home:
"home"};
}
function Child(){
Parent.call(
this);
this.language =
"js";
}
|
ES5中的Object.create()
1
2
3
|
var p = {
name :
'allin'};
var obj =
Object.create(o);
obj.name;
// allin
|
-
Object.create()
作为new
操作符的替代方案是ES5
之后才出来的。我们也可以自己模拟该方法:
1
2
3
4
5
6
7
8
9
10
|
//模拟Object.create()方法
function myCreate(o){
function F(){};
F.prototype = o;
o =
new F();
return o;
}
var p = {
name :
'allin'};
var obj = myCreate(o);
obj.name;
// allin
|
- 目前,各大浏览器的最新版本(包括
IE9
)都部署了这个方法。如果遇到老式浏览器,可以用下面的代码自行部署
1
2
3
4
5
6
7
|
if (!
Object.create) {
Object.create =
function (o) {
function F() {}
F.prototype = o;
return
new F();
};
}
|
类的继承
Object.create()
1
2
3
4
5
6
7
8
9
|
function Person(name, age){}
Person.prototype.headCount =
1;
Person.prototype.eat =
function(){
console.log(
'eating...');
}
function Programmer(name, age, title){}
Programmer.prototype =
Object.create(Person.prototype);
//建立继承关系
Programmer.prototype.constructor = Programmer;
// 修改constructor的指向
|
调用父类方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.headCount =
1;
Person.prototype.eat =
function(){
console.log(
'eating...');
}
function Programmer(name, age, title){
Person.apply(
this,
arguments);
// 调用父类的构造器
}
Programmer.prototype =
Object.create(Person.prototype);
Programmer.prototype.constructor = Programmer;
Programmer.prototype.language =
"js";
Programmer.prototype.work =
function(){
console.log(
'i am working code in '+
this.language);
Person.prototype.eat.apply(
this,
arguments);
// 调用父类上的方法
}
|
封装
命名空间
-
js
是没有命名空间的,因此可以用对象模拟
1
2
3
4
5
6
7
8
9
10
|
var app = {};
// 命名空间app
//模块1
app.module1 = {
name:
'allin',
f:
function(){
console.log(
'hi robot');
}
};
app.module1.name;
// "allin"
app.module1.f();
// hi robot
|
静态成员
1
2
3
4
5
6
7
8
9
|
function Person(name){
var age =
100;
this.name = name;
}
//静态成员
Person.walk =
function(){
console.log(
'static');
};
Person.walk();
// static
|
私有与公有
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
function Person(id){
// 私有属性与方法
var name =
'allin';
var work =
function(){
console.log(
this.id);
};
//公有属性与方法
this.id = id;
this.say =
function(){
console.log(
'say hello');
work.call(
this);
};
};
var p1 =
new Person(
123);
p1.name;
// undefined
p1.id;
// 123
p1.say();
// say hello 123
|
模块化
1
2
3
4
5
6
7
8
9
10
11
|
var moduleA;
moduleA =
function() {
var prop =
1;
function func() {}
return {
func: func,
prop: prop
};
}();
// 立即执行匿名函数
|
多态
模拟方法重载
-
arguments
属性可以取得函数调用的实参个数,可以利用这一点模拟方法的重载
1
2
3
4
5
6
7
8
|
function demo(a, b ){
console.log(demo.length);
// 得到形参个数
console.log(
arguments.length);
//得到实参个数
console.log(
arguments[
0]);
// 第一个实参 4
console.log(
arguments[
1]);
// 第二个实参 5
}
demo(
4,
5,
6);
|
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 add(){
var total =
0;
for(
var i =
arguments.length -
1; i >=
0; i--){
total +=
arguments[i];
}
return total;
}
console.log(add(
1));
// 1
console.log(add(
1,
2,
3));
// 7
// 参数不同的情况
function fontSize(){
var ele =
document.getElementById(
'js');
if(
arguments.length ==
0){
return ele.style.fontSize;
}
else{
ele.style.fontSize =
arguments[
0];
}
}
fontSize(
18);
console.log(fontSize());
// 类型不同的情况
function setting(){
var ele =
document.getElementById(
'js');
if(
typeof
arguments[
0] ===
"object"){
for(
var p
in
arguments[
0]){
ele.style[p] =
arguments[
0][p];
}
}
else{
ele.style.fontSize =
arguments[
0];
ele.style.backgroundColor =
arguments[
1];
}
}
setting(
18,
'red');
setting({
fontSize:
20,
backgroundColor:
'green'});
|
方法重写
1
2
3
4
5
6
7
8
9
10
11
|
function F(){}
var f =
new F();
F.prototype.run =
function(){
console.log(
'F');
}
f.run();
// F
f.run =
function(){
console.log(
'fff');
}
f.run();
// fff
|
抽象类
- 在构造器中
throw new Error('')
; 抛异常。这样防止这个类被直接调用