码迷,mamicode.com
首页 > 其他好文 > 详细

面向对象与原型

时间:2015-09-27 20:01:46      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:


一,创建对象
var box = new Object();
box.name = ‘lee‘;
box.age = 23;
box.run = function () {
    return this.name + this.age + " run....";
}
alert(box.run());

上面创建了一个对象,并且创建属性和方法,在run()方法里的this,就是代表box 对象本身。这种是JavaScript 创建对象最基本的方法,但有个缺点,想创建一个类似的对象,就会产生大量的代码。

var box1 = new Object();
box1.name = ‘jack‘;
box1.age = 24;
box1.run = function () {
    return this.name + this.age + " run....";
}
alert(box1.run());

为了解决多个类似对象声明的问题,我们可以使用一种叫做工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复的问题。

1.工厂模式
function createObject(name, age)
{
    var obj = new Object();            //创建对象
    obj.name = name;                    //添加属性
    obj.age = age;
    obj.run = function () {            //添加方法
        return this.name + this.age + " runing...";
    };

    return obj;                        //返回对象
};
var box2 = createObject(‘hg‘, 100);    //创建第一个对象
var box3 = createObject(‘wj‘, 200);    //创建第二个对象
alert(box2.run());        //打印run方法
alert(box3.run());

工厂模式:就解决了实例化对象,产生大量重复的问题.但是又引出了一个新的问题,声明出来的对象都是object的类型,无法区分它们.

2.构造函数方法的方式创建对象
function Box(name, age)        //创建对象
{
    this.name = name;            //添加属性
    this.age = age;
    this.run = function ()
    {
        return  this.name + this.age + " runing...";
    };
};

var box1 = new Box(‘lee‘, 100);            //实力化    
var box2 = new Box(‘wenjing‘, 200);    

alert(box1.run());
alert(box2.run());

alert(box1 instanceof Box);        //true
构造函数方式:(改良后的工厂方法)
(1)构造函数没有使用new object,但是系统会自动调用var obj=new object().
(2)this 相当于 obj.
(3)构造函数方式没有像工厂一样return obj; 后台自动返回对象.

构造函数的方法有一些规范:
(1)函数名和实例化构造名相同且大写.(非强制,但是有助于区分与普通函数之间的区别).
(2)通过构造函数创建对象,一定要用new
(3)解决了对象识别问题box1 instanceof Box 返回ture
注意:    
A;this的使用
this如果在全局,就是代表windows对象,在构造函数内,代表构造函数所声明的对象.构造函数用普通函数调用,一般是无效的,必须使用new运算符.
B:对象冒充调用:
var o = new Object();
Box.call(o, ‘Jack‘, 200)     //对象冒充调用
alert(o.run());                //正确

C:探讨一下构造函数体内构造方法

function Box(name, age)        //创建对象
{
    this.name = name;        //添加属性
    this.age = age;
    this.run = function ()
    {
        return  this.name + this.age + " runing...";
    };
};
var box1 = new Box(‘hg‘, 123);
var box2 = new Box(‘wj‘, 321);
alert(box1.run == box2.run);        //false

两个对象使用的run函数不相同.解决引用地址不同,可以通过对象外面引用同一个函数,来解决.

function Box(name, age)        //创建对象
{
    this.name = name;            //添加属性,实例属性
    this.age = age;
    this.run = run;            //实例方法
};
function run()
{
    return  this.name + this.age + " runing...";
}

var box1 = new Box();
var box2 = new Box();
alert(box1.run());
alert(box1.run == box2.run);        //true
用全局的run来解决唯一性,但是又带来了新的问题.run暴露在外边.对象调用this代表box,被当作普通函数的时候,this代表window.


3.原型
每一个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含特定类型的所有实例共享的属性和方法.
function Box() {};                    //原型
Box.prototype.name = ‘hg‘;            //原型属性
Box.prototype.age = 23;
Box.prototype.run = function ()        //原型方法
{
    return  this.name + this.age + " runing...";
}
var box1 = new Box();
var box2 = new Box();
alert(box1.run());
alert(box1.run == box2.run);        //true

如果是实例方法,不同的实例化,他们的方法地址是不同的地址. 而原型方法,他们的地址是共享的,大家都是一样的.

构造函数方式





原型模式方式

__proto__ 是一个指针,指向prototype的原型对象.
在声明原型的时候,多了2个属性,这2个属性都是创建对象自动生成的, __proto__属性是实例指向原型对象的一个指针.他的作用就是指向构造函数的原型属性constructor.
PS:IE 浏览器在脚本访问__proto__会不能识别,火狐和谷歌浏览器及其他某些浏览器均能识别。虽然可以输出,但无法获取内部信息。
alert(box1.__proto__);         //[object Object]

alert(box1.constructor);    //可以获取构造函数本身.

判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf()方法来测试。
alert(Box.prototype.isPrototypeOf(box1));            //true

原型的执行过程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回;
2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;
这说明原型是原型,对象是对象.通过原型创建的对象依旧可以添加自己的属性和方法,但是这个属性和方法不影响原型.说明我们可以通过对象访问原型的值,但是不可以改写原型的值.
Box.prototype.name = ‘hg‘;    //原型属性
Box.prototype.age = 23;

