Cirry's Blog

面向对象和原型

Jan 4, 2017
技术 js
13分钟
2445字

印象笔记迁移

面向对象函数

var box = new Object();
box.name = 'dog';
box.age = 20;
box.run = function () {
return this.name + this.age + 'gg';
};
alert(box.run());

创建同样的object:

var box = new Object(); //方法1
box.name = 'dog';
box.age = 20;
box.run = function () {
return this.name + this.age + 'gg';
};
var box2 = new Object(); //代码繁杂
box2.name = 'lv';
box2.age = 18;
box2.run = function () {
return this.name + this.age + 'gg';
};
alert(box.run());
alert(box2.run());
var box = new Object();
box.name = 'dog';
box.age = 20;
box.run = function () {
return this.name + this.age + 'gg';
};
var box2 = box; //方法2
box2.name = 'lv';
box2.age = 18;
box2.run = function () {
return this.name + this.age + 'gg';
};
alert(box.run()); //会有重复
alert(box2.run()); //结果box被box2覆盖

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

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

原型(共享)

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

原型函数执行流程:

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

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

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

原型声明被重写:

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

其他类型的原型:

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

扩展其他类型的原型:

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

原型的缺点:

function Box() {
};
Box.prototype = {
constructor: Box,
name: 'dog',
age: 20,
family: ['bro', 'sis'],
run: function () {
return this.name + this.age + 'gg';
}
};
var box1 = new Box();
alert(box1.family); //bro,sis
box1.family.push('didi'); //在第一个实例修改后,保持了共享
alert(box1.family); //bro,sis,didi
2 collapsed lines
var box2 = new Box();
alert(box2.family) //bro,sis,didi 共享了box1添加后的引用类型的原型

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

function Box(name, age) { //保持独立的用构造函数
this.name = name;
this.age = age;
this.family = ['bro', 'sis'];
}
Box.prototype = { //保持共享的用原型
constructor: Box,
run: function () {
return this.name + this.age + 'gg';
}
};
var box1 = new Box('dog', 20);
alert(box1.run()); //dog20gg
var box2 = new Box('lv', 18);
4 collapsed lines
alert(box2.run()); //lv18gg
box1.family.push('didi');
alert(box1.family); //bro ,sis,didi
alert(box2.family); //bro,sis

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

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

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

function Box(namem, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function () {
this.name + this.age + 'gg';
};
return obj;
}
var box1 = new Box('dog', 20);

稳妥构造函数:

function Box(name, age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function () {
this.name + this.age + 'gg';
};
return obj;
}
var box1 = Box('dog', 20); //不用new

继承

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

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

default

继承中的小细节

function Box() {
this.name = 'dog';
}
Box.prototype.name = 'lv'
function Desk() {
this.age = 20;
}
Desk.prototype = new Box();
var desk = new Desk();
alert(desk.name); //dog,就近原则,先实例,后原型
//子类型从属于自己或者他的超类型
alert(desk instanceof Desk); //true
4 collapsed lines
alert(desk instanceof Box); //true
alert(desk instanceof Object);
true
alert(Box instanceof Desk); //false

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

function Box(name, age) {
this.name = name;
this.age = age;
this.family = ['bro', 'sis'];
}
Box.prototype.family = 'home';
function Desk(name, age) {
Box.call(this, name, age); //对象冒充,只能继承构造里的信息.原型里的不行
}
var desk = new Desk('dog', 20);
alert(desk.name);
alert(desk.family);
1 collapsed line
alert(desk.fanily);

原型式继承:

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

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

function obj(o) { //临时中转函数
function F() {
};
F.prototype = o;
return new F();
}
function create(o) { //寄生函数
var f = obj(o);
f.run = function () {
return this.name + 'gg';
};
}
var box = {
6 collapsed lines
name: 'dog',
age: 20,
family: ['bro', 'sis']
};
var box1 = create(box);
alert(box1.run());

寄生组合继承:

function obj(o) { //临时中转函数
function F() {
};
F.prototype = o;
return new F();
}
function create(box, desk) { //寄生函数
var f = obj(box.prototype);
f.constructor = desk; //调整原型构造指针
desk.prototype = f;
}
function Box(name, age) {
this.name = name;
15 collapsed lines
this.age = age;
}
function Desk(name, age) {
Box.call(this, name, age); //对象冒充
}
Box.prototype.run = function () {
return this.name + this.age + 'gg';
}
//通过寄生组合继承来实现继承
create(Box, Desk);
var desk = new Desk('lv', 18);
alert(desk.run());
alert(desk.constructor);
本文标题:面向对象和原型
文章作者:Cirry
发布时间:Jan 4, 2017
感谢大佬送来的咖啡☕
alipayQRCode
wechatQRCode
总访问量
总访客数人次