js面相对象

面向对象

<script type="text/javascript">
    //  面向对象:就是一种编程思想,只关注其功能,不关注其内部细节
    //  面向对象特点:
    //1.封装 :不考虑内部实现,只考虑功能 
    //2.继承 :从已有的对象上,继承出新的对象
    //3.多态 :不同的操作,产生不同的结果

    //JS的面向对象
    //JS是基于对象的,它不是面向对象

    //对象组成
    //1.属性 :变量
    //2.方法 :函数
    var ary = [1, 2, 3];
    //alert(typeof(ary)); //object
    //数组的属性 ary.length
    //数组的对象的方法 ary.push()
    var ary2 = [4, 5, 6];
    //属于一个对象的变量叫属性
    //属于一个对象的函数叫方法

    //创建空对象
    var obj = new Object();
    obj.name = "邹振洲";
    obj.sex = "boy";
    obj.showName = function(){
        alert(this.name);
    }
    obj.showName();

    var obj2 = new Object();
    obj2.name = "小风儿";
    obj2.sex = "boy";
    obj2.showName = function(){
        alert(this.name);
    }
    obj2.showName();
</script>

工厂方式

<script type="text/javascript">
    //工厂方式
    function CreatePerson(name, sex){
        //1.原料
        var obj = new Object();
        //2.加工
        obj.name = name;
        obj.sex = sex;
        obj.showName = function(){
            alert(this.name);
        };
        obj.showSex = function(){
            alert(this.sex);
        }
        //3.出厂
        return obj;
    }
    var p1 = CreatePerson("阿波罗", "boy");
    var p2 = CreatePerson("asdf", "boy");

    p1.showName();
    p2.showName();
    alert(p1.showName == p2.showName);//false
    //工厂方式的缺点:
    //1.每一个对象都有一套自己的方法,浪费资源
    //2.没有new
</script>

new

<script type="text/javascript">
    //构造函数:用来创建对象的函数
    function CreatePerson(name, sex){
        //var this = new Object();  //下面使用new 本行系统默认写出
        this.name = name;
        this.sex = sex;
        this.showName = function(){
            alert(this.name);
        };
        this.showSex = function(){
            alert(this.sex);
        }
        //return this;  //下面使用new 本行系统默认写出
    }
    //new过程叫做实例化
    //p1实例(实例化的对象)
    var p1 = new CreatePerson("小风儿", "boy");
    p1.showName();

</script>

 给数组添加方法

<script type="text/javascript">
    //var ary1 = new Array(1, 2, 3);
    //数组是系统对象
    //扩展系统对象的属性和方法
    var ary1 = [1, 2, 3];
    var ary2 = [4, 5, 6];
    ary1.sum = function(){
        var s = 0;
        for(var i = 0; i < this.length; i++){
            s += this[i];
        }
        return s;
    }
    alert(ary1.sum());
    ary1.push(10);
    alert(ary1.sum());
</script>

prototype

<script type="text/javascript">
    //给Array原型加方法
    Array.prototype.sum = function(){
        var s = 0;
        //this 代表实例化的对象  ary1
        for(var i = 0; i < this.length; i++){
            s += this[i];
        }
        console.log(this);
        return s;
    }
    var ary1 = [1, 2, 3];
    var ary2 = [4, 5, 6];

    alert(ary1.sum());
    alert(ary2.sum());
    alert(ary1.sum == ary2.sum);
</script>

混合法

<script type="text/javascript">
    //混合法创建对象
    function CreatePerson(name, sex) {
        //构造函数里添加属性
        this.name = name;
        this.sex = sex;
    }
    //原型上添加方法
    CreatePerson.prototype.showName = function() {
        alert(this.name);
    };
    CreatePerson.prototype.showSex = function() {
        alert(this.sex);
    }
    var p1 = new CreatePerson("小风儿", "boy");
    var p2 = new CreatePerson("小风", "boy");
    p1.showName();
    p2.showName();
    alert(p1.showName == p2.showName)
</script>

原型的优先级

<script type="text/javascript">
    function Person(name, sex){
        this.name = name;
        this.sex = sex;
        this.age = 18;
    }
    Person.prototype.showName = function(){
        alert(this.name);
    }
    var p1 = new Person("小风儿", "boy");
    p1.age = 20;
    alert(p1.age);
</script>

Json

<script type="text/javascript">
    //Json
    //好处:1.结构件单,比较清晰
    //坏处:2.无法批量创建对象
    var person = {};
    person.name = "";
    person.sex = "";
    person.showName = function(){
        alert(this.name);
    }
    var person1 = person;
    person1.name = "aaa";

    var person2 = person;
    person2.name = "zzz";

    person1.showName();//zzz
    person2.showName();//zzz

    //变量之间传 数值 
    //对象之间传 地址; 数组是对象
