JS 继承又一法

简介: 首先贴出 DC 的 Object.create(),这是理解 js 创建对象的关键。如下: if (!Object.create) { /** * @ref https://developer.

首先贴出 DC 的 Object.create(),这是理解 js 创建对象的关键。如下:

if (!Object.create) {
    /**
    * @ref https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
    */
    Object.create = function (o) {
        if (arguments.length > 1) {
            throw new Error('Object.create implementation only accepts the first parameter.');
        }
        function F() { }
        F.prototype = o;
        return new F();
    };
}
然后,贴出我写的 $$.define/ $$.mix。如下:

/**
* 定义一个类并让它继承于某个父类。
* @param {Function/[]/Object} fatherClass	父类函数引用
* @param {Function} classBody		子类函数体
* @param {Object}	 args			构造器参数,当前仅单参数
*/
$$.define = function (fatherClass, classBody, args) {
    if (fatherClass instanceof Array) {
        return $$.mix.apply(this, arguments);
    }

    // 如果从 Object 继承 则分配一个虚拟的父类。
    classBody.prototype = fatherClass === Object ? function () {
        this.constructor = function () { }
    } : fatherClass.prototype;


    var _pro = args ? new classBody(args) : new classBody;
    if (_pro.constructor) {
        _pro.constructor.prototype = _pro;
        return _pro.constructor;
    } else {
        function F() { } 	// 不提供构造器,设置一个空的。
        F.prototype = _pro;
        return F;
    }
}

/**
* 混入
* 参见:
* 《JS OO继承、多态一法》 http://blog.csdn.net/zhangxin09/article/details/6226279
* 《透视Ext JS 4类背后的机制与特点(上)》http://blog.csdn.net/zhangxin09/article/details/6197408
* @param {Function []} _Class 父类
* @param {Object} sub 子类
* @param {Array} args 可选的参数列表
*/
$$.mix = function (fatherClasses, classBody, args) {
    var _pro = args ? new classBody(args) : new classBody;
    _pro.constructor.prototype = _pro;

    for (var _fatherClass, _newSubClass, i = 0, j = fatherClasses.length; i < j; i++) {
        fatherClasses[i].prototype.constructor.call(_pro);
    }

    return _pro.constructor;
}

主要理解两点:

  • prototype = new Function,必须以“对象/函数”二义性的写法写出对象 prototype;
  • 构造器同一闭包下的写法。做法就是 new 了 prototype 之后,用其 constructor:Function 作构造器并赋予“类”返回。
举一个例子如下,某组件的写法:
$$.Component = function(){
	
}
/**
 * @param {Object} defaultCfg
 * @return {Object}
 */
$$.Component.loadCfg = function (defaultCfg, instanceCfg){
	instanceCfg = instanceCfg || new Object; // 新建一个配置容器
	for(var i in defaultCfg){
		if(!instanceCfg[i]){
			instanceCfg[i] = defaultCfg[i]; // 读取默认值
		}
	}
	
	return instanceCfg;
}
$$.Component.prototype = new function(){
	var getEl = document.getElementById;
	this.getEl = $$.Component.getEl = function(cfg){
		var el;
		if(cfg instanceof HTMLElement){
			el = cfg;
		}else if(typeof cfg == 'string'){
			el = getEl(cfg);
		}else if(cfg.el || cfg.container){
			return arguments.callee(cfg.el || cfg.container);
		}
		
		if(!el){
			console.dir(cfg);
			throw '没有指定的元素!';
		}
		
		return el;
	}
}

/**
 * @class $$.dhtml.ExpandBox
 * 可折叠的一个容器。结构如下:
 * <container>
 * 	<p>
 * 	</p>
 *  <mask></mask>
 * </container>
 */
$$.dhtml.ExpandBox = $$.define($$.Component, function(){
	this.constructor = function(el){
		this.container = el.container;
		// p 即 contetnt 区域是必须的
		
		// mask 是可选的,视乎你在 HTML 有否安排 mask tag
		this.mask = this.container.querySelector('.x-contMask');
		
		this.el = el;
		this.btn = el.toogleBtn;
		if(!this.btn){
			throw '找不到按钮!';
		}
		this.init();
	}
	
	this.showMoreText = "显示更多";
	this.closeText = '收 起';
	
	this.init = function (){
		this.p = this.container.querySelector('p');
		if(!this.p){
			throw '正文内容必须具备,请设置好元素!';
		}
		this.colHeight = this.p.clientHeight; /* 此处的 80 是与 css 设置的一样 */
		if(!this.colHeight){
			throw '不能获取原始高度';
		}

		this.btn.onClk(toggleHandler.bind(this));
		this.el.toggleHandler && this.btn.onClk(this.el.toggleHandler.bind(this));
	}
	
	var fxFn = $$.dhtml.Fx.slide;
	var dTime = 150;
	
	function toggleHandler(e){
		var btn = e.currentTarget;
		if(	btn.innerHTML == this.closeText){
//			fxFn(this.p, 'height', this.p.scrollHeight, this.colHeight, dTime);
			move(this.p, this.p.scrollHeight,  this.colHeight);
			btn.innerHTML = this.showMoreText;
			this.mask && this.mask.addClass('x-contMask_bg');
			this.currentState = 'closed';
		}else{
//			fxFn(this.p, 'height', this.colHeight, this.p.scrollHeight, dTime);
			move(this.p,  this.colHeight, this.p.scrollHeight);
			btn.innerHTML = this.closeText;
			this.currentState = 'opened';
			this.mask && this.mask.removeClass('x-contMask_bg');
		}
	}
	
	/**
	 * 缓动公式
	 * @param {Element} el
	 * @param {Number} s 初始值
	 * @param {Number} v 目标值
	 */
	function move(el, s, v){
		var style = el.style;
		function fx(){
//			debugger;
//			console.log(v);
			/*用来保存上一次的左标*/
			var old = style.height || s || 0;
			var x = window.parseInt(old);
			style.height = x + 0.800 * (v - x) + 'px';
			/*如果和上一次左边的坐标相等则清除定时器*/
			if(style.height === old)window.clearInterval(si);
		}
		var si = window.setInterval(fx, 20);
	}
});

目录
相关文章
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(一)
深入JS面向对象(原型-继承)
31 0
|
1月前
|
JavaScript 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承利用原型链查找属性,节省内存但不支持私有成员。类继承通过ES6的class和extends实现,支持私有成员但占用更多内存。两者各有优势,适用于不同场景。
19 0
|
3月前
|
JavaScript
|
3月前
|
JavaScript 前端开发
原型继承在 JavaScript 中是如何工作
原型继承在 JavaScript 中是如何工作
20 0
|
1月前
|
设计模式 JavaScript 前端开发
JavaScript中继承的优缺点
JavaScript中继承的优缺点
13 3
|
1月前
|
JavaScript 前端开发
如何在 JavaScript 中实现继承?
如何在 JavaScript 中实现继承?
11 2
|
1月前
|
JavaScript 前端开发
js继承的超详细讲解:原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承、class继承
js继承的超详细讲解:原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承、class继承
54 0
|
2月前
|
前端开发 JavaScript 算法
在 JavaScript 中,有哪些方式可以达到继承的效果?
在 JavaScript 中,有哪些方式可以达到继承的效果?
30 0
|
3月前
|
JavaScript 前端开发
JS 常见的 6 种继承方式
JS 常见的 6 种继承方式
|
3月前
|
JavaScript 前端开发 Java
【面试常见】JS继承与原型、原型链
【面试常见】JS继承与原型、原型链