Cirry's Blog

面向对象和原型

2017-01-04
技术
js
最后更新:2024-04-02
13分钟
2451字

印象笔记迁移

面向对象函数

1
var box = new Object();
2
box.name = 'dog';
3
box.age = 20;
4
box.run = function () {
5
return this.name + this.age + 'gg';
6
};
7
alert(box.run());

创建同样的object:

1
var box = new Object(); //方法1
2
box.name = 'dog';
3
box.age = 20;
4
box.run = function () {
5
return this.name + this.age + 'gg';
6
};
7
var box2 = new Object(); //代码繁杂
8
box2.name = 'lv';
9
box2.age = 18;
10
box2.run = function () {
11
return this.name + this.age + 'gg';
12
};
13
alert(box.run());
14
alert(box2.run());
1
var box = new Object();
2
box.name = 'dog';
3
box.age = 20;
4
box.run = function () {
5
return this.name + this.age + 'gg';
6
};
7
var box2 = box; //方法2
8
box2.name = 'lv';
9
box2.age = 18;
10
box2.run = function () {
11
return this.name + this.age + 'gg';
12
};
13
alert(box.run()); //会有重复
14
alert(box2.run()); //结果box被box2覆盖

解决多个类似对象声明的问题:

1
//工厂模式
2
function createObject(name, age) {
3
var obj = new Object(); //创建对象
4
obj.name = name; //添加属性
5
obj.age = age;
6
obj.run = function () { //添加方法
7
return this.name + this.age + 'gg';
8
};
9
return obj; //返回对象引用
10
}
11
12
var box1 = createObject('dog', '20'); //创建第一个对象
13
var box2 = createObject('lv', '18'); //创建第二个对象
14
alert(box1.run()); //dog20gg
15
alert(box2.run()); //lv18gg
2 collapsed lines
16
alert(box1 instanceof Object);
17
alert(box2 instanceof Object); //他们都是object实例,无法分清到底是哪个object的实例
1
//构造函数
2
function Box(name, age) { //创建对象,所有构造函数的对象就是object
3
this.name = name; //添加一个属性
4
this.age = age;
5
this.run = function () { //添加方法
6
return this.name + this.age + 'gg';
7
}
8
}
9
10
function Desk(name, age) { //创建对象,所有构造函数的对象就是object
11
this.name = name; //添加一个属性
12
this.age = age;
13
this.run = function () { //添加方法
14
return this.name + this.age + 'gg';
15
}
22 collapsed lines
16
}
17
18
var box1 = new Box('dog', '20');
19
var box2 = new Box('lv', '18');
20
var box2 = new Desk('gg', 'gg');
21
alert(box1.run());
22
alert(box2.run());
23
alert(box1 instanceof Object); //true
24
alert(box1 instanceof Box); //true
25
alert(box3 instanceof Box); //false,此时可以识别了解决了工厂模式的对象识别问题
26
//1.构造函数没有new Object,但它会后台自动var obj = new Object
27
//2.this就相当于obj
28
//3.构造函数不需要返回对象引用,它是后台自动返回的
29
30
//规范:
31
//1. 构造函数也是函数,但函数名第一个字母大写
32
//2.必须new 构造函数名,new Box()
33
//3.必须使用new运算符
34
alert(Box('dog', '20')); //构造函数用普通函数方式调用,无效
35
var o = new Object();
36
Box.call(o, 'dog', '20'); //对象冒充
37
alert(o.run());

原型(共享)

1
function Box() {
2
}; //构造函数体内什么都没有,如果有,叫做实例属性,实例方法
3
Box.prototype.name = 'dog';
4
Box.prototype.age = 20;
5
Box.prototype.run = function () {
6
return this.name + this.age + 'gg';
7
};
8
var box1 = new Box();
9
var box2 = new Box();
10
alert(box1.name); //dog
11
alert(box1.run()); //dog20gg
12
//如果是实例方法,不同的实例化,他们的方法地址是不一样的,是唯一的
13
//如果是原型方法,那么他们的地址是共享的
14
alert(box1.run == box2.run); //true
15
alert(box1.prototype); //这个属性是个对象,访问不到
1 collapsed line
16
alert(box1.__proto__); //这个属性是一个指针指向prototype原型对象,ie不支持
1
function Box() {
2
};
3
Box.prototype.name = 'dog';
4
Box.prototype.age = 20;
5
Box.prototype.run = function () {
6
return this.name + this.age + 'gg';
7
};
8
var box1 = new Box();
9
var box2 = new Box();
10
alert(box1.constructor); //构造属性,可以获取构造函数本身
11
//判断一个对象实例,是不是指向了对象的原型对象,基本上只要实例化了,他是自动指向的
12
alert(Box.prototype.isPrototypeOf(box1));

原型函数执行流程:

  1. 先查找构造函数实例里的属性或方法,如果就返回;
  2. 如果构造函数实例里没有,就去原型对象里找,如果有就返回;