</script>

Json 命名空间

<script type="text/javascript">
    var Baidu = {};
    Baidu.news = {
        name : "zzz",
        showName : function(){
            return this.name;
        }
    };
    Baidu.news.age = {

    }
    Baidu.news.showName = function(){

    }
    Baidu.vedio = {
        name : "jjj",
        showName : function(){
            return this.name;
        }
    };
</script>

面向对象的拖拽

<style type="text/css">
    #box_1 {
        width: 100px;
        height: 100px;
        background: red;
        position: absolute;
        left: 0;
        top: 0;
    }
    #box_2 {
        width: 100px;
        height: 100px;
        background: green;
        position: absolute;
        left: 200px;
        top: 0;
    }
</style>
</head>
<body>
<div id="box_1"></div>
<div id="box_2"></div>
<script type="text/javascript">
    //构造函数首字母大写
    function Drag(id){
        var _this = this; //Drag的实例化对象
        //添加属性
        //鼠标位置
        this.mX = 0;
        this.mY = 0;
        //元素位置
        this.bX = 0;
        this.bY = 0;
        //获取元素
        this.oBox = document.getElementById(id);
        //绑定鼠标事件
        this.oBox.onmousedown = function(e){
            var e = e || window.event;
            _this.fnDown(e);
        }
    }
    Drag.prototype.fnDown = function(e){
        var _this = this;  //Drag的实例化对象
        //获取鼠标初始位置
        this.mX = e.clientX;
        this.mY = e.clientY;
        //获取元素的初始位置
        this.bX = this.oBox.offsetLeft;
        this.bY = this.oBox.offsetTop;

        document.onmousemove = function(e){
            var e = e || window.event;
            _this.fnMove(e);
        }
        this.oBox.onmouseup = function(){
            _this.fnUp();
        }
    }
    Drag.prototype.fnMove = function(e){
        //获取当前的鼠标位置
        var nowmX = e.clientX;
        var nowmY = e.clientY;
        //计算差值
        var lessX = nowmX - this.mX;
        var lessY = nowmY - this.mY;

        //更新元素的偏移量
        this.oBox.style.left = this.bX + lessX + "px";
        this.oBox.style.top = this.bY + lessY + "px";

    }
    Drag.prototype.fnUp = function(){
        document.onmousemove = null;
    }
    new Drag('box_1');
    new Drag('box_2');
</script>
</body>

第二部分


Javascript面向对象编程(一)封装的方法 

Prototype模式 

Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。 
这个对象的所有属性和方法,都会被构造函数的实例继承。 
这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。

 function Cat(name, color) {    
        this.name = name;    
        this.color = color;  
    }  
    Cat.prototype.type = "猫科动物";  
    Cat.prototype.eat = function() {
        alert("吃老鼠")
    };
 
    var cat1 = new Cat("大毛", "黄色");  
    var cat2 = new Cat("二毛", "黑色");  
    console.log(cat1.type); // 猫科动物
    cat1.eat();             // 吃老鼠

    这时cat1和cat2会自动含有一个 constructor 属性, 
    指向它们的构造函数。
    console.log(cat1.constructor == Cat); //true
    console.log(cat2.constructor == Cat); //true

    instanceof运算符, 验证原型对象与实例对象之间的关系。  
    alert(cat1 instanceof Cat); //true
    alert(cat2 instanceof Cat); //true

    这时所有实例的type属性和eat() 方法, 
    其实都是同一个内存地址, 指向prototype对象, 
    因此就提高了运行效率。  
    alert(cat1.eat == cat2.eat); //true

Prototype模式的验证方法

 isPrototypeOf() 
    判断,某个proptotype对象和某个实例之间的关系。
    alert(Cat.prototype.isPrototypeOf(cat1)); //true

 hasOwnProperty()   有自己的属性
    每个实例对象都有一个hasOwnProperty()方法,
    用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。
    alert(cat1.hasOwnProperty("name")); // true   

 in运算符 
    1.判断某个实例是否含有某个属性,不管是不是本地属性。
    alert("type" in cat1); // true
    2.in运算符还可以用来遍历某个对象的所有属性。
    for(var prop in cat1){
        alert("cat1["+prop+"]="+cat1[prop]); 
    }

Javascript面向对象编程(二)构造函数的继承

function Animal() {    
    this.species = "动物";  
}

function Cat(name, color) {  
    //在extend方法中uber要在Cat中进行体现
    Cat.uber.constructor.call(this);     
    this.name = name;    
    this.color = color;  
}

构造函数绑定

function Cat(name, color) {    
    Animal.apply(this, arguments);  //apply 数组 
  //Animal.call(this, species);      //call 一个个的
    this.name = name;    
    this.color = color;  
}  
var cat1 = new Cat("大毛", "黄色");  
alert(cat1.species); // 动物