Box.prototype.run = function ()    //原型方法
{
    return  this.name + this.age + " runing...";
}

var box1 = new Box();
var box2 = new Box();

alert(box2.name);        //hg
box2.name = ‘wj‘;        //重写name的属性
alert(box2.name);        //wj
delete box2.name;        //删除box2的对象name属性
alert(box2.name);        //hg
//可以通过prototype来重写原型中的属性.
Box.prototype.name = ‘kkk‘;    //可以重写原型的属性

可以使用hasOwnProperty()函数来验证:构造函数的实例里是否有属性.
alert(box.hasOwnProperty(‘name‘)); //实例里有返回true,否则返回false

in操作符判断属性是否在对象中,无论属性存在于实例或者原型中都返回true.
alert(‘name‘ in box1);        //true
alert(‘name‘ in box2);        //true
判断是否属性只存在于原型,而实例中没有.
function isProperty(object, property) { //判断原型中是否存在属性
return (!object.hasOwnProperty(property)) && (property in object);
}
var box = new Box();
alert(isProperty(box, ‘name‘)) //true,如果原型有


注意:
var box = new Box();
alert(box.prototype);        //
alert(box.__proto__);        //可以,但是IE本身是无法反问的.
alert(Box.prototype);        //可以
如果想访问prototype,用Box.prototype可以.
使用字面量的方式创建原型对象.
function Box() {}
Box.prototype = {
    name:‘hg‘,
    age:23,
    run:function () {
        return this.age + this.name + " runing...";
    }
};

var box = new Box();
alert(box.run());            //正常打印
注意:Box.prototype = {};创建了一个新的对象,不再指向Box了.
可以用constructor:Box进行强制转换.

function Box() {}

Box.prototype = {
    name:‘hg‘,
    age:23,
    run:function () {
        return this.age + this.name + " runing...";
    }
};
//这里就切断了之前的原型与对象的链接.不会保存以前的原型中的属性
Box.prototype = {            
age:100,
};

var box = new Box();
alert(box.run());        //run is undefined

原型的缺点:第一:省略了传参的过程,所有的实例,初始化都是一样的.无法保持独立性.第二个缺点也是它最大的优点就是,所以的都是共享的.
//原型的缺点
function Box() {}
Box.prototype = {
    constructor:Box,
    name:‘hg‘,
    age:100,
    family:[‘gege‘, ‘jiejie‘, ‘didi‘],
    run:function () {
        return this.name + this.family;
    }
};

var box1 = new Box();
alert(box1.family);
box1.family.push(‘meimei‘);        //更改了原型
alert(box1.family);

var box2 = new Box();
alert(box2.family);                //受box1的操作影响


//组合构造函数+原型模式
function Box(name, age)
{
    this.name = name;
    this.age = age;
    this.family = [‘gg‘,‘jj‘,‘mm‘];
};

Box.prototype = {
    constructor:Box,
    run:function () {
        return this.name + ‘ ‘ + this.family;
    },
};

var box = new Box();
alert(box.family);
box.family.push(‘dd‘);    //添加新的数据
alert(box.family);

var box1 = new Box();
alert(box1.family);        //没有改变

这样family并没有被共享.

//动态原型模式
//将原型封装到构造函数里面
function Box(name, age)
{
    this.name = name;
    this.age = age;
    this.family = [‘gg‘,‘jj‘,‘mm‘];
//原型初始化开始
    Box.prototype.run = function () {
        return this.name + ‘ ‘ + this.family;
    };
//原型初始化结束
};
事实上原型只初始化一次就可以了,所以想办法第一次初始化调用一次就好了.
function Box(name, age)
{
    this.name = name;
    this.age = age;
    this.family = [‘gg‘,‘jj‘,‘mm‘];
//这样就只初始化一次,判断run函数是否存在.
    if (typeof this.run != ‘function‘){
        Box.prototype.run = function () {
            return this.name + ‘ ‘ + this.family;
        };    
    }

};
Var box = new Box(‘hg’, 123);
Alert(box.run());


使用动态原型模式,要注意一点,不可以再使用字面量的方式重写原型,因为会切断实例和新原型之间的联系。重写原型prototype就将之前的原型给替换了.

//寄生构造模式 = 工厂模式 + 构造函数
function Box(name, age) {
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.run = function () {
        return this.name + this.age + ‘运行中...‘;
    };
    return obj;
}

var box = new Box(‘hg‘, 123);
alert(box.run());

//稳妥构造函数 不允许使用this和new
在一些安全的环境中,比如禁止使用this 和new,这里的this 是构造函数里不使用this,这里的new 是在外部实例化构造函数时不使用new。这种创建方式叫做稳妥构造函数。
function Box(name , age) {
    var obj = new Object();
    obj.run = function () {
    return name + age + ‘运行中...‘; //直接打印参数即可
    };
    return obj;
}
var box = Box(‘Lee‘, 100); //直接调用函数
alert(box.run());    
稳妥构造函数和寄生构造函数很类似.

 

面向对象与原型

标签:

原文地址:http://www.cnblogs.com/hgonlywj/p/4842613.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!