js面向对象

创建对象的五种方式

第一种

var person = new Object();
person.name = "Leon";
person.age = "22";

第二种 json

var person = {
    name:"Leon",
    age:22
};

第三种 工厂

function createPerson(name,age){
    var o = new Object();
    o.name = name;
    o.age = age;
    return o;
}

第四种 构造函数

function Person(name,age){
    this.name = name;
    this.age = age;
}

    第一、二种方式存在的缺点是不可重用,第三种方式无法判断数据类型,第四种方式每个对象的方法占用不同的内存,创建大量对象会占用较多的内存,解决方法是把方法变成全局的,但是它变成了window的方法。

第五种 基于原型

function Person(){}
Person.prototype.name = "Leon";
Person.prototype.age = 22;
Person.prototype.say = function(){
    alert(this.name+","+this.age);
}

    第一种状态:function Person(){},Person函数中有一个prototype属性指向Person的原型对象,在原型对象中有一个constructor的属性指向了Person函数,所以可以通过new Person()创建对象。
    第二种状态:通过Person.prototype.name为原型设置值之后,这些属性和方法都是设置在Person的原型中的。
    第三种状态:当使用Person创建对象之后,会在对象中有一个_prop_属性(这个属性是不能被访问的)指向了原型,当使用对象调用原型的时候,首先会在对象内部找到是否有这个属性,如果没有会通过_prop_去原型中找属性,所以当调用p1.say(),在自己的空间中不存在这个方法,就会去原型中找,找到之后就会完成say的调用。
    Person.prototype.isPrototypeOf(p1);
    检测p1是否有_prop_指向Person的原型。
    第四种状态:当创建了一个新的p2之后依然会有一个_prop_属性指向Person原型,此时如果通过p2.name设置了属性之后,会在对象自己的内存空间中存储name的值,当调用say方法的时候,在寻找name时,在自己的空间中找到之后,就不会去原型中查找了。(特别注意:原型中的值不会被替换,仅仅只是在查找时被覆盖)

检测某个对象是否是某个函数的原型

alert(Person.prototype.isPrototypeOf(p2));

检测某个对象的constructor

alert(p1.constructor == Person);

检测某个属性是否是自己的属性

alert(p1.hasOwnProperty("name"));

可以通过delete删除空间中的属性

检测某个对象在原型或者自己中是否包含有某个属性,通过in检测(原型和自己的空间都没有为false),可以通过如下方法检测某个属性是否在原型中存在。

function hasPrototypeProperty(obj,prop){
    return ((!obj.hasOwnProperty(prop))&&(prop in obj));
}

重写原型
Person.prototype = {
    name:"Leon",
    age:23,
    say:function(){
        alert(this.name+","+this.age);
    }
}
var p1 = new Person();
Person.prototype.sayHi = function(){
    alert(this.name+":Hi");
}
重写放在new Person()之后。

基于原型的创建虽然可以有效的完成封装,但是依然存在一些问题

1.无法通过构造函数来设置属性值。

2.当属性中有引用类型变量时,可能存在变量值重复。

function Person(){}
Person.prototype = {
    constructor:Person,
    name:"Leon",
    age:30,
    friends:["Ada","Chris"],
    say:function(){
        alert(this.name+"["+this.friends+"]");
    }
}
var p1 = new Person();
p1.say();
p1.friends.push("Mike");
var p2 = new Person();
p2.say();//p2也有Mike
为了解决原型所带来的问题,此处需要通过组合构造函数和原型来实现对象的创建,将属性在构造函数中定义,将方法在原型中定义,有效结合两者的优点是比较常用的方式。为了让定义的方式更加符合Java的需求,把定义方法的原型代码放置到Person这个构造函数中(判断,防止重复定义if(!Person.prototype.say))。

继承

基于原型链实现继承
function Parent(){
    this.pv = "parent";
}
Parent.prototype.pp = "ok";
Parent.prototype.showParentValue = function(){
    alert(this.pv);
}
function Child(){
    this.cv = "child";
}
Child.prototype = new Parent();
child.prototype.showChildValue = function(){
    alert(this.cv);
}
var c = new Child();
c.showParentValue();
c.showChildValue();
在使用原型链进行继承一定要注意以下问题:
1.不能在设定了原型链之后,再重新为原型链赋值。
Child.prototype = {
    showChildValue:function(){
        alert(this.cv);
    }
}
原型又重写了,不存在任何的继承关系了。
2.一定要在原型链赋值之后才能添加或者覆盖方法,如showChildValue放在Child.prototype = new Parent();之前,它不再新的原型对象中。
Child.prototype.showParentValue = function(){
    alert("over parent");
}
同样在原型链设定之后执行这里覆盖后的方法。
原型链继承的缺点:
1.无法从子类中调用父类的构造函数,这样就没有办法把子类中的属性赋值到父类。
2.如果父类中有引用类型,此时这个引用类型会添加到子类的原型中,当第一个对象修改了这个引用之后,其他对象的引用同时修改。

基于函数伪造的方式实现继承

function Parent(){
    this.color = ["red","blue"];
    this.name = "Leon";
}
function Child(){
    Parent.call(this);
    Parent();
}
/*
在child中的this指向child对象,当调用Parent方法的时候,而且this又是指向child,此时就等于在这里完成this.color=["red","blue"];也就等于在Child中有了this.color属性,这样也就变相地完成了继承,Parent()仅仅完成了函数的调用,无法实现继承。
*/
var c1 = new Child();
c1.color.push("green");
alert(c1.color);//red,blue,green
var c2 = new Child();
alert(c2.color);//red,blue


使用伪造的方式可以把子类的构造函数参数传递到父类中。
function Parent(name){
    this.color = ["red","blue"];
    this.name = name;
}
function child(name,age){
    this.age = age;
    Parent.call(this,name);
}
var c1 = new Child("Leon",12);
var c2 = new Child("Ada",22);
alert(c1.name+","+c1.age);//Leon,12
alert(c2.name+","+c2.age);//Ada,22
原型的方式写方法不会继承,解决方案是写在构造函数中,但是又会占用太多内存。

基于组合的方式实现继承

组合的实现方式是属性通过伪造的方式实现,方法通过原型链的方式实现。
function Parent(name){
    this.color = ["red","blue"];
    this.name = name;
}
Parent.prototype.ps = function(){
    alert(this.name+"["+this.color+"]");
}
function Child(name,age){
    Parent.call(this,name);
    this.age = age;
}
Child.prototype = new Parent();
Child.prototype.say = function(){
    alert(this.name+""+this.age+"["+this.color+"]");
}
var c1 = new Child("Leon",22);
c1.color.push("green");
c1.say();
c1.ps();
var c2 = new Child("Ada",23);
c2.say();
c2.ps();







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值