js 中分为基本变量,和引用变量。在$.extend(),体现得非常深刻。
除了数组,对象,其他的变量都可以称为基本变量。
var a = 3;
var b = a;
b = 4;
console.log(a); //3
console.log(b); //4
var a = {name:"strong"}
var b = a;
b.name = "Lee";
console.log(a.name) // Lee;
console.log(b.name) //Lee;
ps:可见,b属性的变化,影响到了a , 这种赋值就是浅复制,而取消这种影响,就是深复制 ;
在jQuery源码中,对于 对象 还有一个判断函数 是 $.isPlainObject(),用于判断此对象是否为“纯对象”,纯对象就是变量直接申请的对象。
var a = {
a:3
};
function cons(){
this.a = 3;
}
var b = new cons();
// a就是纯对象,而b就不是。
以下为jquery中 isPlainObject 的源码。
//此函数的核心,就是以object.prototype.constructor 属性,来判断是否为纯对象。
//当 constructor是 Object() 时,为纯对象;当为其他构造函数时就是非纯函数。
isPlainObject: function( obj ) {
var proto, Ctor;
// Detect obvious negatives
// Use toString instead of jQuery.type to catch host objects
if ( !obj || toString.call( obj ) !== "[object Object]" ) {
return false;
}
proto = getProto( obj ); //obj的原型
// Objects with no prototype (e.g., `Object.create( null )`) are plain
if ( !proto ) {
return true;
}
// Objects with prototype are plain if they were constructed by a global Object function
Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
}
深层复制的基本原理就是将对象引用,变为基本变量赋值,这样就不会出现对象引用后,修改对象属性,造成原对象属性污染。通俗一点,就是要把对象的属性(此属性为基本变量) 赋值给 另一个对象的相应属性;
所以我们可以自己先写一个较为简单的 深层复制 对象扩展函数,
function extend(target,src){
for( i in src){
var a = target[i]?target[i]:{};
//判断纯对象,并递归或直接赋值;
target[i] = $.isPlainObject(src[i])?extend(a,src[i]):src[i];
}
return target;
}
ps:jquery中的深层复制只能对于纯对象,以下特例不会进行深层复制的
function a(){
this.a = 3;
}
var b = {
c :3,
d : new a()
}
var e = {};
$.extend(e,b);
b当中的d属性并不会深层复制给e,当e改变d属性时会影响b.d 的值;
以下为jquery中extend的源码:
jQuery.extend = jQuery.fn.extend = function() {
//arguments[0] -> boolean;
//arguments[1] -> target;
//arguments[2] -> src
var options, name, src, copy, copyIsArray, clone,
target = arguments[ 0 ] || {},
i = 1, //记录处理的参数位置
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
target = {};
}
// Extend jQuery itself if only one argument is passed
//like $().extend({a:3})
//另外一种形式$.extend(a,b) //jquery工具方法;
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( ( options = arguments[ i ] ) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ]; // 将要被复制到的地址
copy = options[ name ]; // 来源内容,属性
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
//recurse 递归吧
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = jQuery.isArray( copy ) ) ) ) {
if ( copyIsArray ) { // 此if,根据src 类型 , 改变clone;
copyIsArray = false;
clone = src && jQuery.isArray( src ) ? src : [];
} else {
clone = src && jQuery.isPlainObject( src ) ? src : {};
}
// Never move original objects, clone them
//copy 是对象,且好几层对象,递归复制,保障深层复制成功。
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
网友评论