编程思想
一般面向对象包含:继承,封装,多态,抽象
1. 对象形式的继承
var Person = {
name: 'poetry',
age: 18,
address: {
home: 'home',
office: 'office',
}
sclools: ['x','z'],
};
var programer = {
language: 'js',
};
function extend(p, c){
var c = c || {};
for( var prop in p){
c[prop] = p[prop];
}
}
extend(Person, programer);
programer.name; // poetry
programer.address.home; // home
programer.address.home = 'house'; //house
Person.address.home; // house
从上面的结果看出,浅拷贝的缺陷在于修改了子对象中引用类型的值,会影响到父对象中的值,因为在浅拷贝中对引用类型的拷贝只是拷贝了地址,指向了内存中同一个副本
function extendDeeply(p, c){
var c = c || {};
for (var prop in p){
if(typeof p[prop] === "object"){
c[prop] = (p[prop].constructor === Array)?[]:{};
extendDeeply(p[prop], c[prop]);
}else{
c[prop] = p[prop];
}
}
}
利用递归进行深拷贝,这样子对象的修改就不会影响到父对象
extendDeeply(Person, programer);
programer.address.home = 'poetry';
Person.address.home; // home
利用call和apply继承
function Parent(){
this.name = "abc";
this.address = {home: "home"};
}
function Child(){
Parent.call(this);
this.language = "js";
}
ES5中的Object.create()
var p = { name : 'poetry'};
var obj = Object.create(p);
obj.name; // poetry
Object.create()
作为new操作符的替代方案是ES5之后才出来的。我们也可以自己模拟该方法:
//模拟Object.create()方法
function myCreate(o){
function F(){};
F.prototype = o;
o = new F();
return o;
}
var p = { name : 'poetry'};
var obj = myCreate(p);
obj.name; // poetry
目前,各大浏览器的最新版本(包括IE9)都部署了这个方法。如果遇到老式浏览器,可以用下面的代码自行部署
if (!Object.create) {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
2. 类的继承
Object.create()
function Person(name, age){}
Person.prototype.headCount = 1;
Person.prototype.eat = function(){
console.log('eating...');
}
function Programmer(name, age, title){}
Programmer.prototype = Object.create(Person.prototype); //建立继承关系
Programmer.prototype.constructor = Programmer; // 修改constructor的指向
调用父类方法
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.headCount = 1;
Person.prototype.eat = function(){
console.log('eating...');
}
function Programmer(name, age, title){
Person.apply(this, arguments); // 调用父类的构造器
}
Programmer.prototype = Object.create(Person.prototype);
Programmer.prototype.constructor = Programmer;
Programmer.prototype.language = "js";
Programmer.prototype.work = function(){
console.log('i am working code in '+ this.language);
Person.prototype.eat.apply(this, arguments); // 调用父类上的方法
}
3. 封装
var app = {}; // 命名空间app
//模块1
app.module1 = {
name: 'poetry',
f: function(){
console.log('hi robot');
}
};
app.module1.name; // "poetry"
app.module1.f(); // hi robot
对象的属性外界是可读可写 如何来达到封装的额目的?答:可通过
闭包+局部变量
来完成
function Girl(name,age){
var love = '小明';//love 是局部变量 准确说不属于对象 属于这个函数的额激活对象 函数调用时必将产生一个激活对象 love在激活对象身上 激活对象有作用域的关系 有办法访问 加一个函数提供外界访问
this.name = name;
this.age = age;
this.say = function () {
return love;
};
this.movelove = function (){
love = '小轩'; //35
}
}
var g = new Girl('yinghong',22);
console.log(g);
console.log(g.say());//小明
console.log(g.movelove());//undefined 因为35行没有返回
console.log(g.say());//小轩
function fn(){
function t(){
//var age = 22;//声明age变量 在t的激活对象上
age = 22;//赋值操作 t的激活对象上找age属性 ,找不到 找fn的激活对象....再找到 最终找到window.age = 22;
//不加var就是操作window全局属性
}
t();
}
console.log(fn());//undefined
4. 静态成员
面向对象中的静态方法-静态属性:没有new对象 也能引用静态方法属性
function Person(name){
var age = 100;
this.name = name;
}
//静态成员
Person.walk = function(){
console.log('static');
};
Person.walk(); // static
5. 私有与公有
function Person(id){
// 私有属性与方法
var name = 'poetry';
var work = function(){
console.log(this.id);
};
//公有属性与方法
this.id = id;
this.say = function(){
console.log('say hello');
work.call(this);
};
};
var p1 = new Person(123);
p1.name; // undefined
p1.id; // 123
p1.say(); // say hello 123
6. 模块化
var moduleA;
moduleA = function() {
var prop = 1;
function func() {}
return {
func: func,
prop: prop
};
}(); // 立即执行匿名函数
7. 多态
多态:同一个父类继承出来的子类各有各的形态
function Cat(){
this.eat = '肉';
}
function Tiger(){
this.color = '黑黄相间';
}
function Cheetah(){
this.color = '报文';
}
function Lion(){
this.color = '土黄色';
}
Tiger.prototype = Cheetah.prototype = Lion.prototype = new Cat();//共享一个祖先 Cat
var T = new Tiger();
var C = new Cheetah();
var L = new Lion();
console.log(T.color);
console.log(C.color);
console.log(L.color);
console.log(T.eat);
console.log(C.eat);
console.log(L.eat);
8. 抽象类
在构造器中
throw new Error('')
; 抛异常。这样防止这个类被直接调用
function DetectorBase() {
throw new Error('Abstract class can not be invoked directly!');
}
DetectorBase.prototype.detect = function() {
console.log('Detection starting...');
};
DetectorBase.prototype.stop = function() {
console.log('Detection stopped.');
};
DetectorBase.prototype.init = function() {
throw new Error('Error');
};
// var d = new DetectorBase();
// Uncaught Error: Abstract class can not be invoked directly!
function LinkDetector() {}
LinkDetector.prototype = Object.create(DetectorBase.prototype);
LinkDetector.prototype.constructor = LinkDetector;
var l = new LinkDetector();
console.log(l); //LinkDetector {}__proto__: LinkDetector
l.detect(); //Detection starting...
l.init(); //Uncaught Error: Error