面向对象与面向过程的区别:
面向过程

面向对象

*** √Tips:面向过程思想注重具体的步骤;面向对象思想注重的是一个个对象。面向对象思想可以使代码结构清晰、层次分明,所以它可以帮助团队更好的分工协助,提高开发效率。
面向对象的特征:主要包括封装性、继承性和多态性
1、封装性(表单生成器)
封装指的是隐藏内部的实现细节,只对外开放操作接口
(function(window) {
var FormBuilder =function(data) {
this.data = data;
};
window.FormBuilder =FormBuilder;
})(window);
上述代码将表单生成器封装成一个构造函数。其中最外层是一个自调用的匿名函数,在调用时传入的window对象用于控制FormBuilder库的作用范围,再通过window.FormBuilder =FormBuilder;将FormBuilder作为传入对象的属性;
在匿名函数中定义的变量、函数都不会污染全局作用域,体现了面向对象的封装性。
2、继承性
继承是指一个对象继承另一个对象的成员,从而在不改变另一个对象的前提下进行扩展
(1)、利用原型对象实现继承
如果一个对象中本来没有某个属性或方法,但可以从另一个对象中获得即继承
function Person(name) {
this.name = nam`e;
}
Person.prototype.sayHello =function () {
console.log('你好,我是' +this.name);
}
var p1 =new Person('Jim');
var p2 =new Person('Tom');
p1.sayHello();// 输出结果:你好,我是Jim
p2.sayHello();// 输出结果:你好,我是 Tom
//p1、p2本无sayHello()成员,但在构造函数Person的原型对象添加了sayHello()成员后,p1、p2也拥有了sayHello()成员,即p1、p2对象继承了原型对象中的成员。
(2)替换原型对象实现继承
将构造函数的原型对象替换成另一个对象A,该构造函数创建的对象就会继承新的原型对象
function Person() {}// 构造函数Person原本有一个原型对象prototype
Person.prototype = {// 将构造函数的prototype属性指向一个新的对象
sayHello:function () {// 在新的对象中定义一个sayHello()方法用于测试
console.log('你好,我是新对象');
}
}
var p =new Person();
p.sayHello();// 输出结果:你好,我是新对象
在基于构造函数创建对象时,代码应写在替换原型对象之后
function Person() {}
Person.prototype.sayHello =function() {
console.log('原来的对象');
}
var p1 =new Person();
Person.prototype = {
sayHello:function(){
console.log('替换后的对象');
}
}
var p2 =new Person();
p1.sayHello();// 输出结果:原来的对象
p2.sayHello();// 输出结果:替换后的对象
//在通过替换原型对象的方式实现继承时要注意代码编写的顺序
(3)利用Object.create()实现继承
var obj = {
sayHello:function(){
console.log('我是一个带有sayHello方法的对象');
}
};
var newObj =Object.create(obj);
newObj.sayHello();// 输出结果:我是一个带有sayHello方法的对象
newObj.__proto__ ===obj;// 返回结果:true
//上述代码实现了将obj对象作为newObj对象原型,newObj对象继承了obj对象的sayHello()方法
(4)混入继承
将一个对象的成员加入到另一个对象中,实现对象功能的扩展
var o1 = {};
var o2 = {name:'Jim'};
o1.name =o2.name;// o1继承o2的name属性
console.log(o1.name);// 输出结果:Jim
当对象成员比较多时,可以编写一个函数专门实现对象成员的赋值,函数通常命名为mix(混合)或extend(扩展)
// 编写extend函数
function extend(o1, o2) {
for (var k in o2) {
o1[k] = o2[k];
}
}
// 测试extend函数
var o1 = {name:'Jim'};
var o2 = {age:16,gender:'male'};
extend(o1,o2);// 将o2的成员添加给o1
console.log(o1.name);// 输出结果:Jim
console.log(o1.age);// 输出结果:16
混入式继承和原型继承还可以组合在一起使用,实现以对象的方式传递参数,或以对象的方式扩展原型对象成员
function Person(options) {
// 调用前面编写的extend(),将传入的options对象的成员添加到实例对象中
extend(this, options);
}
Person.fn =Person.prototype;// 将prototype属性简化为fn方便代码书写
Person.fn.extend =function(obj) {
extend(this, obj);// 此处的this相当于Peron.prototype
};
//以此之下五行代码演示了以对象的方式扩展原型对象的成员,当需要为原型对象一次添加多个成员时,使用这种方式会非常方便,只需将这些成员保存到一个对象中,再调用extend()方法来继承
Person.fn.extend({
sayHello:function() {
console.log('你好,我是' + (this.name ||'无名'));
}
});
var p1 =new Person();
var p2 =new Person({name:'张三',age:16});//通过Person()构造函数创建对象时传入了对象形式的参数,这种传递参数的方式相比传递多个参数更加灵活
p1.sayHello();// 输出结果:你好,我是无名
p2.sayHello();// 输出结果:你好,我是张三
3、多态性
多态指的是同一个操作作用于不同的对象,会产生不同的执行结果。JavaScript中一个变量可以存储任意类型的数据就是多态性的体现。其中如数字、数组、函数都具有toString()方法,当使用不同的对象调用该方法时,执行不同的结果。
var obj =123;
console.log(obj.toString());// 输出结果:123
obj = [1,2,3];
console.log(obj.toString());// 输出结果:1,2,3
obj =function() {};
console.log(obj.toString());// 输出结果:function () {}
//面向对象中,多态性的实现基本离不开继承。因为当多个对象继承了同一个对象后,就获得了相同的方法,然而根据每个对象的需求来改变同名方法的执行结果。
ps:例子程序
包含了一些面向对象属性的特性
var elements = [
{tag: 'input', text: '姓名:', attr: {type: 'text', name: 'user'}},//将姓名:<input type="text" name="user">转化为对象
{tag: 'input', text: '性别:', attr: {type: 'radio', name: 'gender'}, option: {m: '男', w: '女'}},
{tag: 'input', text: '爱好:', attr: {type: 'checkbox', name: 'hobby[]'}, option: {swimming: '游泳', reading: '读书', running: '跑步'}},
{tag: 'select', text:'住址:', attr: {name: 'area'}, option: {'': '--请选择--', bj: '北京', sh: '上海', sz: '深圳'}},
{tag: 'textarea', text: '自我介绍:', attr: {name: 'introduce', cols:'50', rows: '5'}},
{tag: 'input', attr: {type: 'submit', value: '确定'}}
];
//上述代码中,每个表单项都具有tag、text、attr和option4个属性,表示它们具有相同的特征。而每个表单项的标签名、提示文本、属性值是不同的,这表示每个对象都有不同之处
document.getElementById('form').innerHTML = new FormBuilder(elements).create();
//封装表单生成器,前面有详解
(function(window) {
var FormBuilder = function(data) {
this.data = data;
};
//接下来的所有代码都是为了实现表单的自动生成
//编写create()方法
FormBuilder.prototype.create = function() {
var html = '';
for (var k in this.data) {//this.data表示传入的elements数组
var item = {tag: '', text: '', attr: {}, option: null};
for (var n in this.data[k]) {//接下来7行代码遍历整个数组
item[n] = this.data[k][n];
}
html += builder.toHTML(item);
}
return '<table>' + html + '</table>';
};//上述11行代码实现了表单的自动的生成
//编写builder对象,builder是封装在匿名函数内部的对象,专门用于对每一种表单项进行生成
var builder = {
toHTML: function(obj) {
var html = this.item[obj.tag](this.attr(obj.attr), obj.option);
return '<tr><th>' + obj.text + '</th><td>' + html + '</td></tr>';
},//上述3行代码中,“this.item[obj.tag]()”用于根据obj.tag的值来调用item对象中的方法。当obj.tag的值为input时,就表示调用builder.item.input()方法
//接下来编写attr()方法,实现将“{type:'text',name:'user'}”形式的对象转换为“type="text" name="user"”形式的HTML字符串
attr: function(attr) {
var html = '';
for(var k in attr) {
html += k + '="' + attr[k] + '" ';
}
return html;
},
//编写item对象
item: {
input: function(attr, option) {
var html = '';
if (option === null) {//通过判断option是否为null,来区分单个控件和组合控件
html += '<input ' + attr + '>';
} else {
for (var k in option) {
html += '<label><input ' + attr + 'value="' + k + '"' + '>' + option[k] + '</label>';//在生成组合控件时使用label标签包裹input标签,这样可以扩大选择范围,当单击提示文本时,相应的表单控件就会被选中
}
}
return html;
},
select: function(attr, option) {
var html = '';
for (var k in option) {
html += '<option value="' + k + '">' + option[k] + '</option>';
}
return '<select ' + attr +'>' + html + '</select>';
},
//编写item对象中的textarea()方法
textarea: function(attr) {
return '<textarea ' + attr + '></textarea>';
}
}
};
window.FormBuilder = FormBuilder;
})(window);