javascriptde面向对象

来源:互联网 发布:西门子plc编程软件下载 编辑:程序博客网 时间:2024/05/29 09:51


javascript中创建对象的方式:
1,通过var Person=new Object()来创建一个对象,然后给这个对象新建属性和方法。也是创建对象的最基本的方法.
例如:
var Person = new Object(); //创建一个Object对象
Person.name = 'xiaoxiao'; //创建一个name属性并赋值
Person.age = 16; //创建一个age属性并赋值
Person.say = function () { //创建一个say()方法并返回值
return this.name + this.age;
};
alert(Person.say()); //输出属性和方法的值
2,joson是javascript的一个对象,所以也可以使用json也可以创建一个对象。
var Person={
"name":"xiaoxiao",//属性和属性值
"age":18,
"say":function (){
alert(this.name + this.age)
}
}
Person.say();
以上方法可以快速创建一个对象,但是也存在缺点,就是当我们想再创建多个对象时,我们就还要写上述代码,从而产生大量的重复代码,增加代码量。这个时候我们可以使用工厂模式来实现对象的批量创建。
3,使用工厂模式创建对象。把我们需要的属性以传递参数的方式传递进去。从而将传递进来的属性赋值给对象。

function Person(name,age){
var per=new Object();
per.name=name;
per.age=age;
per.say=function(){
alert(this.name + this.age);
}
return per;
}
var per1=Person("xiaoxiao",18);
var per2=Person("xiaohong",18);
per1.say();
per2.say();


但是此时执行alert(typeof per1);(也可以用instanceof来判断类)时我们发现会弹出object,无法获取我们的对象类型。所以此时我们可以用到一种新的方式来实现我们想要的效果,那就是使用构造函数来创建特定的对象。
4,构造函数的方式来创建对象。
特点:
(1).构造函数的命名必须和类名完全相同。
(2).构造函数的功能主要用于在类的对象创建时定义初始化的状态。
(3).构造函数的本质是实例化对象。


在构造函数中关于this的指向问题:
关于this的使用,this其实就是代表当前作用域对象的引用。如果在全局范围this就代表window对象,如果在构造函数体内,就代表当前的构造函数所声明的对象。

构造函数和普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函数,必须用new运算符来调用,否则就是普通函数。例如:
var per1 = new Person('xiaoxiao', 18);//构造模式调用
alert(per1.say());
Person('xiaoxiao', 18);//普通模式调用
具体方法如下:
function Person(name,age) {
this.name=name;
this.age=age;
this.say=function(){
alert(this.name+this.age)
}
}
var per1=new Person("xiaoxiao",18);
var per2=new Person("xiaohong",16);
per1.say();
per2.say();
alert(Person instanceof per1);//此时可以使用instanceof来判断类行了
但是此时又会带来另外一个问题,就是say()方法此时是一个闭包,在堆中不断地创建和积累,增加内存的消耗。
5,原型prototype
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。逻辑上可以这么理解:prototype通过调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。

关于对原型的理解,可以用如下几幅图片表示:


例如:

function Person() {} //声明一个构造函数
Person.prototype.name = 'xiaoxiao'; //在原型里添加属性
Person.prototype.age = 18;
Person.prototype.say = function () { //在原型里添加方法
return this.name + this.age 
};

per1=new Person();
per1.say();

原型模式的执行流程:

1.先查找构造函数实例里的属性或方法,如果有,立刻返回;

2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;

原型的检测:

a,判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf()方法来测试。

alert(Person.prototype.isPrototypeOf(per1));//只要实例化对象,都会指向

b,如何判断属性是在构造函数的实例里,还是在原型里?可以使用hasOwnProperty()函数来验证:

alert(per1.hasOwnProperty('name'));//实例里有返回true,否则返回false

c,in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。

alert('name' in per1);//true,存在实例中或原型中

d,可以通过hasOwnProperty()方法检测属性是否存在实例中,也可以通过in来判断实例或原型中是否存在属性。那么结合这两种方法,可以判断原型中是否存在属性。

