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

21 篇文章 0 订阅
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的原型对象中添加一个方法



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值