高级Js-面向对象编程
目录
- JavaScript Window-浏览器对象模型
- 匿名包装器
- 工厂方式
- 工厂方式改进版
- 同一个引用
- 构造函数与new命令
- prototype 对象
- 面向对象的写法
- 原型链
- 面向对象的继承
- 面向组件编程
- 命名空间
JavaScript Window-浏览器对象模型
浏览器对象模型(BOM)
- 所有浏览器都支持 window 对象. 它表示浏览器窗口.
- 全局变量是 window 对象的属性.
- 全局函数是 window 对象的方法.
- 甚至 HTML DOM 的 document 也是 window 对象的属性之一.
匿名包装器
- 使用匿名包装器来创建命名空间
(function() {
// 函数创建一个命名空间
window.foo = function() {
// 对外公开的函数,创建了闭包
};
})(); // 立即执行此匿名函数
解决的问题
- 使用全局变量的代码容易产生错误并且维护成本较高.
好处
- 不仅可以防止命名冲突, 而且有利于程序的模块化
工厂方式
function Stu(name, age) {
// 1. 创建对象
var obj = new Object();
// 2. 挂载属性
obj.name = name;
obj.age = age;
// 3. 导出对象
return obj;
}
var ostu = Stu("hvgege", 50);
console.log(ostu.name);
输出结果
hvgege
工厂方式改进版
function Stu(name) {
this.name = name; // 属性
this.showName = function() {//方法
console.log(this.name);
}
}
// 创建第一个对象
var p1 = new Stu('hvgege');
p1.showName();
// 创建第二个对象
var p2 = new Stu('hvge');
p2.showName();
// 判断两个对象方法的引用地址
console.log(p1.showName == p2.showName);
输出结果
hvgege
hvge
false
工厂方式构建对象的问题
- js会增大内存的开销,导致执行效率下降
- showName 方法是属于两个不同对象的, 即便方法名相同, 也是不等的.
- showName 方法是属于两个不同对象的, 即便方法名相同, 也是不等的.
同一个引用
var a = [1, 2, 3];
var b = a;
b.push(4);// 给数组添加值
console.log(a);
输出结果
(4) [1, 2, 3, 4]
代码解释
- 把数组的入口地址赋值给了b,a 和 b 在同一个引用上
构造函数与new命令
// 构造函数
function Stu(name, age) {
// 添加对象的属性
this.name = name;
this.age = age;
// 添加对象的方法
this.say = function() {
}
}
// new命令新建一个对象
var stu = new Stu("aa", 12);
console.log(stu);
输出结果
Stu {name: "aa", age: 12, say: ƒ}
构造函数
- JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype).
- JavaScript 语言使用构造函数(constructor)作为对象的模板.
- 一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构.
构造函数的特点
- 函数体内部使用了this关键字,代表了所要生成的对象实例.
- 生成对象的时候,必须使用new命令.
new命令
new命令的作用
- 执行构造函数,返回一个实例对象
prototype 对象
- JavaScript 语言的继承则是通过“原型对象”(prototype).
// 构造函数
function Animal(name, color) {
this.name = name;
}
// 添加原型对象的属性
Animal.prototype.say = '三毛';
// 新建两个对象
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
// 输出测试结果
console.log(cat1.name, cat2.name, cat1.say, cat2.say);
输出结果
大毛 二毛 三毛 三毛
JavaScript 继承机制的设计思想
- 原型对象的所有属性和方法,都能被实例对象共享.
原型对象的作用
- 定义所有实例对象共享的属性和方法.
- 解决工厂模式的问题.
面向对象的写法
// 第一段 构造函数
function 构造函数() {
this.属性
}
// 第二段 原型对象
构造函数.原型.方法 = function() {
// body...
}
// 第三段 实例化对象
var 对象1 = new 构造函数();
面向对象的写法
- 公共的属性和方法, 添加到原型上
面向对象程序的this指向
- 哪个对象调用了this所在成员方法,this就指向哪个对象
原型链
实例对象与原型之间的连接,叫做原型链
- 只要是处在原型链上的属性方法,我们都可以调用.
面向对象的继承
什么是继承
- 在原有对象的基础上,略作修改,得到一个新的对象
- 不影响原有对象的功能
实现继承属性
// 如何继承属性
function A(name){
this.name = name;
}
// 添加原型对象的属性
A.prototype.say = function(){
console.log(this.name);
};
// 实现继承属性
function B(name, age){
A.call(this, name);
this.age = age;
}
// 输出两对象情况
var oa = new A('hv');
console.log(oa);
var ob = new B('hvge', 18);
console.log(ob);
- 输出结果
A {name: "hv"} __proto__:say:ƒ ()
B {name: "hvge", age: 18} __proto__:
- call 方法
- 改变函数的 this 对象的指向
- 第一个参数是 this 指向的对象
- 可以利用后续参数传参
- 实现的效果
- 可以实现属性的继承
- 实现不了原型对象属性的继承.
原型对象属性的继承
- 拷贝继承
// 属性继承加上以下部分
for (var attr in A.prototype){
B.prototype[attr] = A.prototype[attr];
}
B.prototype.speak = function(){};
- 输出结果
{name: "hv"} __proto__:say:ƒ ()
{name: "hvge", age: 18} __proto__:say:ƒ ()speak:ƒ ()
- 拷贝继承的知识点
- attr 只包括原型对象的属性, 不包括 constructor.
- 给 B 的原型对象添加方法, 不影响 A 的原型对象
- 原型继承
// 原型继承
B.prototype.__proto__ = A.prototype;
B.prototype.speak = function(){
console.log(this.name, this.age);
};
// 输出两对象情况
var oa = new A("hvge");
var ob = new B("hvgege", 18);
oa.say();
ob.speak();
ob.say();
- 输出结果
hvge
hvgege 18
hvgege
- 输出总结
- oa 没有 speak 方法, 表明 B 的原型对象的方法添加并没有影响到 A.
- 只要是处在原型链上的属性方法,我们都可以直接调用.
面向组件编程
组件的定义
- 对面向对象的深入应用(UI组件,功能组件),提升程序的可复用性
组件代码设计模式
- 匿名函数自执行,封闭作用域空间
- 通过返回内部方法引用的形式,向外公开接口
- 组件内部采用传统混合设计模式的三段式
- 组件入口参数建议使用JSON对象
命名空间
// 命名空间 - 顶级命名空间
// 防止命名空间已经存在
window.KG = window.KG || {};
// 分配个人的命名空间
KG.HGG = {};
// HGG 在自己的命名空间里写组件
KG.HGG.Tab = (function(){
return;
})();
解决问题
- 解决命名冲突的问题