Javascript是一种基于原型的对象语言,而不是我们比较熟悉的,像C#语言基于类的面向对象的语言。在前一篇文章中,我们已经介绍了Javascript中对象定义的创建。接下来我们来介绍一下Javascript对象的继承。我们通过一个例子来介绍对象继承实现的几种方法。

比如,现在有一个“水果”的构造函数:

function Fruit(color) {

    this.color = color;

    this.whatColor = function () {
console.log("This fruit color is " + this.color + ".");
} this.contain = function () {
console.log("Which vitamins it contains.")
}
}

另外”苹果“的构造函数:

function Apple(variety, color) {

    this.variety = variety;

    this.color = color;

    this.whatVariety = function () {
console.log("It is " + this.variety + ".");
};
}

那么在Javascript中如何让”苹果“继承”水果“呢?

  1. 构造函数的继承

    在前面的文章中,我们介绍过函数对象的方法call和apply,它们都是用来调用某个函数,并用方法中指定的对象来替换所调用方法中this。正是基于这一点,我们可以考虑在Apple的构造函数中调用函数Fruit,让Apple对象来替换Fruit中的this,这样就让Apple对象有了Fruit的contain方法,Apple本身的属性color也可以不用在本身的构造函数中定义了。

    function Apple(variety, color) {
    Fruit.call(this, color); this.variety = variety; this.whatVariety = function () {
    console.log("It is " + this.variety + ".");
    }
    } var myApple = new Apple("红富士", "red");
    myApple.whatColor(); //This fruit color is red.
    myApple.contain(); //Which vitamins it contains.
    myApple.whatVariety(); //It is 红富士.

    可以看出Apply对象除了拥有自己本省的属性外,还拥有Fruit对象的属性和方法。但是如果Fruit对象原型有一个属性type定义如下

    Fruit.prototype.type = "fruit";

    这时候如果还利用上面的方法继承,我们就会发现在myApple里面没有定义属性type

    alert(typeof(myApple.type)); // undefined
  2. 原型(prototype)模式继承

    我们知道每个对象都有一个prototype,这也是Javascript的特点。

    如果让Apple的原型指向Fruilt对象的一个实例,那么Apple对象就能有Fruit的所有属性和方法了

       function Apple(variety, color) {       
    
            Fruit.call(this, color);
    this.variety = variety; this.whatVariety = function () {
    console.log("It is " + this.variety + ".");
    }
    } Apple.prototype = new Fruit();
    Apple.prototype.constructor = Apple; var myApple = new Apple("红富士", "red");
    myApple.whatColor(); // This fruit color is red.
    myApple.contain(); //Which vitamins it contains.
    alert(myApple.type); // fruit

    每个对象原型都有一个constructor属性指向对象的构造函数,每一个对象实例也有一个constructor属性,默认调用原型的constructor。如果没有 Apple.prototype.constructor = Apple; ,那么会因为 Apple.prototype = new Fruit(); 让Apple.prototype.constructor指向了Fruit,这显然会导致继承链的紊乱,因此我们必须手动纠正,将Apple.prototype对象的constructor值改为Apple。这是很重要的一点,编程时务必要遵守。我们在Javascript中应该遵循这一点,即如果替换了prototype对象,必须要将属性constructor指回原来的构造函数(对象原本的构造函数)。

    上面这种方法看上去没有什么问题,但是有一个缺点:定义新对象时需要创建一个被继承对象的实例,有时候在一做法需要消耗一定内存,效率不高。如果直接把Fruit.prototype赋给Apple.prototype的话,那就不需要创建对象实例了,

        function Fruit(color) {
    
            this.color = color;
    
            this.whatColor = function () {
    console.log("This fruit color is " + this.color + ".");
    } this.contain = function () {
    console.log("Which vitamins it contains.")
    }
    } Fruit.prototype.type = "fruit"; function Apple(variety, color) {
    Fruit.call(this, color); this.variety = variety; this.whatVariety = function () {
    console.log("It is " + this.variety + ".");
    }
    } Apple.prototype = Fruit.prototype; // it may let the constructor of Apple be Fruit.
    Apple.prototype.constructor = Apple; // assign the constructor back to itself var myApple = new Apple("红富士", "red");
    alert(typeof (myApple.type)); // fruit

    这样Apple对象继承了父对象Fruit的所有属性和方法, 而且效率高,比较省内存。但是缺点是Apple对象的原型和Fruilt对象的原型是同一个对象,如果我们修改其中的一个,势必就会影响到另外一个。

    所以代码 Apple.prototype.constructor = Apple; ,虽然让修正了Apple构造函数的问题,但是Fruit对象的构造函数又有问题。

    alert(Fruit.prototype.constructor === Apple); // true

    结合原型模式继承的这两种方式的优缺点和问题,我们有了另外一种继承方法。

  3. 利用空对象作为中介来继承

        function Fruit(color) {
    
            this.color = color;
    
            this.whatColor = function () {
    console.log("This fruit color is " + this.color + ".");
    } this.contain = function () {
    console.log("Which vitamins it contains.")
    }
    } Fruit.prototype.type = "fruit"; function Apple(variety, color) { Fruit.call(this, color);
    this.variety = variety; this.whatVariety = function () {
    console.log("It is " + this.variety + ".");
    }
    } function Empty() {
    }
    Empty.prototype = Fruit.prototype;
    Apple.prototype = new Empty();
    Apple.prototype.constructor = Apple;

    Empty对象是空对象,几乎不占内存,而且如果修改Apple.prototype不会影响到Fruit的prototye对象。在有的javascript库通常将上面的这种方法封装成一个函数:

    function extend(child, parent) {
    var e = function () { };
    e.prototype = parent.prototype;
    child.prototype = new e();
    child.prototype.constructor = child;
    }

    大家在使用这种方式的时候千万不要忘记在子对象的构造函数中调用父对象的构造函数来初始化父对象中属性和方法,不至于每个新创建的子对象实例中父对象属性都是默认值。如果上面的例子中移除

    Fruit.call(this, color);

    之后,

        var myApple = new Apple("HFS", "red");
    myApple.whatColor(); // This fruit color is undefined.

    虽然我们在创建Apple实例的时候传了“red”值进去,但是取出来的却是undefined,为什么呢?问题就出现在 Apple.prototype = new Empty(); 上,这时候Apple里面没有定义color属性,所以即使有值传进构造函数中,获取到color属性还是未定义的。加上父对象构造函数调用的代码后,就让子对象拥有了父对象的方法和属性,并利用传入的值对它们进行初始化。

  4. 拷贝继承

    接下来我们介绍另外一种方式,纯粹采用"拷贝"方法实现继承。简单说,通过把父对象实例的所有属性和方法,拷贝进子对象来实现继承。

        function Fruit(color) {
    
            this.color = color;
    
            this.whatColor = function () {
    console.log("This fruit color is " + this.color + ".");
    } this.contain = function () {
    console.log("Which vitamins it contains.")
    }
    } Fruit.prototype.type = "fruit"; Function.prototype.extendEx = function (parent) {
    for (var p in parent) {
    this.prototype[p] = parent[p];
    }
    } function Apple(variety, color) { Fruit.call(this, color);
    this.variety = variety; this.whatVariety = function () {
    console.log("It is " + this.variety + ".");
    }
    }
    Apple.extendEx(new Fruit()); var myApple = new Apple("HFS", "red");
    myApple.whatColor(); // This fruit color is red.
    myApple.contain(); //Which vitamins it contains.
    alert(myApple.type); // fruit