1
function Box() {
2
};
3
Box.prototype.name = 'dog';
4
Box.prototype.age = 20;
5
Box.prototype.run = function () {
6
return this.name + this.age + 'gg';
7
};
8
var box1 = new Box();
9
box1.name = 'lv';
10
alert(box1.name); //lv
11
delete box1.name; //删除实例中的属性
12
alert(box1.name); //dog
13
delete Box.prototype.name; //删除原型中的属性
14
Box.prototype.name = 'gg'; //覆盖原型中的属性
15
var box2 = new Box();
1 collapsed line
16
alert(box2.name); //dog
1
function Box() {
2
};
3
Box.prototype.name = 'dog';
4
Box.prototype.age = 20;
5
Box.prototype.run = function () {
6
return this.name + this.age + 'gg';
7
};
8
var box1 = new Box();
9
box1.name = 'dog';
10
alert(box1.hasOwnProperty('name')); //判断实例中是否存在指定属性
11
alert('name in box1'); //不管实例属性或原型属性是否存在,只要有就返回true,都没有就返回false
1
function Box() {
2
};
3
Box.prototype.name = 'dog';
4
Box.prototype.age = 20;
5
Box.prototype.run = function () {
6
return this.name + this.age + 'gg';
7
};
8
9
//判断只有原型中有属性
10
function isProperty(object, property) {
11
return !object.hasOwnProperty(property) && (property in object);
12
};
13
var box1 = new Box();
14
alert(isProperty(box1, 'name'));
1
alert(box.prototype); //使用对象实例无法访问到prototype
2
alert(box.__proto__); //使用对象实例访问prototype的指针
3
alert(Box.prototype); //使用构造函数名(对象名)访问prototype,结合前面的图看

使用字面量的方式创建原型对象:(new Object 相当于{})

1
Box.prototype = { //创建了一个新的对象
2
constructor: Box, //强制指向Box
3
name: 'dog',
4
age: 20,
5
run: function () {
6
return this.name + this.age + 'gg';
7
}
8
}; //字面量创建的方式使用constructor属性不会指向实例,而会指向object,构造函数相反,除非强制指向

原型声明被重写:

1
Box.prototype = {
2
constructor: Box,
3
name: 'dog',
4
age: 20,
5
run: function () {
6
return this.name + this.age + 'gg';
7
}
8
};
9
Box.prototype = { //不会保留之前原型的任何信息.把原来的原型对象和构造函数的连接切断了
10
age: 18
11
};
12
var box = new Box();
13
alert(box.age); //18
14
alert(box.run()); //box.run is not a function

其他类型的原型:

1
alert(Array.prototype.sort); //查看sort是否是Array原型对象里的方法
2
alert(String.prototype.substr);

扩展其他类型的原型:

1
alert(String.prototype.addstring); //undefined,检查
2
String.prototype.addstring = function () {
3
return this + ',被添加了';
4
}
5
var box = 'dog';
6
alert(box.addstring()); //dog,被添加了

原型的缺点:

1
function Box() {
2
};
3
Box.prototype = {
4
constructor: Box,
5
name: 'dog',
6
age: 20,
7
family: ['bro', 'sis'],
8
run: function () {
9
return this.name + this.age + 'gg';
10
}
11
};
12
var box1 = new Box();
13
alert(box1.family); //bro,sis
14
box1.family.push('didi'); //在第一个实例修改后,保持了共享
15
alert(box1.family); //bro,sis,didi
2 collapsed lines
16
var box2 = new Box();
17
alert(box2.family) //bro,sis,didi 共享了box1添加后的引用类型的原型

解决构造传参和共享问题,可以组合构造函数+原型模式:

1
function Box(name, age) { //保持独立的用构造函数
2
this.name = name;
3
this.age = age;
4
this.family = ['bro', 'sis'];
5
}
6
7
Box.prototype = { //保持共享的用原型
8
constructor: Box,
9
run: function () {
10
return this.name + this.age + 'gg';
11
}
12
};
13
var box1 = new Box('dog', 20);
14
alert(box1.run()); //dog20gg
15
var box2 = new Box('lv', 18);
4 collapsed lines
16
alert(box2.run()); //lv18gg
17
box1.family.push('didi');
18
alert(box1.family); //bro ,sis,didi
19
alert(box2.family); //bro,sis

动态原型模式:封装构造函数和原型模式:

1
function Box(name, age) {
2
this.name = name;
3
this.age = age;
4
this.family = ['bro', 'sis'];
5
alert('初始化开始');
6
Box.prototype.run = function () {
7
return this.name + this.age + 'gg';
8
};
9
alert('初始化结束');
10
}
11
12
var box1 = new Box();
13
var box2 = new Box(); //alert执行四次,然而原型初始化只要第一次初始化就可以了,没必要每次构造函数实例化的时候都初始化
1
function Box(name, age) {
2
this.name = name;
3
this.age = age;
4
this.family = ['bro', 'sis'];
5
if (typeof this.run != 'function') { //判断this.run是否存在
6
alert('初始化开始');
7
Box.prototype.run = function () {
8
return this.name + this.age + 'gg';
9
};
10
alert('初始化结束');
11
}
12
}
13
14
var box1 = new Box();
15
var box2 = new Box(); //只初始化一次

