jquery.js和zepto.js中的extend源码分析

       关于js对象的属性继承,只要是对js有了解,应该都知道,由于js最初的定位,并没有类似于java、python这类语言关于类的接口。而随着javascript这门语言的广泛使用,越来越多的程序员应用其做复杂的应用开发,面对复杂应用,面向对象的思想随之引入javascript。运用javascript构建对象以及建立对象与对象之间的关系成为当时js程序员着手解决的问题。

       当下,在ES6标准中的class语法糖已经很明确的标识出js正是一门面向对象的语言,其模块化的方案也越来越具备构建大型复杂应用程序的能力。但在ES6标准出现之前,又是通过什么样的方式构建对象以及对象之间关系的呢?

       在思考这个问题之前,我们首先要理解的是js的类型,js标准中存在array、function、object,而对于function类型来说,它拥有__proto__、prototype、constructor这三个属性。

我们可以试着这样在浏览器中查看:

//object
var s = Object.create({});
console.log(s);
//array
var a = [];
console.log(a);
//function
var f = function(){

}
console.log(f);

对于__proto__、constructor这个是对象特有的一个属性,这也就说明了js中的array以及function可以被当做对象来处理。为此,之前我们可以这样构建一个类:

var testClass = function(){
    this.test = 1;
}

testClass.prototype = {
    'init': function(){
        return 'init';
     }
};

var testObj = new testClass();

这是由function类型特有的属性prototype,又称函数原型所构建,prototype的类型必须是一个object,这个object类型可以被继承,也即实例化。以上面代码为例,所谓的实例化就是new运算符,先是创建一个继承自testClass.prototype的新对象,然后执行testClass的constructor属性亦即构造函数,将该函数(testClass)中的一些上下文环境(this)、变量传递给新对象,之后返回这个新对象。

      而对于__proto__则是js中的原型链机制,其指向它的上一级直到基本对象。

为此我们可以利用这个原理实现一个简易的function类型的继承。

function extend(target, source){
    if(typeof source ! == 'function'){
        return function(){};
    }
    var tmp = new source();
    
    target.prototype = tmp;
    target.prototype.constructor = target.prototype.constructor.call(source);

    return target;
}

现在我们分析下jquery和zepto中的extend(对象继承):

jquery:

jQuery.extend = jQuery.fn.extend = function() {
	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" && typeof target !== "function" ) {
		target = {};
	}

	// Extend jQuery itself if only one argument is passed
	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 ) {
				copy = options[ name ];

				// Prevent Object.prototype pollution
				// Prevent never-ending loop
				if ( name === "__proto__" || target === copy ) {
					continue;
				}

				// Recurse if we're merging plain objects or arrays
				if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
					( copyIsArray = Array.isArray( copy ) ) ) ) {
					src = target[ name ];

					// Ensure proper type for the source value
					if ( copyIsArray && !Array.isArray( src ) ) {
						clone = [];
					} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
						clone = {};
					} else {
						clone = src;
					}
					copyIsArray = false;

					// Never move original objects, clone them
					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;
};

zepto:

function extend(target, source, deep) {
    for (key in source)
      if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
        if (isPlainObject(source[key]) && !isPlainObject(target[key]))
          target[key] = {}
        if (isArray(source[key]) && !isArray(target[key]))
          target[key] = []
        extend(target[key], source[key], deep)
      }
      else if (source[key] !== undefined) target[key] = source[key]
  }

  // Copy all but undefined properties from one or more
  // objects to the `target` object.
  $.extend = function(target){
    var deep, args = slice.call(arguments, 1)
    if (typeof target == 'boolean') {
      deep = target
      target = args.shift()
    }
    args.forEach(function(arg){ extend(target, arg, deep) })
    return target
  }

可以看出zepto和jquery在本质上没什么区别,都是浅拷贝和深拷贝的结合,唯一区别就是zepto运用了函数柯里化。

浅拷贝是一个对象的属性应有另一个对象,就像c语言中的指针一样。深拷贝的好处就是实例化原对象,对本对象的某个属性修改不会对原对象的属性修改。对应上面的源码部位就是:target[key]={},和target[key]=[]

总之在jquery和zepto中对象与对象之间的继承就是运用的深拷贝的原理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值