您的位置:首页 > Web前端 > JavaScript

JavaScript之----面向对象和原型

2016-08-01 12:56 501 查看
ECMAScript有两种开发模式:1、函数式(过程化),面向对象(oop)【好处:有了引用类型的对象可直接调用这个对象对应的方法】
任何一个事物都可以看成是一个对象
1、创建对象
var stu1 = new Object();   //小丽 等于 新 老婆();
stu1.name="小丽";//属性name就是一个变量
stu1.study =function(){
        alert("我叫"+this.name+"爱学习");
};    //实现学习这个功能,行为 定义为函数
alert.name;
alert.study();

这种方式创建了多个学生对象,重复性代码很多

2、使用工厂模式创建对象:解决实例化对象产生大量重复的问题(属性和行为时一样的)
function createObj(name,age){
    var obj = new Object();
    obj.names =name;
    obj.ages = age;
    obj.study = function(){
                     alert("我叫"+this.names+"今年"+this.ages+"爱学习");    
  
    };
return obj;//返回的是对象的引用
}
var stu3 =createObj("张三",23);//var stu3 = obj;
//解释一下子: return obj    最后把obj这个对象返回了,返回的是个引用(var
obj = new Object();),stu3接收到了obj这个引用,引用里存放的是new
Object()这个对象的内存地址,所以stu3接收到的是这个对象的地址,stu3也就指向了张三这个对象

var stu4 =createObj("李四",22);

工厂模式存在的问题:不能确定对象具体的类型

3、使用构造函数(方法)创建特定的对象:

//根据创建对象来起名字
function Student (name,age){
        this.name = name;    //后台自动创建了 new Object()
        this.age = age;           //this就指向了这个对象
        this.study=function(){
                        alert(this.name+","+this.age);
            };                                   //后台返回了该对象
    
}
var stu1 = new Student("zhang",23);
alert(stu1.name);
alert(stu1.age);
stu1.study();

var stu2 = new Student("李斯",20);

alert(stu2.name);

alert(stu2.age);

stu2.study();

//注意:构造函数和工厂模式的区别:
            1、构造函数中直接给name、age赋值,没有显示的创建对象(new object());
             2、直接将属性和方法赋值给this对象;
             3、没有使用return返回;

构造函数的特点:
(1)、定义构造函数是 构造函数的函数名首字母大写,为了和普通函数区分
(2)、使用构造函数时必须使用new(这样才能生成一个新的对象)例如:var
stu1 = new Student("zhang",23);
    把构造函数当成普通函数调用:Student(“张三”,40);没有任何意义(X)因为这个函数没有返回值,得不到对象,只有new之后,后台才能返回对象。
(3)、alert(stu1 instanceof Student);  //判断stu1具体什么类型的实力,判断stu1是不是Student这种类型的,显示true 或 flase
(4)、构造函数中的函数study 是一个引用类型变量 存放的是函数的地址(函数的引用)每new一个对象中的函数study的地址是不同的

4、使用原型
原型的好处:实现了数据的共享。
引用类型中都含有prototype(原型)属性,该属性指向对象
var obj = {
        country:"中国";
};//定义一个对象,给对象定义一个country属性值为中国

function Student (name,age){

        this.name = name;   

        this.age = age;   

        this.study=function(){

                        alert(this.name+","+this.age);

            };                               

}

Student.prototype =obj;//把Student的原型设置为obj对象(把Student引用类型的这种函数的prototype属性指向obj这个对象)

var stu1 = new Student("zhang",23);

var stu2 = new Student("li",20);

alert(stu1.country);//显示中国
alert(stu2.country);//显示中国

注意:是给创建对象的这个构造函数定义原型,从而使用Student创建的对象中都具备了原型对象obj中的这个内容。

prototype写成 _ _proto_ _



如果是一个对象,看他的原型对象:obj.__proto__(用__proto__)

stu1._
_proto_ _  得到stu1的原型对象

stu1._ _proto_ _._
_proto_ _ 
得到的是obj的原型对象
obj._
_proto_ _     得到的是obj的原型对象

显示的也是一个object类型的一个对象
obj._
_proto_ _ ._
_proto_ _  //显示的是空   最基本的object类型中就没有原型对象了   得到的是obj的原型对象的原型对象

//判断一个对象是否指向了构造函数的原型对象
alert(Student.prototype.isPrototypeOf(stu1));//返回的是true 或是flase
解释一下:判断stu1是不是指向了构造函数Student的原型对象
 比较谁isPrototypeOf(***)
 ***就写谁

stu1.name  指的是stu1对象中的属性name值
如果原型对象中也有个name

var obj = {

        country:"中国";

        name:"tom";

};
stu1.name 还是指的是stu1对象中的属性name值

说明:对象中含有name属性则优先使用对象中的属性,如果对象中没有的属性再到原型中查找有没有需要的属性    (构造方法中自己有的属性就用自己的,没有的再用原型中的)

①hasOwnProperty()方法:判断是否自己含有的属性

