【JavaScript编程】面向对象

面向对象


定义
  • 内存中同时存储多个数据和功能的存储空间;
  • 描述现实中一个具体事物的属性和功能的程序结构;
  • 事物的属性,会成为对象中的属性;
  • 事物的功能,会成为对象中的方法;
使用
  • 在开始写程序前,都要先用对象,描述好要操作的事物的属性和功能;
  • 再按需使用对象的功能,访问对象的属性。
本质
  • js中一切对象的底层都是关联数组。
  • 每个属性/方法都是关联数组中的元素。
  • 属性名/方法名是key,属性值/函数对象是value。
三大特点
  • 封装
  • 继承
  • 多态 (抽象)

一、封装(定义对象)


定义:将一个具体事物的属性和功能集中定义在一个对象中。


1、对象字面量的方式
var obj = { name: "张三" }
2、创建 0bject 对象
// 创建对象
var obj = new Object();
// 自定义对象的属性和方法
obj.name = "张三";
obj.showname = function(){
    alert(this.name)
};
3、使用构造函数

专门描述一类对象统一结构的函数

  • 只要反复创建多个相同结构的对象时,都要先定义构造函数
  • 复用对象的结构代码
  • 只能复用代码,不能节约内存

创建构造函数

function Parent(name, sex){
    this.name = name;
    this.sex = sex;
}
Parent.prototype.show = function(){ // 提高性能
    return this.name + "-" + this.sex;
};

调用构造函数

  • new 后面就是构造函数;
  • 当 new 调用一个函数的时候,这个函数中的 this 就是创建出的对象;
  • 而且函数的返回值就是 this (隐式返回)。
var p1 = new Parent('张三', "男");
var p2 = new Parent('李四', "女");

console.log(p1.__proto__ == Parent.prototype); // true

new 做的4件事

  • 创建新的空对象;
  • 让新对象继承构造函数的原型对象;
  • 用新对象去调用构造函数,按需访问对象的属性,调用对象的方法;
  • 将新对象的地址保存在变量。

二、继承


定义:子类可以继承父类的一些功能,但不影响父类,以达到代码复用。


1、构造函数绑定

使用 call | apply | bind 方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:

function Child(name, sex){
	Parent.apply(this, arguments);
    this.age = 28;
}

解读:

callapply 的第一个参数都是要绑定的子对象,后面的参数就是要传递给父对象的参数。不同的是 apply 是以数组的形式传递。

Parent.call(this, name, sex)

bind 参数和 call 一样,但是需要手动执行。

Parent.bind(this, name, sex)()

2、原型继承
function Child(){
    this.age = 28;
}

Child.prototype = new Parent();
Child.prototype.constructor = Child;

var c1 = new Child();

解读:

将 Child 的prototype对象指向一个 Parent 的实例。它相当于完全删除了prototype 对象原先的值,然后赋予一个新值。

Child.prototype = new Parent();

任何一个 prototype 对象都有一个constructor属性,指向它的构造函数。如果没有 “Child.prototype = new Parent();” 这一行,Child.prototype.constructor 是指向 Child 的;加了这一行以后,Child.prototype.constructor 指向 Parent。

console.log(Child.prototype.constructor === Parent); // true

更重要的是,每一个实例也有一个constructor属性,默认调用prototype对象的constructor属性。

console.log(c1.constructor === Child.prototype.constructor); // true

因此,在运行"Child.prototype = new Parent();"这一行之后,c1.constructor也指向Parent。

console.log(c1.constructor === Parent); // true

这显然会导致继承链的紊乱(c1 明明是用构造函数 Child 生成的),因此我们必须手动纠正,将 Child.prototype 对象的 constructor 值改为 Child。


缺点:该方法需要执行和建立 Parent 的实例了,比较耗内存。


3、利用空对象作为中介
function extend(Child, Parent) {
  var F = function(){};
  F.prototype = Parent.prototype;
  Child.prototype = new F();
  Child.prototype.constructor = Child;
  Child.uber = Parent.prototype;
}

uber属性:这个属性直接指向父对象的prototype属性。(uber是一个德语词,意思是"向上"、“上一层”。)这等于在子对象上打开一条通道,可以直接调用父对象的方法。这一行放在这里,只是为了实现继承的完备性,纯属备用性质。

优点:该方法是针对上一方法的不足而改进的, F是空对象,所以几乎不占内存(这个extend函数,就是YUI库如何实现继承的方法。)


4、拷贝继承
function extend2(Child, Parent) {
	var p = Parent.prototype;
	var c = Child.prototype;
	for (var i in p) {
		c[i] = p[i];
	}
	c.uber = p;
}

三、多态


定义
  • 同一个行为具有多个不同表现形式或形态的能力。
  • 同一操作(方法)作用于不同的对象上面,可以产生不同的解释和不同的执行结果。
实例

Martin Fowler 在《重构:改善既有代码的设计》里写到:

在电影的拍摄现场,当导演喊出“action”时,主角开始背台词,照明师负责打灯光,后面的群众演员假装中枪倒地,道具师往镜头里撒上雪花。在得到同一个消息时,每个对象都知道自己应该做什么。如果不利用对象的多态性,而是用面向过程的方式来编写这一段代码,那么相当于在电影开始拍摄之后,导演每次都要走到每个人的面前,确认它们的职业分工(类型),然后告诉他们要做什么。如果映射到程序中,那么程序中将充斥着条件分支语句。

下面是使用条件分支语句,如果增加一个角色,就必须修改 action 方法:

var action = function(person){
    if (person instanceof p1){
        console.log( '背台词' );
    }
    else if (person instanceof p2){
        console.log( '打灯光' );
    }
}

var p1 = function(){}
var p2 = function(){}

action(new p1()) // 背台词
action(new p2()) // 打灯光

使用对象的多态性

var action = function(person){
	person.do()
}

var p1 = function(){}
p1.prototype.do = function(){
    console.log( '背台词' );
};

var p2 = function(){}
p2.prototype.do = function(){
    console.log( '打灯光' );
};

var p3 = function(){}
p2.prototype.do = function(){
    console.log( '撒雪花' );
};

action(new p1()) // 背台词
action(new p2()) // 打灯光
action(new p3()) // 撒雪花
优点
  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化性

四、系统对象


本地对象

非静态对象:Array Object 等可以new实例化的对象

内置对象

静态对象:Math 等不可以实例化的对象

宿主对象:

DOM(document)、BOM(window)等

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值