JS面向对象经典案例
//一、通用创建函数
function New(aClass,aParams){
//定义临时的中转函数壳
function new_() {
// 调用原型中定义的构造函数,中转构造逻辑及构造参数,用Create方法,来替代原有的构造函数
aClass.Create.apply(this,aParams);
};
new_.prototype=aClass;
return new new_();
};
// Person
var Person = {
// 模拟Object.create()方法,初始化
Create:function(name,age) {
https://www.wendangku.net/doc/8f10663218.html,=name;
this.age=age;
return this;
},
sayHello: function() {
alert("my name is " + https://www.wendangku.net/doc/8f10663218.html, + ",my age is " + this.age);
}
}
window.onload = function() {
var obj = New(Person, ["luolibing", 26]);
obj.sayHello();
// IE9及以上GOOGLE FIREFOX支持,IE8及IE8以下不支持,跟上面的方法类似
// getPrototypeOf获取Object的原型,IE版本要求高IE9以上var o = Object.create(Person).Create("liuxiaoling", 27);
o.sayHello();
}
function person(name){
https://www.wendangku.net/doc/8f10663218.html,=name;
};
// 二、原型链级,子类需要一个原型指向父类,传递起来比较麻烦person.prototype.sayHello=function(){
alert("Hello,I'm "+https://www.wendangku.net/doc/8f10663218.html,);
};
// employee
function employee(name,money){
person.call(name);
this.money=money;
};
// 子类原型指向父类Person
employee.prototype=new person();
// 子类原型添加showMoney方法
employee.prototype.showMoney=function(){
alert(https://www.wendangku.net/doc/8f10663218.html,+this.money);
};
var em=new employee("bob",11);
em.showMoney();
em.sayHello();
var pp=new person("jack");
pp.sayHello();
//alert(pp.sayHello==em.sayHello);
String.prototype.toString()=function(){
};
var aaa="bb";
aaa.toString();
String.prototype.isDate=function(){
var reg=/^[0-9]*$/;return reg.test(this);
};
alert("11231".isDate());
alert("2005-11-11".isDate());
function Person(name){
https://www.wendangku.net/doc/8f10663218.html,;
};
https://www.wendangku.net/doc/8f10663218.html,pany="MS";
//原型的方法
Person.prototype.SayHello = function() {
alert("Hello, I'm " + https://www.wendangku.net/doc/8f10663218.html, + " of " + https://www.wendangku.net/doc/8f10663218.html,pany);
};
var BillGates = new Person("Bill Gates");
BillGates.SayHello(); //由于继承了原型的东西,规规矩矩输出:Hello, I'm Bill Gates
var SteveJobs = new Person("Steve Jobs");
https://www.wendangku.net/doc/8f10663218.html,pany = "Apple"; //设置自己的company属性,掩盖了原型的company属性
//实现了自己的SayHello方法,掩盖了原型的SayHello方法
SteveJobs.SayHello = function() {
alert("Hi, " + https://www.wendangku.net/doc/8f10663218.html, + " like " + https://www.wendangku.net/doc/8f10663218.html,pany + ", ha ha ha ");
};
SteveJobs.SayHello(); //都是自己覆盖的属性和方法,输出:Hi, Steve Jobs like Apple, ha ha ha BillGates.
三、闭包:什么是闭包
要了解什么是闭包,涉及到JS的其他几个特性:作用域链,垃圾回收机制,嵌套函数
作用域链:就是函数在定义的时候创建的,用于寻找使用到的变量的值的一个索引,他内部的规则是,把函数自身的变量放在最前面,把自身的父级函数中的变量放到其次,
再高一级的放在更后面,以此类推,最后到全局对象为止。当函数中遇到一个变量时,JS解析器会去作用域链中查找,从函数本身变量开始查找,如果没有再上一级,。。一旦找到就不再
继续,如果到最后也没有找到需要的变量,则返回undefined
垃圾回收机制:一个函数在执行开始的时候,会给其中定义的变量划分内存空间,等到函数执行完毕,这些变量被认为是无用的,对应的内存空间也就被回收了。下次再执行的
时候,又分配一个内存空间,如此周而复始。但是如果这个函数内部又嵌套了另一个函数,而
这个被嵌套的函数又在外部被调用,并且这个嵌套函数又实用了外部函数的某些变量的话,上
面的内存回收机制就会出现问题。如果在外部函数返回后,又直接调用了内部函数,那么内部
函数就无法读取到他所需的外部函数中的变量值。所以js解释器在遇到函数定义的时候,会自
动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一起保存起来.也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用以后(例如被删除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收.
嵌套函数:函数中嵌套一个函数,有了闭包,嵌套函数才可能执行
var result=[];
function foo(){
var i= 0;
for (i= 0;i<3;i=i+1){
//
result[i]=function() {
alert(i);
}
}
};
window.onload = function() {
foo();
result[0]();//3
result[1]();//3
result[2]();//3
}
为什么是3?这是因为闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.
解决的方法之一,是让内部函数在循环创建的时候立即执行,并且捕捉当前的索引值,然后记录在自己的一个本地变量里.然后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值,改进后的代码:
var result=[];
function foo(){
//var i= 0;
for (var i= 0;i<3;i=i+1){
// 匿名函数,返回函数
result[i]=(function(j) {
return function() {
alert(j);
}
})(i)
}
};
window.onload = function() { foo();
result[0]();
result[1]();
result[2]();
}