alert(stu1.hasOwnProperty('name'));  //显示true   对象stu1中本身就有name属性

②'name' in stu1 这种方法是看一下stu1中(无论是自身还是原型中)是否含有name属性

Student中如果不设置prototype属性的值,他也含有默认的object对象(Student本身就含有prototype原型对象)

Student.prototype =obj;覆盖了Student的原有的原型对象

obj的原型对象是object



obj具备object里面的属性和方法

Student具备obj里面的属性和方法也具备object里面的属性和方法

默认原型和设置的原型的区别:
var stu =  new Student("zhang",22);
构造 constructor属性   stu .constructor表示stu这个对象的构造方法是什么

如果使用的是默认原型object时, stu
.constructor使用的构造函数是 function Student(name,age){}
如果使用的是obj这个原型时 ,stu
.constructor使用的构造函数是obj 的构造方法 就是 functionObject(){}这个构造方法

如果我们用的是Student.prototype = obj;这个原型时,但是我们想用的是Student这个构造方法所以在原型对象要这样写:
var obj ={
        constructor:Student,                    //要加上这句,意思是强制创建的stu对象时使用的构造方法为Student方法
        country:"中国"
    };
或者不覆盖原型,向原型对象中添加一个新属性(在Student原有的原型对象中添加一个country属性,使用的是本来的默认原型对象)
Student.prototype.country = "中国"  
这两种方式,建议使用第一种方式

function Student (){ }

Student.prototype = {

        name:"xin",

        age:22,

        family:['妈妈','爸爸'],

        fun:function(){

                    return this.name;

                }

};
这样是有问题的, 创建的任何一个对象的姓名和年龄都相同了,对于引用类型放到原型中,若一个对象进行其修改,其他对象都变化了。(对特有的属性应定义在构造函数中,而共享的定义在原型当中)  解决这个问题利用构造函数+原型
 这种模式      如下:

5、使用构造函数+原型
function Student (name,age){           //每个对象特有的数据使用构造函数
        this.name
= name;   

        this.age = age;   

        this.family =['妈妈','爸爸'];                              

 }

Student.prototype = {            //所有对象共享的内容定义在原型对象中
    fun:function(){
            return this.name + this.age+ this.family;
    }
}

var stu1 = new Student("liso",20);
stu1.family.push("姐姐");//给stu1的family中添个姐姐
alert(stu1.family);//显示的是 妈妈 爸爸 姐姐
var stu2 = new Student("zhao",21);
alert(stu2.family);//显示的是  妈妈 爸爸
这样就互不影响了

6、使用动态原型

动态原型模式:将两部分写在一起

function Student (name,age){      

        this.name = name;   

        this.age = age;   

        this.family =['妈妈','爸爸'];    

//原型直接写在构造函数当中

              alert("原型被初始化开始");

Student.prototype.fun = function(){

            return this.name + this.age+ this.family;

    }   

 alert("原型被初始化结束");

 }

var stu1 = new Student("liso",20);

alert(stu1.fun());//显示liso,20,妈妈 爸爸

var stu2 = new Student("zhang",24);

alert(stu2.fun());//显示zhang24妈妈
,爸爸

这样存在一个问题:每次创建对象时都会把原型代码初始化一次,应该第一次初始化一次,之后就不用初始化了,所以在外面加一个判断:

function Student (name,age){      

        this.name = name;   

        this.age = age;   

        this.family =['妈妈','爸爸'];    

if(typeof this.fun! = 'function'){

              alert("原型被初始化开始");

Student.prototype.fun = function(){

            return this.name + this.age+ this.family;

    }      //注:动态原型模式只能这样写,不能 Student.prototype={} 这样直接给prototype赋值对象

 alert("原型被初始化结束");

}

 }

var stu1 = new Student("liso",20);

alert(stu1.fun());

var stu2 = new Student("zhang",24);

alert(stu2.fun());

7、使用寄生构造函数:工厂模式+构造函数

function Student (name,age){   

        

    var obj = new Object();

    obj.name=name;

    obj.age = age;

    obj.fun= function(){

                   return this.name+this.age);    
  

    };

return obj;

}
var stu = new Student("zhang",23);
alert(stu.fun);

这种模式不能实现共享,不建议使用

8、使用稳妥构造函数:在一些安全的环境中,比如禁止使用this 和 new,这里的this是构造函数里不能使用this,这里的new是在外部实例化构造函数时不能使用new
 function Person(name,age){
    var obj = new Object();
    boj.fun = function(){
                    return name +age;//直接使用参数的值
        }
    rerun obj;
}
var person = Person("lisi",24);//不能使用new创建对象
alert(person.fun());//显示lisi24

了解这种模式就行

alert(Array.prototype.sort);//显示function sort(){}   说明sort是原型对象中的一个方法
String.prototype.substr // 如上sort

js内部定义的引用类型也都是含有原型的,并可以添加方法,但不建议这样使用,因为容易发生命名冲突

String.prototype.myStr
= function(){
 
         ---- 功能----
}
       //给string的原型对象中添加一个方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息