一、面向对象
1. 编程思想
-
面向过程编程(POP, Process-oriented programming):分析解决问题的步骤,按照步骤解决问题。
优点:性能高,适合与硬件联系紧密的东西。
缺点:不易维护、复用、扩展。 -
面向对象编程(OOP, Object-oriented programming):以对象功能划分问题,由对象之间分工合作解决。
优点:可以设计出低耦合、灵活、易维护、复用、扩展的大型系统。
缺点:性能比面向过程低。面向对象三大特性:封装性、继承性、多态性。
2. ES6类和对象
-
对象:特指一个实例化的具体的对象,由属性(特征)和方法(行为)组成。
-
类:泛指某一大类,抽象化对象的公共属性和方法封装成一个类。
// 创建类[类首字母大写] class Star{ // 构造函数[类自动生成该函数,创建实例时自动调用该函数] constructor(uname,age){ // 共有属性 this.uname = uname; this.age = age; } // 类中函数不需要加function // 多个函数方法之间不需要添加逗号分隔 sing(song) { console.log(this.uname + song); } } // 创建类的实例--对象 var ldh = new Star('刘德华', 18) ldh.sing('冰雨') // 刘德华冰雨
3. 类的继承
extends
关键字用于继承父类。
super
关键字用于访问和调用父类的函数。可以为构造函数/普通函数。
class Son extends Father {
constructor(x, y) {
// super(x,y)调用父类构造函数
// 必须先调用父类的构造方法,再使用子类构造方法
super(x, y);
this.x = x;
this.y = y;
}
say() {
// super.say()调用父类普通函数
console.log(super.say() + '的儿子');
}
}
【注意】
1)ES6中类没有变量提升,必须先定义类再实例化对象。
2)类里面的属性和方法一定要加this使用。
3)继承中的属性/方法查找为就近原则。
4)this指向问题:constructor里的this指向实例对象,方法里的this指向方法的调用者。
4. 面向对象案例:Tab对象
1)【切换功能】点击Tab栏切换相应内容项
2)【添加功能】点击+添加Tab栏和内容项
// insertAdjacentHTML()可以直接把字符串格式的元素追加到父元素指定位置
var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>';
ul.insertAdjacentHTML('beforeend', li);
3)【删除功能】点击x删除当前Tab栏和内容项
4)【修改功能】点击Tab栏或内容项文字可以修改文字内容
// ondblclick 双击事件
this.spans[i].ondblclick = this.editTab;
// 双击禁止选定文字
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
二、构造函数和原型
1. 构造函数
特殊的函数,ES6前用来初始化对象,与new一起使用。将对象中公共的属性和方法抽取出来封装到构造函数中。
// 创建某类对象时:首字母大写
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
// 与new一起使用,new执行时:
// 1)在内存中创建一个空对象
// 2)用this指向这个空对象
// 3)执行构造函数中的代码,为对象添加属性和方法
// 4)返回这个对象
var ldh = new Star('刘德华', 18);
2. 实例成员与静态成员
-
实例成员:构造函数内部,this添加的成员。
实例成员只能通过实例化的对象访问。console.log(ldh.sing())
-
静态成员:构造函数外部,构造函数本身添加的成员。
静态成员只能通过构造函数来访问。Star.sex='男' console.log(Star.sex)
3. 原型
1)构造函数存在的问题
构造函数定义的函数方法非共享,每创建一个对象实例就要开辟一块新的内存空间,存在浪费内存的问题。
2)原型
-
原型是一个对象:
prototype
对象
每一个构造函数都有一个prototype属性指向一个对象。这个对象的所有属性和方法为构造函数所有。 -
原型的作用为共享方法
将不变的方法直接定义在prototype对象上,所有的对象实例都可以共享这些方法。// 一般公共属性定义到构造函数中,公共方法定义到原型对象中 Star.prototype.sing = function() { console.log('我会唱歌'); }
3)对象原型
对象原型__proto__
指向构造函数的prototype
原型对象。它是非标准属性,在开发中不可以使用。
__proto__
与prototype
是等价的,因此对象可以使用构造函数prototype
原型对象的属性和方法。
4)constructor属性
__proto__
与prototype
都有一个constructor属性,指回构造函数本身。
Star.prototype = {
// 给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
constructor: Star,
sing: function() {
console.log('我会唱歌');
}
}
5)原型链
- 原型链成员查找规则:就近原则,没有则向上查找。
6)原型对象的应用
扩展内置对象方法:
Array.prototype.sum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
};
4. 继承
ES6前通过“构造函数+原型对象”实现继承,称为组合继承。
- 通过构造函数继承父类属性:通过
call( )
将父类的this指向子类型的this - 通过原型对象继承父类方法:通过new父类的实例传递原型对象的方法
// call(thisArg, arg1, arg2, ...) 可以改变函数的this指向
// 1)通过构造函数继承父类属性
function Father(uname, age) {
this.uname = uname;
this.age = age;
}
function Son(uname, age, score) {
// 此时Father的this指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score; // 子类的属性
}
var son = new Son