一、对象
ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值,对象或者函数。所以js中对象就是一组键值对。
 
面向对象的语言中,都是通过类的来创建任意多个具有相同属性和方法的对象实例的。但是js中没有类的概念,接下来我先通过一个例子来阐述js中没有“类”的概念蕴含的哲学。这点会让初学者很困惑,但是也正因为放下了“类”的概念,js对象才有了其他语言没有的活力。事实上js中对象的“类”是从无到有,又不断演化,最终消失于无形之中。
 
举例:小蝌蚪找妈妈的故事,小蝌蚪在其自身类型不断演化的过程中,逐渐变成了和妈妈一样的“类”。
 
代码:
 
 
<!DOCTYPE >
<html>
<meta charset="utf-8">
<head>
    <title>小蝌蚪找妈妈</title>
</head>
<body>
<script>
    var life={};//光溜溜的生命
    for(life.age=1;life.age<=3;life.age++)
    {
        switch (life.age)
        {
            case 1:
                life.body="卵细胞";//增加body属性
                life.say=function(){
                 console.log(this.age+this.body);
                };//新建say方法
                break;
            case 2:
                life.tail="尾巴";//增加tail属性
                life.gill="腮";//增加gail属性
                life.body="蝌蚪";
                life.say=function(){
                    console.log(this.age+this.body+'-'+this.tail+","+this.gill);
                };
                break;
            case 3:
                delete life.tail;//删除tail属性
                delete life.gill;//删除gill属性
                life.legs="四条腿";//增加legs属性
                life.lung="肺";//增加lung属性
                life.body="青蛙";
                life.say=function(){
                    console.log(this.age+this.body+"-"+this.legs+","+this.lung);
                };
                break;
        }
        life.say();//调用say方法,每次逻辑都会发生动态改变
    }
</script>
</body>
</html>
 
 
 
(1)js程序一开始产生了一个生命对象life,life诞生时只是个光溜溜的生命对象,没有任何属性和方法。
 
(2)第一次生命进化,life对象有了身体属性body,并有了一个say方法,看起来是一个“卵细胞”。
 
(3)第二次生命进化,它又长出了“尾巴”和“腮”,有了tail和gill属性,显示它是一个“蝌蚪”。
 
(4)第三次生命进化,它的tail和gill消失了,但又长出了“四条腿”和“肺”,有了legs和lung属性,从而最终变成了“青蛙”。
 
所以说,对象的“类”是从无到有,又不断演化,最终消失于无形中。
 
“类”确实可以帮助我们对世界分类,但是我们思想不能被“类”束缚,如果生命开始就被规定了固定的“类”,就无法演化,蝌蚪就变不成青蛙。所以js中没有“类”,类已化为无形与对象融为一体。这样也更加贴近现实世界,不是吗?
 
js没有类,js对象就是一组键值对,接下来看看js中9种创建对象的方式。
 
js创建对象的方法的产生是一个迭代的过程,因为已有方法的缺陷催生出新的方法。首先是早期js程序员经常使用也是最简单的方法——通过Objec构造函数创建对象。
 
二、通过Object构造函数创建对象
代码:
 
 
<script>
  var person=new Object();
    person.nam="lxy";
    person.age="22";
    person.job="Software Engineer";
    person.sayName= function () {
        alert(this.nam);
    }
    person.sayName();
</script>
 
优点:简单
 
三、通过字面量创建对象
代码:
 
<script>
  var person={
    name:"lxy",
    age:22,
    job:"Software Engineer",
 
    sayName:function(){
        alert(this.name);
    }
  };
    person.sayName();
</script>
 
要注意一点就是每声明一个键值对后面标点是“,”。
 
对象字面量相对于Object构造函数代码量少了一点点。但是这2种方法通过一个接口创建很多对象,会产生大量重复代码。Don't Repeat Yourself!我们需要对重复的代码进行抽象。工厂模式就是在这种情况下出现的。
 
四、工厂模式
 通过类来创建多个实例必然可以减少代码重复,但是ECMAScript中无法创建类,所以就用函数来封装以特定接口创建对象的细节。
 
代码:
 
 
<script>
    function createPerson(name ,age,job){
        var o=new Object();
        o.name=name;
        o.age=age;
        o.job=job;
        o.sayName=function(){
            alert(this.name);
        }
        return o;
    }
    var lxy=createPerson("lxy",22,"Software Engineer");
    var strangerA=createPerson("strangerA",24,"Doctor");
    lxy.sayName();
    strangerA.sayName();
</script>
 
工厂模式减少了重复代码,但是不能够识别对象,所有实例都是object类型的。
 
这时构造函数模式就出现了。
 
五、构造函数模式
 像Object和Array这样的原生构造函数,在运行时会自动出现在执行环境中。我们可以创建自定义构造函数,从而创建特定类型的对象。
 
代码:
 
 
<script>
    function Person(name ,age,job){
        this.name=name;
        this.age=age;
        this.job=job;
        this.sayName=function(){
            alert(this.name);
        }
    }
    var lxy=new Person("lxy",22,"Software Engineer");
    var strangerA=new Person("strangerA",24,"Doctor");
    lxy.sayName();
    strangerA.sayName();
</script>
 
构造函数中首字母大写,而非构造函数首字母小写作为区别。
 
通过new操作符来创建Person实例,这样创建的实例都有一个constractor(构造函数)属性,该属性指向Person。
 
    alert(lxy.constructor==Person);//true
    alert(strangerA.constructor==Person);//true
lxy和strangeA是Person的实例,同时也是Object的实例。因为所有的对象都继承自Object。
 
创建自定义构造函数意味着将来可以将它的实例标识为一种特定的类型;而这正是构造函数胜过工厂模式的地方。
 
构造函数也是函数,所以语法上可以像普通函数一样去用,但是可以用并不代表应该用,还是以构造函数的方式用更合理。
 
构造函数的问题是,同一构造函数的不同实例的相同方法是不一样的。
 
alert(lxy.sayName==strangerA.sayName());//false
这个问题很好理解,因为js中函数就是对象,每定义一个函数,也就是实例化了一个对象。
 
从代码的角度可能理解的更深刻:
 
this.sayName=function(){alert(this.name)};与
 
this.sayName=new Function(alert(this.name));是等价的。
 
所以使用构造函数创建对象,每个方法在每个实例上都要重新实现一遍,一是耗资源,二是创建两个或者多个完成同样认为的Function没有必要,三是有this在,没必要在代码执行前就把函数绑定到特定对象上。
 
所以,有一种方法是说把函数定义转移到构造函数外部,代码如下:
 
 
<script>
    function Person(name ,age,job){
        this.name=name;
        this.age=age;
        this.job=job;
        this.sayName=sayName;
    }