JS 面向对象与原型(一)

面向对象的语言有一个标志,就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象,而ECMAScript中没有类的概念。

ECMA-262 把对象定义为 :“无序属性的集合,其属性可以包含基本值,对象或函数。” 严格来说,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。想象成,一组名值对,值可以是数据或函数。

创建对象:
方法一: 一次只能创建一个对象,当想创建另一个属性方法相同的对象时,会产生大量重复性的代码。

        var box = new Object();
        box.name = "Lee";
        box.age = 100;
        box.run = function () {
            return this.name + this.age + "运行中...";
        }
        alert(box.run());
        alert(this.name);

方法二:
工厂模式:解决了实例化对象产生大量重复的问题,但,存在识别问题,即,无法识别box1,box2 到底属于哪个对象的实例。


  function createObject(name, age) {  // 集中实例化的函数
        var obj = new Object();  // 创建对象
        obj.name = name;         // 添加属性
        obj.age = age;           // 添加属性
        obj.run = function () {  // 添加方法
            return this.name + this.age + "运行中...";
        }
        return obj;               // 返回对象引用
    }

    var box1 = createObject("Qiqi", 29);  // 创建第一个对象
    var box2 = createObject("tianyu", 25);// 创建第二个对象
    alert(box1.run());               // 打印第一个对象的run()
    alert(box2.run());               // 打印第二个对象的run()

方法三:
构造函数方式 : 既解决了重复实例化的问题,又解决了对象识别的问题

   function Box(name, age) {       // 创建一个对象,所有构造函数的对象就是Object
        this.name = name;           // 添加一个属性
        this.age = age;
        this.run = function () {    // 添加一个方法
            return this.name + this.age + "运行中...";
        };
    }

   function Desk(name, age) {       // 创建一个对象,所有构造函数的对象就是Object
        this.name = name;           // 添加一个属性
        this.age = age;
        this.run = function () {    // 添加一个方法
            return this.name + this.age + "运行中...";
        };
    }
    var box1 = new Box("Lee", 100);  // 实例化
    var box2 = new Box("Jack", 200); // 实例化
    var box3 = new Desk("KKK",300); // 实例化

    alert(box1.run());
    alert(box2.run());

    alert(box1 instanceof Box);  // true;
    alert(box2 instanceof Box);  // true;
    // 对比可知,box3 是属于 Desk 的对象的引用,而不是 Box , 解决了识别问题
    alert(box3 instanceof Desk); // true;
    alert(box3 instanceof Box);   // false   

构造函数方式与工厂模式的不同之处:

  1. 构造函数没有 new Object , 但它后台会自动创建,并传给一个对象 var obj = new Object();
  2. this 就相当于 obj
  3. 构造函数不需要返回对象引用,后台自动返回

构造函数规范:

  1. 构造函数也是函数,但函数名第一个字母大写
  2. 必须 new 构造函数名(), new Box(), 而这个 Box 第一个字母也是大写的
  3. 必须使用 new 运算符

调用构造函数实际经历的过程:

  1. 创建一个新对象
  2. 将构造函数的作用域赋给这个新对象(因此,this就指向了这个新对象)
  3. 执行构造函数中的代码
  4. 返回新对象
    var o = new Object();
    Box.call(o, "abc", 10);
    alert(o.run());

也可以使用call()或apply() 在某个特殊对象的作用域中调用Box()函数。这里是在对象o的作用域中调用的,因此,调用后o就拥有了所有属性和run()方法

再来看一个问题:

   function Box(name, age) {
        this.name = name;
        this.age = age;
//        this.run = function () {
//            return this.name + this.age + "运行中...";
//        }
        this.run = new Function("return this.name + this.age + '运行中...'");
    }


    var box1 = new Box("Lee", 100);
    var box2 = new Box("Lee", 100);
    alert(box1.run()); // 正常执行
    alert(box1.run() == box2.run()); // true  方法的值相等
    alert(box1.run == box2.run);     // false  引用地址不同

以上代码可以看出,也可以使用 new Function() 的方法来代替 ,说明了 run() 是引用类型,值相等,而引用地址不等,说明值存储在堆内存中,引用地址存储在栈内存中,具有唯一性。

你可能感兴趣的:(JS 面向对象与原型(一))