概念相关
面向对象的核心
目的
- 改善重用性
- 提升重用性
原则:开放封闭原则
- 对于扩展是开放的:当应用的需求改变时,可以对模块进行扩展,使其满足那些改变的新行为
- 对于修改是封闭的:对模块行为进行扩展时,不必改动模块的源代码或二进制代码
三要素: 继承、封装和多态
- 继承:指一个对象直接使用另一个对象的属性和方法
- 封装:指不暴露对象的属性和内部实现细节,只对外提供接口
- 多态:指对于同一行为(方法)具有不同的表现形式或行为
js中new操作符执行了哪些操作
有如下代码:
function Temp(name){
this.name = name;
}
Temp.prototype = function(){
console.log(this.name);
}
var obj = new Temp('hexon');
上面的new操作符执行了如下这么四步操作:
- 创建一个空对象obj(这个名字是假设的),并将this指向obj
- 将
this.__proto__
指向它的构造函数的原型Temp.prototype
(假设Temp为构造函数) - 执行Temp构造函数中的代码
- 返回obj对象
构造函数的继承
在实际应用中,经常需要一个构造函数继承另一个构造函数;可以分成两步实现:
- 在子类的构造函数中,调用父类的构造函数
```
function Sub(value) {
Super.call(this);
this.prop = value;
}
```
Sub是子类的构造函数,this是子类的实例,在实例上调用父类的构造函数**Super**,就会让子类拥有父类的**实例属性**
注意: call表示在调用Super构造函数时将其内部的this指向Sub实例
经过第一步后,子类只是拥有了父类的**实例属性**,但是其原型链上属性和方法并没有获取到,可以通过`console.log(子类实例.__proto__);` 打印出它的原型
- 让子类的原型指向父类的原型,这样子类就可以继承父类原型
```
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.method = '...';
```
举例说明:
function Shap() {
this.x = 0;
this.y = 0;
}
Shap.prototype.move = function(x, y){
this.x = x;
this.y = y;
console.log('Shap move: ', x+y);
};
function Rectangle() {
Shap.call(this);
}
Rectangle.prototype = Object.create(Shap.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
rect.print();
多重继承:
function M1() {
this.hello = 'hello';
}
function M2() {
this.world = 'world';
}
function S() {
M1.call(this);
M2.call(this);
}
S.prototype = M1.prototype;
var s = new S();
s.hello // 'hello'
s.world // 'world'
模块化
封装私有变量:立即执行函数的写法
通过立即执行函数,将对象的私有变量和方法封装在一个函数作用域里面,可以达到不暴露私有成员的目的
var module1 = (function(){
var _count = 0; //
var m1 = function() {
// somecode
};
var m2 = function() {
// somecode
};
return {
m1: m1,
m2: m2
};
})();
通过一个立即执行函数将私有成员封装起来
console.log(module1._count); // 输出: undefined,因为返回的对象中没有包含_count
模块的放大模式
有时候一个模块很大,必须分成好几个部分;或者一个模块需要继承好几个模块,这时有必要采用“放大模式”(argumentation)
var module2 = (function(mod){
mod.m3 = function(){
};
return mod;
})(module2);
console.log(module2.m3);
上面代码,为module2添加一个新方法,然后返回module2;
很多时候,模块的各个部分来自网上,有时无法知道哪个模块先加载,如果采用上面的方法,很可能module2没有加载完就使用,很可能出现错误,因此需要使用“宽放大模式”(loose argumentation),如下:
var module3 = (function(mod){
// ...
return mod;
})(window.module3 || {})
输入全局变量
独立性是模块的重要特点,模块内部最好不与程序的其他部分交互
为了在模块内部使用全局变量,必须要将其作为参数传入,
var module1 = (function ($, YAHOO) {
//...
})(jQuery, YAHOO);
module1需要使用jQuery和YAHOO两个库,就将其作为参数引入即可
立即执行函数可以起到命名空间的作用
(function($, window, document) {
function go(num) {
}
function handleEvents() {
}
function initialize() {
}
function dieCarouselDie() {
}
//attach to the global scope
window.finalCarousel = {
init : initialize,
destroy : dieCouraselDie
}
})( jQuery, window, document );
上面代码中,finalCarousel对象输出到全局,对外暴露init和destroy接口,内部方法go、handleEvents、initialize、dieCarouselDie都是外部无法调用的。