function isProperty(object, property) {//判断原型中是否存在属性

return !object.hasOwnProperty(property) && (property in object);

}

var box = new Box();

alert(isProperty(box, 'name'))//true,如果原型有

6,原型的重写

function Person(){};
// 原型重写,避免产生闭包,但是有缺点,下一个解决
Person.prototype={
"constructor":Person,//原型重写后constructor属性也被覆盖了,需要手动指向person对象
"name":"xiaoming",
"age":18,
"friends":['xiaohong','xiaohua','xiaoniu'],
"say":function(){
alert(this.name+this.age);
}
};
var per2=new Person();
per2.say();


此时可以很好地解决构造函数的闭包问题,但是当json内有复杂的数据类型时(比如数组),两个都会增加后增加的值,例如:

function Person(){};

Person.prototype.sayhello=function(){
alert("hello");
}
var per1=new Person();

// 原型重写,避免产生闭包,但是有缺点,下一个解决
Person.prototype={
"constructor":Person,////原型重写后constructor属性也被覆盖了,需要手动指向person对象
"name":"xiaoming",
"age":18,
"friends":['xiaohong','xiaohua','xiaoniu'],
"say":function(){
alert(this.name+this.age);
}
};
// Person.prototype.say();
var per2=new Person();
per2.say();//正常弹出
// per1.say();//报错,p1没有和say绑定,原型重写后,会覆盖前面的对象,但是对象不会消失,等有人需要时还可以调用
per1.sayhello();//正常弹出
// per2.sayhello();//报错


此时就需要对原型进行封装,讲属性以参数的形式写在函数中将方法写在对象内。

function Person(name,age,sex,friends){
this.name=name;
this.age=age;
this.sex=sex;
this.friends=friends;
};//在构造函数内传递参数


Person.prototype={
"say":function(){
alert(this.name+this.age+this.friends);
}
};//在对象内写方法
var p1=new Person("小明",18,"男",['小小','大大','妞妞']);
var p2=new Person("小画",18,"男",['小红','瑶瑶','牛牛']);

p1.friends.push("xiao");//给p1.friends的数组增加一个值,此时不会影响p2
p1.say();
p2.say();

7,继承:(1)基于原型链的实现,使子级的prototype指向父级。

function Parent(){
this.pv="父级";
}
function Son(){
this.sv="子级";
}
Son.prototype=new Parent();//基于原型链实现,使子级的prototype指向父级对象
var s1=new Son();
alert(s1.pv+s1.sv);
但是当子级继承父级后,如父级的方法不能满足子级的使用,就需要进行父级方法的重写(覆盖)。

s1.say=function(){

alert(“你好”)

}

但是这样一来我们就的方法并没有写在原型内,所以我们可以尝试用两外一种方式来实现继承,基于伪装的实现继承。

(1)基于伪装的继承,使用call()和apply()方法来实现。

例如:

function Parent(pv){
this.pv=pv;
}
Parent.prototype={
"say":function(){
alert("haha")
}
}
function Son(name,age,pv){
this.name=name;
this.age=age;
Parent.call(this,pv);//this指代Son;
}
Son.prototype={
"says":function(){
alert(this.name+this.age+this.pv)
}
};
var s1=new Son("xx",18,"hehehehe");
s1.says();
alert(s1.pv);

这样子级继承了父级的属性,但是并没有继承父级的方法,仍然无法达到我们全部继承的目的,所以我们可以将两种方法进行组合,各取所长,弃其所短,从而达到目的,具体如下:

function Parent(pv){
this.pv=pv;
}
Parent.prototype.psay=function(){
alert(this.pv)
}
function Son(name,age,pv){
this.name=name;
this.age=age;
Parent.call(this,pv);//this指代Son;
}
Son.prototype=new Parent();
Son.prototype.ssay=function(){
alert(this.name+this.age)
}
var s1=new Son("xx",18,"hehehehe");
s1.ssay();
alert(s1.pv);
s1.psay();

这样就很好地实现了继承。

0 0
原创粉丝点击