prototype模式

Cat.prototype = new Animal();  
Cat.prototype.constructor = Cat;  
console.log(Cat.prototype.constructor == Animal);
var cat1 = new Cat("大毛", "黄色");  
console.log(cat1.species); // 动物

代码解析:
第一行:
将Cat的prototype对象指向一个Animal的实例;
相当于完全删除了prototype 对象原先的值,然后赋予一个新值;
任何一个prototype对象都有一个constructor属性,指向它的构造函数;
Cat.prototype.constructor指向Animal
第二行:所以加第二行
其实  每一个实例也有一个constructor属性,
     默认调用prototype对象的constructor属性。


----------
小例子:
//父构造函数(父类)
function P1(name, sex){
    this.name = name;
    this.sex = sex;
}
P1.prototype.showName = function(){
    alert("123123");
}
function P2(age){
    this.age = age;
}
P2.prototype = new P1("中国人", "boy");
P2.prototype.constructor = P2;
var pp = new P2("18");
console.log(pp);
console.log(pp.name)

利用空对象作为中介 

解决直接机继承浪费资源的问题

var F = function() {};  
F.prototype = Animal.prototype;  
Cat.prototype = new F();  
Cat.prototype.constructor = Cat;
代码解析
F是空对象, 所以几乎不占内存。 
这时,修改Cat的prototype对象,
就不会影响到Animal的prototype对象。 

封装上面
function extend(Child, Parent) {                    
    var F = function() {};    
    F.prototype = Parent.prototype;    
    Child.prototype = new F();    
    Child.prototype.constructor = Child;    
    Child.uber = Parent.prototype;  
}

extend(Cat, Animal);  
var cat1 = new Cat("大毛", "黄色");  
alert(cat1.species); // 动物

封装方法最后一行解析:
子对象上打开一条通道, 可以直接调用父对象的方法。(备用)

拷贝继承

function Animal() {}  
Animal.prototype.species = "动物";

function extend2(Child, Parent) {    
    var p = Parent.prototype;    
    var c = Child.prototype;    
    for(var i in p) {      
        c[i] = p[i];      
    }    
    c.uber = p;  
}
extend2(Cat, Animal);  
var cat1 = new Cat("大毛", "黄色");  
alert(cat1.species); // 动物

 


Javascript面向对象编程(三)非构造函数的继承 
一、什么是”非构造函数”的继承? 

这两个对象都是普通对象,不是构造函数,无法使用构造函数方法实现”继承”。

var Chinese = { //对象一:   nation:'中国'   };  
var Doctor ={ //对象二:    career:'医生'   }

二、object()方法

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
  }
把子对象的prototype属性,指向父对象

使用:
var Doctor = object(Chinese);
Doctor.career = '医生';
alert(Doctor.nation); //中国
代码解析:
先在父对象的基础上,生成子对象:
然后,再加上子对象本身的属性:
这时,子对象已经继承了父对象的属性了。

三、浅拷贝

function extendCopy(p) {
      var c = {};
    for (var i in p) { 
      c[i] = p[i];
    }
    c.uber = p;
    return c;
  }

使用:
var Doctor = extendCopy(Chinese);
Doctor.career = '医生';
alert(Doctor.nation); // 中国
但是,这样的拷贝有一个问题。
如果父对象的属性等于数组或另一个对象,
那么实际上,子对象获得的只是一个内存地址,
而不是真正拷贝,因此存在父对象被篡改的可能。

例子:
  Chinese.birthPlaces = ['北京','上海','香港'];
  var Doctor = extendCopy(Chinese);
  Doctor.birthPlaces.push('厦门');

  alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
  alert(Chinese.birthPlaces); //北京, 上海, 香港, 厦门
所以,extendCopy()只是拷贝基本类型的数据,
我们把这种拷贝叫做"浅拷贝"。这是早期jQuery实现继承的方式

四、深拷贝 

所谓”深拷贝”,就是能够实现真正意义上的数组和对象的拷贝。 
它的实现并不难,只要递归调用”浅拷贝”就行了。

function deepCopy(p, c) {
    var c = c || {};
    for (var i in p) {
      if (typeof p[i] === 'object') {
        c[i] = (p[i].constructor === Array) ? [] : {};
        deepCopy(p[i], c[i]);
      } else {
         c[i] = p[i];
      }
    }
    return c;
  }

使用:
  var Doctor = deepCopy(Chinese);
  Chinese.birthPlaces = ['北京','上海','香港'];
  Doctor.birthPlaces.push('厦门');

  alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
  alert(Chinese.birthPlaces); //北京, 上海, 香港

apply()与call()的区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值