寄生构造函数 = 工厂模式 + 构造函数

1
function Box(namem, age) {
2
var obj = new Object();
3
obj.name = name;
4
obj.age = age;
5
obj.run = function () {
6
this.name + this.age + 'gg';
7
};
8
return obj;
9
}
10
var box1 = new Box('dog', 20);

稳妥构造函数:

1
function Box(name, age) {
2
var obj = new Object();
3
obj.name = name;
4
obj.age = age;
5
obj.run = function () {
6
this.name + this.age + 'gg';
7
};
8
return obj;
9
}
10
11
var box1 = Box('dog', 20); //不用new

继承:ECMAScript只支持继承,不支持接口实现,而实现继承的方法是依靠原型链

1
function Box() { //被继承的函数叫做超类型(父类,基类)
2
this.name = 'dog';
3
}
4
5
function Desk() { //继承的函数叫做子类型(子类,派生类)
6
this.age = 20;
7
}
8
9
function Table() {
10
this.level = 'aa';
11
}
12
13
var desk = new Desk();
14
alert(desk.age); //20
15
alert(desk.name); //undefined
5 collapsed lines
16
//通过原型链继承,超类型实例化后的对象实例,赋值给子类型的原型属性
17
//new Box()会将Box构造里的信息和原型里的信息都交给Desk
18
//Desk的原型,得到的是Box的构造和原型里的信息
19
Desk.prototype = new Box();
20
Table.prototype = new Desk();

继承中的小细节

1
function Box() {
2
this.name = 'dog';
3
}
4
5
Box.prototype.name = 'lv'
6
7
function Desk() {
8
this.age = 20;
9
}
10
11
Desk.prototype = new Box();
12
var desk = new Desk();
13
alert(desk.name); //dog,就近原则,先实例,后原型
14
//子类型从属于自己或者他的超类型
15
alert(desk instanceof Desk); //true
4 collapsed lines
16
alert(desk instanceof Box); //true
17
alert(desk instanceof Object);
18
true
19
alert(Box instanceof Desk); //false

解决引用共享和超类型无法传参的问题:(对象冒充):

1
function Box(name, age) {
2
this.name = name;
3
this.age = age;
4
this.family = ['bro', 'sis'];
5
}
6
7
Box.prototype.family = 'home';
8
9
function Desk(name, age) {
10
Box.call(this, name, age); //对象冒充,只能继承构造里的信息.原型里的不行
11
}
12
13
var desk = new Desk('dog', 20);
14
alert(desk.name);
15
alert(desk.family);
1 collapsed line
16
alert(desk.fanily);

原型式继承:

1
function obj(o) { //临时中转函数
2
function F() {
3
}; //F构造是个临时新建的对象,用来存储传递过来的对象
4
F.prototype = o; //将o对象实例赋值给F构造的原型对象
5
return new F(); //最后返回这个得到传递过来对象的对象实例
6
}
7
8
var box = { //这是字面量的声明方式,相当于var box = new Box();
9
name: 'dog',
10
age: 20,
11
family: ['bro', 'sis']
12
};
13
//box1就等于new F()
14
var box1 = obj(box);
15
alert(box1.name);
5 collapsed lines
16
alert(box1.family);
17
box1.family.push('didi');
18
alert(box1.family);
19
var box2 = obj(box);
20
alert(box2.family); //原型继承共享了

寄生式继承 = 原型式 +工厂模式

1
function obj(o) { //临时中转函数
2
function F() {
3
};
4
F.prototype = o;
5
return new F();
6
}
7
8
function create(o) { //寄生函数
9
var f = obj(o);
10
f.run = function () {
11
return this.name + 'gg';
12
};
13
}
14
15
var box = {
6 collapsed lines
16
name: 'dog',
17
age: 20,
18
family: ['bro', 'sis']
19
};
20
var box1 = create(box);
21
alert(box1.run());

寄生组合继承:

1
function obj(o) { //临时中转函数
2
function F() {
3
};
4
F.prototype = o;
5
return new F();
6
}
7
8
function create(box, desk) { //寄生函数
9
var f = obj(box.prototype);
10
f.constructor = desk; //调整原型构造指针
11
desk.prototype = f;
12
}
13
14
function Box(name, age) {
15
this.name = name;
15 collapsed lines
16
this.age = age;
17
}
18
19
function Desk(name, age) {
20
Box.call(this, name, age); //对象冒充
21
}
22
23
Box.prototype.run = function () {
24
return this.name + this.age + 'gg';
25
}
26
//通过寄生组合继承来实现继承
27
create(Box, Desk);
28
var desk = new Desk('lv', 18);
29
alert(desk.run());
30
alert(desk.constructor);
本文标题:面向对象和原型
文章作者:Cirry
发布时间:2017-01-04
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
感谢大佬送来的咖啡☕
alipayQRCode
wechatQRCode