Javascript中的对象(二)的更多相关文章

  1. javascript中的对象,原型,原型链和面向对象

    一.javascript中的属性.方法 1.首先,关于javascript中的函数/“方法”,说明两点: 1)如果访问的对象属性是一个函数,有些开发者容易认为该函数属于这个对象,因此把“属性访问”叫做 ...

  2. javascript中Date对象的应用——简易日历的实现

    × 目录 [1]效果 [2]HTML [3]CSS[4]JS 前面的话 简易日历作为javascript中Date对象的常见应用,用途较广泛.本文将详细说明简易日历的实现思路 效果演示 HTML说明 ...

  3. Javascript中的对象和原型(3)

    在Javascript中的对象和原型(二)中我们提到,用构造函数创建的对象里面,每个对象之间都是独立的,这样就会降低系统资源的利用率,解决这样问题,我们就要用到下面提到的原型对象. 一 原型对象 原型 ...

  4. javascript中Date对象的应用

    前面的话 简易日历作为javascript中Date对象的常见应用,用途较广泛.本文将详细说明简易日历的实现思路 效果演示 HTML说明 使用type=number的两个input分别作为年和月的输入 ...

  5. Javascript中的对象和原型(三)(转载)

    在Javascript中的对象和原型(二)中我们提到,用构造函数创建的对象里面,每个对象之间都是独立的,这样就会降低系统资源的利用率,解决这样问题,我们就要用到下面提到的原型对象. 一 原型对象 原型 ...

  6. Javascript中的对象和原型(一)(转载)

    面向对象的语言(如Java)中有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象.但是,JavaScript 没有类的概念,因此它的对象也与基于类的语言中的对象有所不同. 要了解面向对象,首 ...

  7. JavaScript中的对象与原型—你不知道的JavaScript上卷读书笔记(四)

    一.对象 对象可以通过两种形式定义:声明(文字)形式和构造形式.即: var myObj = { key: value // ... }; 或: var myObj = new Object(); m ...

  8. Javascript 中判断对象为空

    发现了一个巧妙的实现: 需要检查一个对象(Object)是否为空,即不包含任何元素.Javascript 中的对象就是一个字典,其中包含了一系列的键值对(Key Value Pair).检查一个对象是 ...

  9. JavaScript 中的对象

    JavaScript 中的对象 在 JavaScript 中,对象是数据(变量),拥有属性和方法. JavaScript 中的所有事物都是对象:字符串.数字.数组.日期,等等.   访问对象的属性 访 ...

  10. JavaScript中判断对象类型方法大全1

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

随机推荐

  1. 小白成长记-----python实现注册的小程序

    # 3.写一个注册的程序,输入username,密码,# 密码确认,输入的账号和密码不能为空,两次输入密码必须一致,# 用户名不能重复,错误次数四次 .注册成功提示成功# 把注册账号密码信息的写到文件 ...

  2. 欢迎访问新博客aiyoupass.com

    新博客基本搭建好了,欢迎访问.aiyoupass.com

  3. django中使用第三方包实现定时任务

    # 转载请留言联系 在做主页静态化的时候,需要定时生成主页HTML,以保持数据的最新. 定时任务可以用第三方包django-crontab来实现. 附上官方文档:https://pypi.org/pr ...

  4. Centos7 环境准备

    Centos7 环境准备 #关闭防火墙 systemctl stop firewalld systemctl disable firewalld #关闭selinux sed -i 's/SELINU ...

  5. 181. Employees Earning More Than Their Managers

    The Employee table holds all employees including their managers. Every employee has an Id, and there ...

  6. K8S的APISERVER,应用了HTTPS之后,命令行如何访问?

    用命令行总是很麻烦,因为要自定义一些证书的位置....... curl https://1.2.3.1:443/api/v1/nodes \ --cacert /etc/kubernetes/pki/ ...

  7. sprint定时任务执行两次

    我这里遇到的是tomcat问题,把appBase设置为空 <Host name="localhost" appBase="" unpackWARs=&qu ...

  8. 将Electron桌面应用转化为Win10的UWP应用

    如果有小伙伴不知道如何打包Electron桌面应用的,请戳我. 微软提供了一款快捷工具:electron-windows-store,用于将electron桌面应用打包成Windows10系统上.ap ...

  9. Sass和Compass的安装

    Sass和Compass都是基于Ruby编程语言的命令行工具.要使用它们,你首先需要在电脑中安装Ruby,并对电脑的命令行操作有一个基本的理解.Sass和Compass可以安装在Windows.Mac ...

  10. 【BZOJ 1901】【ZJU 2112】Dynamic Rankings

    http://www.lydsy.com/JudgeOnline/problem.php?id=1901 重新用整体二分写了一下. 整体二分的思想详见论文. 貌似带修区间k大和静态区间k大都是\(O( ...