Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When nodeType() used in object behaves different in jQuery versions '1.11.2' and '3.1.1'

I am eager to know why the jQuery versions '1.11.2' and '3.1.1' behaves in two different ways while using nodeType() function in jQuery object.

To illustrate this, I have two fiddle links for these two versions.

jquery-1.11.2
https://jsfiddle.net/38z9m9j9/9/

jquery-3.1.1
https://jsfiddle.net/38z9m9j9/8/

And in this, I have an condition that,

this.options.data == data.colors[0];

This gets equal only in version '1.11.2' on using 'nodeType()' function for object 'this.options.data.colors[0]' where as not working in '3.1.1'. So, how does the 'nodeType()' works here in '1.11.2'?

Thanks in advance.

like image 800
Abu Avatar asked May 23 '17 11:05

Abu


1 Answers

Cause of the problem in the difference in implementation of the function isPlainObject in these two versions of jQuery.

The current isPlainObject in 1.4 tests .nodeType because IE makes dom nodes look like objects. This has the side effect that $.isPlainObject({ nodeType: ... }); will return false when it should return true. (From jQuery Forum)

Use jQuery 1.11.2

var data = {
  colors: {
    id: 1,
    color: "red",
    nodeType: function () {},
  }
};

function logPlain (value, log) {
	value && value.color == "red" && $('#plain').text(log);
}

//from release of jQuery UI-1.12.1
$.widget.extend = function( target ) {
	var widgetSlice = Array.prototype.slice;
  var input = widgetSlice.call( arguments, 1 );
	var inputIndex = 0;
	var inputLength = input.length;
	var key;
	var value;

	for ( ; inputIndex < inputLength; inputIndex++ ) {
		for ( key in input[ inputIndex ] ) {
			value = input[ inputIndex ][ key ];
			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {

				// Clone objects
				if ( $.isPlainObject( value ) ) {
          logPlain(value, 'true');
					target[ key ] = $.isPlainObject( target[ key ] ) ?
						$.widget.extend( {}, target[ key ], value ) :

						// Don't extend strings, arrays, etc. with objects
						$.widget.extend( {}, value );

				// Copy everything else by reference
				} else {
          logPlain(value, 'false');
					target[ key ] = value;
				}
			}
		}
	}
	return target;
};

$(function() {
  $.widget("custom.widget2", {
    options: {
      data: null
    },
    _create: function() {
      var isDataEqual = this.options.data == data.colors;
      $('#equal').text(isDataEqual ? "true" : "false");
    },
  });

  $("#my-widget1").widget2({
    data: data.colors
  });

});
#equal, #plain {
  background-color: rgba(0, 128, 0, 0.31);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div>
  <div id="my-widget1">Testing 'nodeType' in jQuery version-1.11.2</div>
  <div>isPlainObject: <span id="plain"></div>
  <div>isDataEqual: <span id="equal"></span></div>
</div>

Use jQuery 3.1.1:

var data = {
  colors: {
    id: 1,
    color: "red",
    nodeType: function () {},
  }
};

function logPlain (value, log) {
	value && value.color == "red" && $('#plain').text(log);
}

//from release of jQuery UI-1.12.1
$.widget.extend = function( target ) {
	var widgetSlice = Array.prototype.slice;
  var input = widgetSlice.call( arguments, 1 );
	var inputIndex = 0;
	var inputLength = input.length;
	var key;
	var value;

	for ( ; inputIndex < inputLength; inputIndex++ ) {
		for ( key in input[ inputIndex ] ) {
			value = input[ inputIndex ][ key ];
			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {

				// Clone objects
				if ( $.isPlainObject( value ) ) {
          logPlain(value, 'true');
					target[ key ] = $.isPlainObject( target[ key ] ) ?
						$.widget.extend( {}, target[ key ], value ) :

						// Don't extend strings, arrays, etc. with objects
						$.widget.extend( {}, value );

				// Copy everything else by reference
				} else {
          logPlain(value, 'false');
					target[ key ] = value;
				}
			}
		}
	}
	return target;
};

$(function() {
  $.widget("custom.widget2", {
    options: {
      data: null
    },
    _create: function() {
      var isDataEqual = this.options.data == data.colors;
      $('#equal').text(isDataEqual ? "true" : "false");
    },
  });

  $("#my-widget1").widget2({
    data: data.colors
  });

});
#equal, #plain {
  background-color: rgba(0, 128, 0, 0.31);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div>
  <div id="my-widget1">Testing 'nodeType' in jQuery version-3.1.1</div>
  <div>isPlainObject: <span id="plain"></div>
  <div>isDataEqual: <span id="equal"></span></div>
</div>

Call stack when creating new jQuery UI widget:

  • _createWidget(options)
  • $.widget.extend({}, options)
  • $.isPlainObject(options.colors)

If $.isPlainObject(options.colors) == true then options.colors is cloned into a new object options (jQuery 3.1.1). isDataEqual will be false.

Otherwise options.colors is copied by reference to a new object options (jQuery 1.11.0). isDataEqual will be true.

Why? In jQuery 1.11.2 in the method $.isPlainObject there is the following check:

if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
    return false;
}

So if there is a property nodeType in the object, the method $.isPlainObject returns false.

like image 68
ollazarev Avatar answered Oct 23 '22 09:10

ollazarev