Javascript 面向对象编程,一:封装

创建对象三种方式

1.字面量的方式

var per1={
      name:"沐风",
      age:20,
      sex:"男",
      eat:function () {
        console.log("吃");
      },
      readBook:function () {
        console.log("");
      }
    };

2.调用系统的构造函数

var per2=new Object();
    per2.name="沐风";
    per2.age=30;
    per2.sex="男";
    per2.eat=function () {
      console.log("吃");
    };
    per2.play=function () {
      console.log("玩");
    };

3.自定义构造函数方式(推荐)

function Person(name,age,sex) {
      this.name=name;
      this.age=age;
      this.sex=sex;
      this.play=function () {
        console.log("天天打游戏");
      };
    }
    var per=new Person("沐风",18,"男");
    console.log(per instanceof Person);

工厂模式

function createObject(name,age) {
      var obj=new Object();
      obj.name=name;
      obj.age=age;
      obj.sayHi=function () {
        console.log("您好");
      };
      return obj;
    }

原型

1.构造函数方法很好用,但是存在一个浪费内存的问题

function Cat(name, color) {
    this.name = name;
    this.color = color;
    this.type = "猫科动物";
    this.eat = function () { alert("吃老鼠"); };
}

var cat1 = new Cat("大毛", "黄色");
var cat2 = new Cat("二毛", "黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠

2.Prototype模式,所有实例的type属性和eat()方法,其实都是同一个内存地址,指向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("二毛", "黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠
alert(cat1.eat == cat2.eat); //true

简单的原型写法

Student.prototype = {
      //手动修改构造器的指向
      constructor:Student,
      height: "188",
      weight: "55kg",
      study: function () {
        console.log("学习好开心啊");
      },
      eat: function () {
        console.log("我要吃好吃的");
      }
    };

    var stu=new Student("段飞",20,"男");
    stu.eat();
    stu.study();
    console.dir(Student);
    console.dir(stu);

我们可以为系统的对象的原型中添加方法,相当于在改变源码

//我希望字符串中有一个倒序字符串的方法
    String.prototype.myReverse=function () {
      for(var i=this.length-1;i>=0;i--){
        console.log(this[i]);
      }
    };
    var str="abcdefg";
    str.myReverse();

回调函数

当我们将函数A传递给函数B,并由B来执行A时,A就成了一个回调函数(callback ftmctions)。如果这时A还是一个无名函数,我们就称它为匿名回调函数。

function FunA(a,b,callback) {
    return callback(a, b);
}
function FunB(a,b) {
    return a + b;
}
alert(FunA(1,2,FunB));

还可以用匿名函数代替FunB

function FunA(a,b,callback) {
    return callback(a, b);
}
alert(FunA(1,2,function(a,b){return a + b}));

自调函数

(function (name) {
    alert("我的名字是:"+name)
})("mf")

缺点:无法重复利用

优点:不会产生任何全局变量,适合一次执行或初始化任务

如何把局部变量变成全局变量?

  把局部变量给window就可以了

(function (win) {
    var num=10;//局部变量
    //js是一门动态类型的语言,对象没有属性,点了就有了
    win.num=num;
    })(window);
    console.log(num);

通过自调用函数产生一个随机数对象,在自调用函数外面,调用该随机数对象方法产生随机数

(function (window) {
      //产生随机数的构造函数
      function Random() {
      }
      //在原型对象中添加方法
      Random.prototype.getRandom = function (min,max) {
        return Math.floor(Math.random()*(max-min)+min);
      };
      //把Random对象暴露给顶级对象window--->外部可以直接使用这个对象
      window.Random=Random;
    })(window);
    //实例化随机数对象
    var rm=new Random();
    //调用方法产生随机数
    console.log(rm.getRandom(0,5));

内部私有函数

var FunA = function (parmA) {
    var FunB = function (parmB) {
        return parmB * 2;
    }
    return "结果是:" + FunB(2);
}

优点:有助于我们确保全局名字空间的纯净性,命名冲突的机会更小

私有性:可以选择将必要的函数暴露给外界,并保留属于自己的函数

返回函数的函数

var FunA = function () {
    alert("A");
    return function () {
        alert("B");
    };
}
var A = FunA();//第一次输出A  返回的是函数引用,并不会产生函数调用
A();//第二次输出B

能重写自己的函数

function FunA() {
    alert("A");
    //全局变量A被重新定义并被赋予新的函数
    A= function () {
        alert("B");
    };
}
 FunA();//第一次输出A 
A();//第二次输出B 

闭包

1.闭包概念

作用域链

词法作用域

利用闭包突破作用域链

2.闭包的用途

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。而反过来我们有时候需要得到函数内的局部变量,出于种种原因,正常情况下,这是办不到的,只有通过变通方法才能实现。