diff --git a/core/includes/common.inc b/core/includes/common.inc
index 673ac9c..cea46ad 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -4043,77 +4043,36 @@ function drupal_region_class($region) {
  *     should load the JavaScript item. See
  *     drupal_pre_render_conditional_comments() for details.
  *
- * @return
+ * @return array
  *   The current array of JavaScript files, settings, and in-line code,
- *   including Drupal defaults, anything previously added with calls to
- *   drupal_add_js(), and this function call's additions.
+ *   anything previously added with calls to drupal_add_js(), and this function
+ *   call's additions. Drupal defaults (settings and jQuery/jQuery Once
+ *   libraries) are only included when $data is omitted and at least one
+ *   non-setting has been added.
  *
  * @see drupal_get_js()
  */
 function drupal_add_js($data = NULL, $options = NULL) {
   $javascript = &drupal_static(__FUNCTION__, array());
 
-  // Construct the options, taking the defaults into consideration.
-  if (isset($options)) {
-    if (!is_array($options)) {
-      $options = array('type' => $options);
+  if (isset($data)) {
+    // Construct the options, taking the defaults into consideration.
+    if (isset($options)) {
+      if (!is_array($options)) {
+        $options = array('type' => $options);
+      }
     }
-  }
-  else {
-    $options = array();
-  }
-  $options += drupal_js_defaults($data);
-
-  // Preprocess can only be set if caching is enabled.
-  $options['preprocess'] = $options['cache'] ? $options['preprocess'] : FALSE;
+    else {
+      $options = array();
+    }
+    $options += drupal_js_defaults($data);
 
-  // Tweak the weight so that files of the same weight are included in the
-  // order of the calls to drupal_add_js().
-  $options['weight'] += count($javascript) / 1000;
+    // Preprocess can only be set if caching is enabled.
+    $options['preprocess'] = $options['cache'] ? $options['preprocess'] : FALSE;
 
-  if (isset($data)) {
-    // Add jquery.js and drupal.js, as well as the basePath setting, the
-    // first time a JavaScript file is added.
-    if (empty($javascript)) {
-      // url() generates the script and prefix using hook_url_outbound_alter().
-      // Instead of running the hook_url_outbound_alter() again here, extract
-      // them from url().
-      // @todo Make this less hacky: http://drupal.org/node/1547376.
-      $scriptPath = $GLOBALS['script_path'];
-      $pathPrefix = '';
-      url('', array('script' => &$scriptPath, 'prefix' => &$pathPrefix));
-      $javascript = array(
-        'settings' => array(
-          'data' => array(
-            array('basePath' => base_path()),
-            array('scriptPath' => $scriptPath),
-            array('pathPrefix' => $pathPrefix),
-          ),
-          'type' => 'setting',
-          'scope' => 'header',
-          'group' => JS_SETTING,
-          'every_page' => TRUE,
-          'weight' => 0,
-          'browsers' => array(),
-        ),
-        'core/misc/drupal.js' => array(
-          'data' => 'core/misc/drupal.js',
-          'type' => 'file',
-          'scope' => 'header',
-          'group' => JS_LIBRARY,
-          'every_page' => TRUE,
-          'weight' => -1,
-          'preprocess' => TRUE,
-          'cache' => TRUE,
-          'defer' => FALSE,
-          'browsers' => array(),
-        ),
-      );
-      // Register all required libraries.
-      drupal_add_library('system', 'jquery', TRUE);
-      drupal_add_library('system', 'jquery.once', TRUE);
-      drupal_add_library('system', 'html5shiv', TRUE);
-    }
+    // Tweak the weight so that files of the same weight are included in the
+    // order of the calls to drupal_add_js().
+    $options['weight'] += count($javascript) / 1000;
 
     switch ($options['type']) {
       case 'setting':
@@ -4132,6 +4091,58 @@ function drupal_add_js($data = NULL, $options = NULL) {
         $javascript[$options['data']] = $options;
     }
   }
+  // If no $data was passed, then all added JavaScript is retrieved for
+  // inclusion in the response.
+  // @see drupal_get_js(), ajax_render()
+  else {
+    // If any JavaScript (except settings) has been added, include the required
+    // base libraries and default settings.
+    if (array_diff_key($javascript, array('settings' => 0))) {
+      drupal_add_library('system', 'jquery', TRUE);
+      drupal_add_library('system', 'jquery.once', TRUE);
+      $javascript += array('core/misc/drupal.js' => array());
+      $javascript['core/misc/drupal.js'] += array(
+        'data' => 'core/misc/drupal.js',
+        'type' => 'file',
+        'scope' => 'header',
+        'group' => JS_LIBRARY,
+        'every_page' => TRUE,
+        'weight' => -1,
+        'preprocess' => TRUE,
+        'cache' => TRUE,
+        'defer' => FALSE,
+        'browsers' => array(),
+      );
+
+      // url() generates the script and prefix using hook_url_outbound_alter().
+      // Instead of running the hook_url_outbound_alter() again here, extract
+      // them from url().
+      // @todo Make this less hacky: http://drupal.org/node/1547376.
+      $scriptPath = $GLOBALS['script_path'];
+      $pathPrefix = '';
+      url('', array('script' => &$scriptPath, 'prefix' => &$pathPrefix));
+
+      $javascript += array('settings' => array());
+      $javascript['settings'] += array(
+        'data' => array(),
+        'type' => 'setting',
+        'scope' => 'header',
+        'group' => JS_SETTING,
+        'every_page' => TRUE,
+        'weight' => 0,
+        'browsers' => array(),
+      );
+      $javascript['settings']['data'][] = array('basePath' => base_path());
+      $javascript['settings']['data'][] = array('scriptPath' => $scriptPath);
+      $javascript['settings']['data'][] = array('pathPrefix' => $pathPrefix);
+    }
+
+    // Unconditionally add the html5shiv to all pages; it is required for
+    // backwards-compatible CSS styling and has no dependencies.
+    // @todo See todo in drupal_get_js()?
+    drupal_add_library('system', 'html5shiv', TRUE);
+  }
+
   return $javascript;
 }
 
@@ -4194,34 +4205,62 @@ function drupal_js_defaults($data = NULL) {
  * @see drupal_js_defaults()
  */
 function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALSE) {
-  if (!isset($javascript)) {
-    $javascript = drupal_add_js();
+  // The theme system invokes drupal_get_js() multiple times for different page
+  // regions (scopes). In order to not add Drupal's default JavaScript libraries
+  // to the page when no JavaScript (except the html5shiv) is needed,
+  // drupal_add_js() only inserts the defaults when it is called the first time
+  // without arguments. However, the html5shiv is always added by default.
+  // In turn, this means that more than one call to drupal_add_js() without
+  // arguments will insert the default libraries. Therefore, this function
+  // shares the static variable with drupal_add_js().
+  // @todo One could argue that html5shiv.js only needs to be added for HTML
+  //   pages, so instead of unconditionally adding it in drupal_add_js(), it
+  //   would be added in template_preprocess_page(). One could even argue the same
+  //   for jQuery libraries. ;) That would obviously make this a lot easier. ;)
+  $javascript = &drupal_static('drupal_add_js', array());
+  // Call drupal_add_js() the first time this function is called in order to
+  // check whether default libraries need to be added.
+  $initialized = &drupal_static(__FUNCTION__);
+  if (!isset($initialized)) {
+    drupal_add_js();
+    $initialized = TRUE;
   }
+
   if (empty($javascript)) {
     return '';
   }
 
-  // Allow modules to alter the JavaScript.
-  if (!$skip_alter) {
-    drupal_alter('js', $javascript);
-  }
-
   // Filter out elements of the given scope.
   $items = array();
   foreach ($javascript as $key => $item) {
-    if ($item['scope'] == $scope) {
+    if (isset($item['scope']) && $item['scope'] == $scope) { 
       $items[$key] = $item;
     }
   }
 
+  // Allow modules to alter the JavaScript.
+  if (!$skip_alter) {
+    drupal_alter('js', $items);
+  }
+
   // Sort the JavaScript so that it appears in the correct order.
   uasort($items, 'drupal_sort_css_js');
 
   // Provide the page with information about the individual JavaScript files
   // used, information not otherwise available when aggregation is enabled.
-  $setting['ajaxPageState']['js'] = array_fill_keys(array_keys($items), 1);
-  unset($setting['ajaxPageState']['js']['settings']);
-  drupal_add_js($setting, 'setting');
+  if ($files = array_diff_key($items, array('settings' => 0))) {
+    $setting['ajaxPageState']['js'] = array_fill_keys(array_keys($files), 1);
+    $javascript['settings']['data'][] = $setting;
+    // If no other settings were added yet, supply the defaults.
+    $javascript['settings'] += array(
+      'type' => 'setting',
+      'scope' => 'header',
+      'group' => JS_SETTING,
+      'every_page' => TRUE,
+      'weight' => 0,
+      'browsers' => array(),
+    );
+  }
 
   // If we're outputting the header scope, then this might be the final time
   // that drupal_get_js() is running, so add the setting to this output as well
@@ -4229,7 +4268,7 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
   // because drupal_get_js() was intentionally passed a $javascript argument
   // stripped of settings, potentially in order to override how settings get
   // output, so in this case, do not add the setting to this output.
-  if ($scope == 'header' && isset($items['settings'])) {
+  if ($scope == 'header' && isset($items['settings']) && isset($setting)) {
     $items['settings']['data'][] = $setting;
   }
 
diff --git a/core/modules/system/tests/common.test b/core/modules/system/tests/common.test
index 46b379e..9bdb759 100644
--- a/core/modules/system/tests/common.test
+++ b/core/modules/system/tests/common.test
@@ -1191,6 +1191,7 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
     // Only the second of these two entries should appear in Drupal.settings.
     drupal_add_js(array('commonTestArray' => array('key' => 'commonTestOldValue')), 'setting');
     drupal_add_js(array('commonTestArray' => array('key' => 'commonTestNewValue')), 'setting');
+    drupal_add_js('core/misc/jquery.js');
 
     $javascript = drupal_get_js('header');
     $this->assertTrue(strpos($javascript, 'basePath') > 0, t('Rendered JavaScript header returns basePath setting.'));
@@ -1556,6 +1557,63 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
 }
 
 /**
+ * Tests addition of JavaScript default settings and libraries.
+ */
+class CommonJavaScriptDefaultsTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'JavaScript defaults',
+      'description' => 'Tests addition of JavaScript default settings and libraries.',
+      'group' => 'Common',
+    );
+  }
+
+  /**
+   * Tests JavaScript default settings and libraries.
+   */
+  function testJavaScriptDefaults() {
+    // Verify that a page that does not use any Drupal JavaScript only contains
+    // non-Drupal and non-jQuery scripts.
+    $this->drupalGet('');
+    $this->assertNoRaw('Drupal.settings', 'Drupal.settings not found.');
+    $this->assertNoRaw('jQuery', 'jQuery not found.');
+    $this->assertNoRaw('jquery', 'jquery not found.');
+
+    // When only settings are added in a request, no JavaScript should appear.
+    drupal_static_reset();
+    drupal_add_js(array('foo' => 'bar'), 'setting');
+    $this->drupalGetJS();
+    $this->assertNoRaw('Drupal.settings', 'Drupal.settings not found.');
+    $this->assertNoRaw('jQuery', 'jQuery not found.');
+    $this->assertNoRaw('jquery', 'jquery not found.');
+
+    // When adding any other JavaScript, default libraries and settings should
+    // appear.
+    drupal_static_reset();
+    drupal_add_js('core/misc/ajax.js');
+    $this->drupalGetJS();
+    $this->assertRaw('Drupal.settings', 'Drupal.settings found.');
+    $this->assertRaw('jQuery', 'jQuery found.');
+    $this->assertRaw('jquery', 'jquery found.');
+
+    // @todo Test ajaxPageState settings expectations.
+    //   Given that page rendering in template_process_html() invokes
+    //   drupal_get_js() more than once, the processing, comments, and actual
+    //   expectations are pretty hard to identify.
+  }
+
+  /**
+   * Sets the rendered JavaScript as browser content and logs it verbosely.
+   */
+  function drupalGetJS() {
+    // drupal_get_js() is called for each region/scope during page rendering.
+    // @see template_process_html()
+    $this->drupalSetContent(drupal_get_js('footer') . drupal_get_js());
+    $this->verbose('<pre style="white-space: pre-wrap">' . check_plain($this->drupalGetContent()) . '</pre>');
+  }
+}
+
+/**
  * Tests for drupal_render().
  */
 class CommonDrupalRenderTestCase extends DrupalWebTestCase {
