Coder Social home page Coder Social logo

alexuse's People

Contributors

geqianqian-shihan avatar

alexuse's Issues

node 相关

一、使用 node 简单搭建 web 静态服务器

//请求Node.js自带的http模块。 
const http = require('http');   
const fs = require('fs');
const mimeModel = require('./getMime');
const path = require('path');  // 加载path模块
const url = require('url');    // 加载url模块

var server = http.createServer(function(req, res){
    res.setHeader("Content-Type","text/html; charset=utf-8");  

    let pathName = url.parse(req.url).pathname; // 解析请求地址不带参数

    if (pathName == '/') {
        pathName = '/index.html';  // 如果请求地址为空,则加载首页
    }
  
    let extName = path.extname(pathName);   // 获取请求文件的后缀名

    if (pathName != '/favicon.ico') {  // 当不请求 页面图标时
        // Web 为静态资源文件夹
        fs.readFile('Web/' + pathName, (err, data) => {  // 读取对应文件
            if (err) {  // 如果没有找到文件
                res.write('404 !!!');	
            }else{
                let mime = mimeModel.getMime(extName);  // 根据对应的后缀名,获取对应的文件格式
                res.writeHead(200, {'Content-Type': ""+ mime + ";charset=utf-8'"});  // 设置请求状态及表头
                res.write(data);  // 读取数据
                res.end();   // 结束响应
            }
        })
    return false;
          
    }
	
});
 
//这个对象有个叫做listen的方法,这个方法可以有个数值参数。
//指定这个HTTP服务器监听的端口号。
//当我们打开http://localhost:8080的时候,服务器就会接收数据,并且响应数据
server.listen(9999);



// getMime.js
const getMime = (extname) => {
    switch (extname) {
        case '.html':
            return 'text/html';
        case '.css':
            return 'text/css';
        case '.js':
            return 'text/javascript';
        default:
            return 'text/html';
    }
}
module.exports = {
    getMime
}

多文件上传 jquery.MultiFile

jquery.MultiFile.min.js

visit the plugin's official website

$("#btnself").MultiFile({
                list: '#attachment',
                max: 5,
                accept: 'jpg|jpeg|bmp|png|gif|txt|rar|zip|doc|docx|ini|conf|eml|xlsx|pdf|7z|mp4|csv',
                max_size:'8388608',
                maxfile:'8388608',
                STRING: {
                    remove:' <a  href="#" class="$file">×</a>',
                    selected:'',
                    denied:'$exts 上传不被允许',
                    duplicate:'上传文件重复',
                    toomuch:'上传文件不得超过5个',
                    toobig:'文件过大',
                    toomany:'上传文件不得超过5个',
                    file: '<div class="paper uploaded_image"><img src="/assets/essmgr/images/upload.png" alt="$file">$file</div>'
                },
                onFileSelect: function(element, value, master_element) {
                // 清空 提示文字   tips 为自定义文字的类名
                    $('.tips').remove();
                }
            });
// 重置  
$('input:file').MultiFile('reset');

jQuery源码解析

原作者地址:慕课网
1、jQuery2.1.1版本的结构:

;(function(global, factory) {
    factory(global);
}(typeof window !== "undefined" ? window : this, function(window, noGlobal) {
    var jQuery = function( selector, context ) {
		return new jQuery.fn.init( selector, context );
	};
	jQuery.fn = jQuery.prototype = {};
	// 核心方法
	// 回调系统
	// 异步队列
	// 数据缓存
	// 队列操作
	// 选择器引
	// 属性操作
	// 节点遍历
	// 文档处理
	// 样式操作
	// 属性操作
	// 事件体系
	// AJAX交互
	// 动画引擎
	return jQuery;
}));

jQuery使用户能更方便地处理DOM、事件、实现动画效果,并且方便地为网站提供AJAX交互。

2、jQuery的模块依赖网:
image

jQuery一共13个模块,从2.1版开始jQuery支持通过AMD模块划分,jQuery在最开始发布的1.0版本是很简单的,只有CSS选择符、事件处理和AJAX交互3大块。其发展过程中,有几次重要的变革:

☑  1.2.3 版发布,引入数据缓存,解决循环引用与大数据保存的问题
☑  1.3 版发布,它使用了全新的选择符引擎Sizzle,在各个浏览器下全面超越其他同类型JavaScript框架的查询速度,程序库的性能也因此有了极大提升
☑  1.5 版发布,新增延缓对像(Deferred Objects),并用deferred重写了Ajax模块
☑  1.7 版发布,抽象出回调对象,提供了强大的的方式来管理回调函数列表。

每一次大的改进都引入了一些新的机制、新的特性,通过这些新的机制就造就了如今jQuery库,一共13个模块,模块不是单一的,比如jQuery动画,都会依赖异步队列、动画队列、回调队列与数据缓存模块等。

jQuery抽出了所有可复用的特性,分离出单一模块,通过组合的用法,不管在设计思路与实现手法上jQuery都是非常高明的。
遵守单一职责的好处是可以让我们很容易地来维护这个对象,比如,当一个对象封装了很多职责的时候,一旦一个职责需要修改,势必会影响该对象的其它职责代码。通过解耦可以让每个职责更加有弹性地变化。

我们来看看jQuery文档针对业务层的Ajax的处理提供了一系列的门面接口:
.ajaxComplete()
.ajaxError()
.ajaxSend()
.ajaxStart()
.ajaxStop()
.ajaxSuccess()

底层接口:
jQuery.ajax()
jQuery.ajaxSetup()

快捷方法:
jQuery.get()
jQuery.getJSON()
jQuery.getScript()
jQuery.post()

jQuery接口的设计原理

业务逻辑是复杂多变的,jQuery的高层API数量非常多,而且也非常的细致,这样做可以更友好的便于开发者的操作,不需要必须在一个接口上重载太多的动作。我们在深入内部看看Ajax的高层方法其实都是统一调用了一个静态的jQuery.ajax方法。

jQuery.each( [ "get", "post" ], function( i, method ) {
    jQuery[ method ] = function( url, data, callback, type ) {
		// Shift arguments if data argument was omitted
		if ( jQuery.isFunction( data ) ) {
			type     = type || callback;
			callback = data;
			data     = undefined;
		}
		return jQuery.ajax({
			url: url,
			type: method,
			dataType: type,
			data: data,
			success: callback
		});
	};
});

在jQuery.ajax的内部实现是非常复杂的,首先ajax要考虑异步的处理与回调的统一性,所以就引入了异步队列模块(Deferred)与回调模块(Callbacks), 所以要把这些模块方法在ajax方法内部再次封装成、构建出一个新的jQXHR对象,针对参数的默认处理,数据传输的格式化等等。

js 判断浏览器类型以及语言

1、检查是否是移动端(Mobile)、ipad、iphone、微信、QQ等

    //判断访问终端
        var browser={
          versions:function(){
            var u = navigator.userAgent
                return {
                  trident: u.indexOf('Trident') > -1, //IE内核
                  presto: u.indexOf('Presto') > -1, //opera内核
                  webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
                  gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1,//火狐内核
                  mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
                  ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
                  android: u.indexOf('Android') > -1 || u.indexOf('Adr') > -1, //android终端
                  iPhone: u.indexOf('iPhone') > -1 , //是否为iPhone或者QQHD浏览器
                  iPad: u.indexOf('iPad') > -1, //是否iPad
                  webApp: u.indexOf('Safari') == -1, //是否web应该程序,没有头部与底部
                  weixin: u.indexOf('MicroMessenger') > -1, //是否微信
                  qq: u.match(/\sQQ/i) == " qq" //是否QQ
                };
          }(),
          //语言
          language:(navigator.browserLanguage || navigator.language).toLowerCase();
    }

    // 判断是否IE内核 
    if(browser.versions.trident){ alert("is IE浏览器"); } 
        //判断是否webKit内核 
        if(browser.versions.webKit){ alert("is webKit内核浏览器"); } 
        //判断是否移动端 
        if(browser.versions.mobile||browser.versions.android||browser.versions.ios){ alert("移动端"); }
        //判断是否微信内置浏览器
        if(browser.versions.weixin){ alert("微信内置浏览器")}
        //判断是否QQ内置浏览器
        if(browser.versions.qq){ alert("qq内置浏览器")}
        //判断语言
        if(browser.language.indexOf('zh')>-1){
            alert('中文');
        }else if(browser.language.indexOf('en')>-1){
            alert('英文')
        }else{
            alert('其他语言')
        }

// 判断iPhone|iPad|iPod|iOS|Android客户端|PC端,分别跳转不同页面
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { //判断iPhone|iPad|iPod|iOS
  window.location.href ="iPhone.html";
}else if(/(Android)/i.test(navigator.userAgent)) {  //判断Android
  window.location.href ="Android.html";
}else{ //pc
  window.location.href ="pc.html";
};

// 判断是IOS还是Android客户端
if(navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)){
    alert("IOS");
}else if(navigator.userAgent.indexOf('Android') > -1 || navigator.userAgent.indexOf('Adr') > -1){
    alert("Android")
}

//判断PC端还是移动端
var isPc = function(){
  var userAgentInfo = navigator.userAgent.toLowerCase();
    var Agents = ["android", "iphone","symbianos", "windows phone","ipad", "ipod"];
    for (var v = 0; v < Agents.length; v++) {
        if (userAgentInfo.indexOf(Agents[v]) >= 0) {
             alert("移动端");
             return false;
        }
    }
    return true;
}

// 判断ie浏览器版本 
function IEVersion() {
    var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串  
    var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器  
    var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器  
    var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
    if(isIE) {
        var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
        reIE.test(userAgent);
        var fIEVersion = parseFloat(RegExp["$1"]);
        if(fIEVersion == 7) {
            return 7;
        } else if(fIEVersion == 8) {
            return 8;
        } else if(fIEVersion == 9) {
            return 9;
        } else if(fIEVersion == 10) {
            return 10;
        } else {
            return 6;//IE版本<=6
        }   
    } else if(isEdge) {
        return 'edge';//edge
    } else if(isIE11) {
        return 11; //IE11  
    }else{
        return -1;//不是ie浏览器
    }
}

post和get的区别?

原文地址

  1. get是从服务器上获取数据,post是向服务器传送数据。
  2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。
    post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。
  3. 对于get方式,服务器端用Request.QueryString获取变量的值,
    对于post方式,服务器端用Request.Form获取提交的数据。
  4. get传送的数据量较小,不能大于2KB。
    post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。
  5. get安全性非常低,post安全性较高。但是执行效率却比Post方法好。

建议:
1、get方式的安全性较Post方式要差些,包含机密信息的话,建议用Post数据提交方式;
2、在做数据查询时,建议用Get方式;而在做数据添加、修改或删除时,建议用Post方式;

vue+webpack打造todo应用

1、前端工程;
2、webpack;
3、vue;
4、优化配置达到上线标准;
前端价值:

  • 搭建前端工程;
  • 网络优化;
  • api定制;
  • nodejs;

重排和重绘

原文地址:
1、什么是重排和重绘
浏览器下载完页面中的所有组件——HTML标记、JavaScript、CSS、图片之后会解析生成两个内部数据结构——DOM树和渲染树。

  • DOM树表示页面结构,渲染树表示DOM节点如何显示。
  • DOM树中的每一个需要显示的节点在渲染树种至少存在一个对应的节点(隐藏的DOM元素disply值为none 在渲染树中没有对应的节点)。
  • 渲染树中的节点被称为“帧”或“盒",符合CSS模型的定义,理解页面元素为一个具有填充,边距,边框和位置的盒子。一旦DOM和渲染树构建完成,浏览器就开始显示(绘制)页面元素。

当DOM的变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会因此受到影响。
浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。
完成重排后,浏览器会重新绘制受影响的部分到屏幕,该过程称为重绘。
由于浏览器的流布局,对渲染树的计算通常只需要遍历一次就可以完成。但table及其内部元素除外,它可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。这也是为什么我们要避免使用table做布局的一个原因。

2、重排何时发生

  • 1、添加或者删除可见的DOM元素
  • 2、元素位置改变
  • 3、元素尺寸改变
  • 4、元素内容改变(例如:一个文本被另一个不同尺寸的图片替代)
  • 5、页面渲染初始化(这个无法避免)
  • 6、浏览器窗口尺寸改变

3、渲染树变化的排队和刷新

var ele = document.getElementById('myDiv');
ele.style.borderLeft = '1px';
ele.style.borderRight = '2px';
ele.style.padding = '5px';

浏览器会把三次修改“保存”起来(大多数浏览器通过队列化修改并批量执行来优化重排过程),一次完成!

获取布局信息的操作会导致队列刷新:

  • 1.offsetTop, offsetLeft, offsetWidth, offsetHeight
  • 2.scrollTop, scrollLeft, scrollWidth, scrollHeight
  • 3.clientTop, clientLeft, clientWidth, clientHeight
  • 4.getComputedStyle() (currentStyle in IE)

4、最小化重排和重绘
三个样式属性被改变,每一个都会影响元素的几何结构,虽然大部分现代浏览器都做了优化,只会引起一次重排,但是像上文一样,如果一个及时的属性被请求,那么就会强制刷新队列,而且这段代码四次访问DOM,一个很显然的优化策略就是把它们的操作合成一次,这样只会修改DOM一次:

var ele = document.getElementById('myDiv');
 // 1. 重写style
ele.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;'; 
// 2. add style
ele.style.cssText += 'border-;eft: 1px;'
 // 3. use class
ele.className = 'active';

5、fragment元素的应用

<ul id='fruit'>
 <li> apple </li>
 <li> orange </li>
</ul>
var lis = document.getElementById('fruit');
var li = document.createElement('li');
li.innerHTML = 'apple';
lis.appendChild(li);
 
var li = document.createElement('li');
li.innerHTML = 'watermelon';
lis.appendChild(li);

重排了两次,怎么破?前面我们说了,隐藏的元素不在渲染树中,太棒了,我们可以先把id为fruit的ul元素隐藏(display=none),然后添加li元素,最后再显示,但是实际操作中可能会出现闪动,原因这也很容易理解。这时,fragment元素就有了用武之地了。

var fragment = document.createDocumentFragment();
 
var li = document.createElement('li');
li.innerHTML = 'apple';
fragment.appendChild(li);
 
var li = document.createElement('li');
li.innerHTML = 'watermelon';
fragment.appendChild(li);
 
document.getElementById('fruit').appendChild(fragment);

文档片段是个轻量级的document对象,它的设计初衷就是为了完成这类任务——更新和移动节点。文档片段的一个便利的语法特性是当你附加一个片断到节点时,实际上被添加的是该片断的子节点,而不是片断本身。只触发了一次重排,而且只访问了一次实时的DOM。

6、让元素脱离动画流
用展开/折叠的方式来显示和隐藏部分页面是一种常见的交互模式。它通常包括展开区域的几何动画,并将页面其他部分推向下方。
一般来说,重排只影响渲染树中的一小部分,但也可能影响很大的部分,甚至整个渲染树。浏览器所需要重排的次数越少,应用程序的响应速度就越快。因此当页面顶部的一个动画推移页面整个余下的部分时,会导致一次代价昂贵的大规模重排,让用户感到页面一顿一顿的。渲染树中需要重新计算的节点越多,情况就会越糟。

使用以下步骤可以避免页面中的大部分重排:

使用绝对位置定位页面上的动画元素,将其脱离文档流
让元素动起来。当它扩大时,会临时覆盖部分页面。但这只是页面一个小区域的重绘过程,不会产生重排并重绘页面的大部分内容。
当动画结束时恢复定位,从而只会下移一次文档的其他元素

总结
重排和重绘是DOM编程中耗能的主要原因之一,平时涉及DOM编程时可以参考以下几点:

  • 尽量不要在布局信息改变时做查询(会导致渲染队列强制刷新)
  • 同一个DOM的多个属性改变可以写在一起(减少DOM访问,同时把强制渲染队列刷新的风险降为0)
  • 如果要批量添加DOM,可以先让元素脱离文档流,操作完后再带入文档流,这样只会触发一次重排(fragment元素的应用)
  • 将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。

时间复杂度和空间复杂度

原文地址:https://blog.csdn.net/booirror

算法的时间复杂度和空间复杂度合称为算法的复杂度;

一、时间复杂度
(1)时间频度 一个算法执行所消耗的时间;理论上上机运行测试才能得到结果。但是我们只需知道算法花费时间多少即可; 算法花费时间与算法中语句的执行次数成正比;一个算法的语句执行次数成为语句频度或时间频度。T(n).
(2)时间复杂度 n为问题的规模,n变化时T(n)随之变化,变化时的规律引入时间复杂度;某个辅助函数f(n)使得当n趋近于无穷大时,T(n)/f(n) 的极限值为不等于零的常数,则f(n) 是T(n)的同数量级函数,T(n)=O(f(n))为算法的渐进时间复杂度,简称时间复杂度。
时间频度不同,但时间复杂度可能相同。如:T(n)=n2+3n+4与T(n)=4n2+2n+1它们的频度不同,但时间复杂度相同,都为O(n2)。
按数量级递增排列,常见的时间复杂度有:常数阶O(1),对数阶O(log2n),线性阶O(n), 线性对数阶O(nlog2n),平方阶O(n2),立方阶O(n3),..., k次方阶O(nk),指数阶O(2n)。随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低。
(3)最坏时间复杂度和平均时间复杂度  最坏情况下的时间复杂度称最坏时间复杂度。一般不特别说明,讨论的时间复杂度均是最坏情况下的时间复杂度。 这样做的原因是:最坏情况下的时间复杂度是算法在任何输入实例上运行时间的上界,这就保证了算法的运行时间不会比任何更长。
在最坏情况下的时间复杂度为T(n)=0(n),它表示对于任何输入实例,该算法的运行时间不可能大于0(n)。 平均时间复杂度是指所有可能的输入实例均以等概率出现的情况下,算法的期望运行时间。
指数阶0(2n),显然,时间复杂度为指数阶0(2n)的算法效率极低,当n值稍大时就无法应用。
(4)求时间复杂度
【1】如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。
x=91; y=100;
while(y>0) if(x>100) {x=x-10;y--;} else x++;
解答: T(n)=O(1),
这个程序看起来有点吓人,总共循环运行了1100次,但是我们看到n没有?
没。这段程序的运行是和n无关的,
就算它再循环一万年,我们也不管他,只是一个常数阶的函数

【2】当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。
x=1;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
for(k=1;k<=j;k++)
x++;   
该程序段中频度最大的语句是(5),内循环的执行次数虽然与问题规模n没有直接关系,但是却与外层循环的变量取值有关,而最外层循环的次数直接与n有关,因此可以从内层循环向外层分析语句(5)的执行次数: 则该程序段的时间复杂度为T(n)=O(n3/6+低次项)=O(n3)

【3】算法的时间复杂度不仅仅依赖于问题的规模,还与输入实例的初始状态有关。
在数值A[0..n-1]中查找给定值K的算法大致如下:
i=n-1;
while(i>=0&&(A[i]!=k))
i--;
return i;
此算法中的语句(3)的频度不仅与问题规模n有关,还与输入实例中A的各元素取值及K的取值有关: ①若A中没有与K相等的元素,则语句(3)的频度f(n)=n; ②若A的最后一个元素等于K,则语句(3)的频度f(n)是常数0。
(5)时间复杂度评价性能
有两个算法A1和A2求解同一问题,时间复杂度分别是T1(n)=100n2,T2(n)=5n3。(1)当输入量n<20时,有T1(n)>T2(n),后者花费的时间较少。(2)随着问题规模n的增大,两个算法的时间开销之比5n3/100n2=n/20亦随着增大。即当问题规模较大时,算法A1比算法A2要有效地多。它们的渐近时间复杂度O(n2)和O(n3)从宏观上评价了这两个算法在时间方面的质量。在算法分析时,往往对算法的时间复杂度和渐近时间复杂度不予区分,而经常是将渐近时间复杂度T(n)=O(f(n))简称为时间复杂度,其中的f(n)一般是算法中频度最大的语句频度。

2.空间复杂度
一个程序的空间复杂度是指运行完一个程序所需内存的大小。利用程序的空间复杂度,可以对程序的运行所需要的内存多少有个预先估计。一个程序执行时除了需要存储空间和存储本身所使用的指令、常数、变量和输入数据外,还需要一些对数据进行操作的工作单元和存储一些为现实计算所需信息的辅助空间。程序执行时所需存储空间包括以下两部分。  
(1)固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括指令空间(即代码空间)、数据空间(常量、简单变量)等所占的空间。这部分属于静态空间。
(2)可变空间,这部分空间的主要包括动态分配的空间,以及递归栈所需的空间等。这部分的空间大小与算法有关。
一个算法所需的存储空间用f(n)表示。S(n)=O(f(n))  其中n为问题的规模,S(n)表示空间复杂度。

layui 使用遇到的问题

table reload会刷新toolbar里的组件

layui table的toobar和在table reload后 输入框的数据会被清空,button的事件如果只自己用js定义的事件也会被取消 两种解决办法

1、不用toobar 。直接新做一个div 就可以了。

2、用toobar 按钮 事件table.on('toolbar(customTable)', function(obj){};

css 样式问题

一、子元素浮动 父元素高度为0怎么解决

1、给父元素 加一个overflow:hidden;
2、将父元素也一起浮动(这个比较复杂,会影响到父元素的同级元素);
3、在父元素的最后一个子元素 后边再增加多一个非浮动的子元素,然后将这个子元素加个clear(例:<div style="clear:both">)
4、 使用after伪类 #box:after{ content:"."; height:0; visibility:hidden; display:block; clear:both; }

Web高效编程与优化

高效前端:Web高效编程与优化实践

-1

Effective前端1:能用HTML/CSS 解决的问题就不要用JS 2
Effective前端2:优化HTML标签 16
Effective前端3:用CSS画一个三角形 22
Effective前端4:尽可能地使用伪元素 28
第2章 JS优化 34
Effective前端5:减少前端代码耦合 34
Effective前端6:JS书写优化 47
第3章 页面优化 59
Effective前端7:避免页面卡顿 59
Effective前端8:加快页面打开速度 67
Effective前端9:增强用户体验 85
Effective前端10:用好Chrome Devtools 91
第4章 HTML5优化实践 109
Effective前端11:使用H5的history改善AJAX列表请求体验 109
Effective前端12:使用图标替代雪碧图 118
Effective前端13:理解和使用CSS3动画 128
Effective前端14:实现前端裁剪压缩图片 136
Effective前端15:实现跨浏览器的HTML5表单验证 145
Effective前端16:使用Service Worker做一个PWA离线网页应用 151
第5章 前端与计算机基础 164
Effective前端17:理解WebSocket和TCP/IP 164
Effective前端18:理解HTTPS连接的前几毫秒发生了什么 185
Effective前端19:弄懂为什么0.1 0.2不等于0.3 203
Effective前端20:明白WebAssembly与程序编译 209
Effective前端21:理解JS与多线程 221
Effective前端22:学会JS与面向对象 231
Effective前端23:了解SQL 248
Effective前端24:学习常用的前端算法与数据结构 266
第6章 掌握前端基础 291
Effective前端25:掌握同源策略和跨域 291
Effective前端26:掌握前端本地文件操作与上传 299
Effective前端27:学会常用的CSS居中方式 310
Effective前端28:学会常用的CSS布局技术 320
Effective前端29:理解字号与行高 327
Effective前端30:使用响应式开发 336
Effective前端31:明白移动端click及自定义事件 344
Effective前端32:学习JS高级技巧 355
第7章 运用恰当的工具 372
Effective前端33:前端的单元测试与自动化测试 372
Effective前端34:使用AE bodymovin制作网页动画 390

关于重构

卫语句

//  普通格式
      if (true){
            if (true){
                if (true){
                    for (){
                        if (true){
                            业务代码
                        }
                    }
                }
            }
        }

// 卫语句
        if (false){

        }
        if (false){

        }
        if (false){

        }
        for (){
            if (false){
                continue;
            }
            业务代码
        }

这是其中一类,可以将失败前置。只要有一个条件不通过,就快速返回失败,如果到了最后一行,说明所有判断都通过,剩下的就是你预期的结果。而不是一直查成功。

从浏览器输入网址到页面展示完成发生了什么

DNS (Domain Name System) 域名解析

  • 作为将域名和IP地址相互映射的一个分布式数据库
  • 使用 TCP 和 UDP 端口
  • 每一级 63 字符,全长最长 263 字符;

域名的域名解析过程

  1. 第一步:请求,并将该请求发送给本地的域名服务器(首选域名服务器)。
  2. 第二步:请求后查询_本地资源记录_,没有权威回答则查询_本地的缓存_,如果有该纪录项,则本地的域名服务器就直接把查询的结果返回。
  3. 第三步:如果本地的缓存中没有该纪录,则本地域名服务器就直接把请求发给根域名服务器,然后根域名服务器再返回给本地域名服务器一个所查询域(根的子域)的主域名服务器(顶级域名服务器)的地址。
  4. 第四步:本地服务器再向上一步返回的域名服务器发送请求,然后接受请求的服务器查询自己的缓存,如果没有该纪录,则返回相关的下级的域名服务器的地址。
  5. 第五步:重复第四步,直到找到正确的纪录。
  6. 第六步:本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时还将结果返回给客户机。

js高级(第三版)

引用类型

对象字面量也是向函数传递大量可选参数的首选方式。必须值使用命名参数。

function displayInfo(args){
    var output  = "";
    // typeof 检测每个属性是否存在
    if(typeof args.name == "string"){
        output += "Name: " + args.name + "\n";
    }
}

方括号:1、可以通过变量来访问属性;2、属性名导致语法错误的字符或者使用关键字或保留字。ps:一般使用点语法。

Array

数组最多可以包含 4 294 967 295个项,创建初始大小与这个上限值相近的数组时,可能导致运行时间超长的脚本错误。

// 数组最后一项后加逗号, IE8 及之前的版本 会包含三项,第三项undefined;
// 与对象一样,在使用数组字面量表示法时,不会调用Array构造函数(FF3 及更早版本除外)
var values = [1,3,,]

1、数组的length 不是只读,可以用于在数组末尾移除或向数组添加新项;

var colors = ["red","green"];
colors.length = 4;
colors[colors.length] = "black";
//colors = ["red", "green", empty × 2, "black"]

2、检测数组

//Safari 4版及之前,对正则表达式应用 typeof 返回“function”
//对与一个网页或者一个全局作用域而言:instance
    //Douglas Crockford的JSON库,定义了一个全局JSON对象,
if(value instance Array){}
//ECMAscript 5 新增 Array.isArray();
if(Array.isArray(value)){}
//不支持Array.isArray()
    //原生函数  "[ object Function]"
    //正则表达式 "[object RegExp]"
    //数组  "[object Array]"
if(Object.prototype.toString.call(value))   

3、栈方法
push(任意数量参数) 返回新的长度 和 pop(最后一项)返回删除的项

4、队列方法
shift()删除第一项 并返回删除的项 unshift(任意数量参数) 返回新数组长度

5、重排方法

  • reverse() 反转数组的顺序;返回数组;数组改变
  • sort(比较函数) 调用每一项的toString,比较字符串;返回数组;数组改变
  • 比较函数 返回1 ,第一个值位于第二个值之后,-1则之前,0无变化;
function(value1,value2){
    return value2 - value1;
}

6、操作方法

  • concat()

创建新数组(当前数组的副本,接受到的参数添加到新数组末尾);参数为一个或多个数组时,将这些数组中的每一项添加到结果数组中,参数不是数组时,添加到结果数组的末尾。原数组无变化

let colors1 = ["red","green"];
let colors2 = colors1.concat("yellow",["black","brown"]);
let colors3 = colors1.concat({"name":"alex"});
//colors1    ["red", "green"]
//colors2   ["red", "green", "yellow", "black", "brown"]
//colors3   ["red", "green", {"name":"alex"}]
  • slice(起始位置,要删除的项数,要插入的任意数量的项)
    slice()方法中有负数时,则用数组长度减去该数来确定相应的位置。结束位置小于起始位置,返回空数组。
    返回从原始数组中删除的项,没有删除则返回空数组;原数组改变;

------------ECMAScript5------------
7、位置方法
indexOf([要查找的项],查找起点位置索引) lastIndexOf([要查找的项],查找起点位置索引) 返回查找项在数组中的位置。全等比较

var number = [1,2,3,4,5,4,3,2,1];
number.indexOf(4); //3
number.lastIndexOf(4);//5
number.indexOf(4,4);//5
number.lastIndexOf(4,4);//3
var person = {"name":"alex"};
var people = [{"name":"alex"}];
var morepeople = [person];
console.log(people.indexOf(person)) //-1
console.log(morepeople.indexOf(person)) //0

8、迭代方法
原数组不变
两个参数:要在每一项上运行的函数,运行该函数的作用域对象--影响this值;
函数接受三个参数:数组项的值,该项在数组中的位置,数组对象本身;

  • every():数组中每一项运行给定函数,全部返回true,则结果为true;
  • filter():数组中每一项运行给定函数,返回函数会返回true 的项组成的数组;
  • forEach():数组中每一项运行给定函数,没有返回值
  • map():数组中每一项运行给定函数,返回每次函数调用的结果组成的数组;
  • some():数组中每一项运行给定函数,该函数任意一项返回true则结果为true;

9、归并方法
迭代数组中所有项,构建一个最终返回值;
两个参数:每一项上调用的函数(可选),归并处理的初始值;
函数四个参数:前一个值(计算后返回值),当前值,项的索引,数组对象;
reduce() reduceRight()

Date

Date类型是在早期Java中的java.util.Data类基础上构建的。Date类型使用自UTC(国际协调时间)1970年1月1日零时,开始经过的毫秒值保存日期;
Date.UTC(年,基于数字零的月份,[月中的那一天(默认1),小时数,分钟,秒,毫秒])
Date.parse()
"月/日/年";"英文月名 日,年";"英文星期几 英文月名 日 年 时:分:秒 时区";
--------ECMAScript 5---------
YYYY-MM-DDTHH:mm:ss.ssZ
Date.now() 调用该方法时日期和时间的毫秒数;

1、继承方法
toLocaleString() 浏览器设置的地区相适应的格式返回日期和时间
toString()带有时区信息(小时从0 开始)
valueOf()返回日期的毫秒数,用于比较日期值。getTime();

var date1 = new Date(2001,0,1);
var date2 = new Date(2001,1,1);
console.log(date1>date2);

2、日期格式化方法

var date1 = new Date(2001,0,1);
date1.toDateString()
    //"Mon Jan 01 2001"
date1.toTimeString()
    //"00:00:00 GMT+0800 (CST)"
date1.toLocaleDateString()
    //"2001/1/1"
date1.toLocaleTimeString()
    //"上午12:00:00"
date1.toUTCString()
    //"Sun, 31 Dec 2000 16:00:00 GMT"

3、getFullYear(),4位数年份

RegExp

var reg = /pattern/flags
//pattern
//flags
    //g:全局模式,所有字符串,发现并匹配第一项是立即停止
    //i:不区分大小写,
    //m:多行模式,
//元字符必须转义:()[]{}\^$|?*+.

//构造函数
var reg1 = new RegExp("[bc]at","i");  //需要双重转义

------ECMAScript 5 ----------
使用正则表达式字面量必须像直接调用RegExp构造函数一样,每次创建新的RegExp实例;

4、RegExp实例属性
global:g标志
ignoreCase:标志
lastIndex:下一个匹配项的字符位置,默认0
multiline:m标志
source:字面量形式返回正则表达式

5、RegExp实例方法

  • exec(要应用模式的字符串)返回包含第一个匹配项信息的数组,没有匹配项返回null;

    数组包含:index(匹配项在字符串中的位置),input:应用正则表达式的字符串
    lastIndex 在全局匹配模式下,lastIndex 值在每次调用exec都会增加,非全局模式下保持不变;IE 即使在非全局模式下也会变化。

  • test 接受字符串参数,模式匹配时返回true,否则false;

Function

函数实际是对象,每个函数都是Function类型的实例,拥有属性和方法,函数名是指向函数对象的指针,不与某个函数绑定。
函数通常是使用函数声明语法定义的。
函数末尾有分号;
Function 函数可以接受任意数量的参数,最后一个参数始终都被看做函数体,其他参数枚举了新函数的参数。

  • 解析两次代码,1、解析常规ECMAScript代码,2、解析传入构造函数的参数字符串。影响性能。
function sum(num1,num2){
    return num1+num2;
}
console.log(sum(10,10));     //20
let aSum = sum;
console.log(aSum(10,10));    //20
sum = null;
    //sum 与函数“断绝关系”
console.log(aSum(10,10));    //20

1、没有重载
函数名是指针,因此函数只有覆盖。

2、函数声明与表达式

  • 解析器会率先读取函数声明,并使其在执行任何代码时可用。函数声明提升
  • 函数表达式必须等到解析器执行到该语句所在的代码行,才会真的被执行。
console(sum(10,10));
var sum = function(num1,num2){
    return num1+num2;
}
//函数位于初始化语句中,并非函数声明,

3、函数本身就是变量,函数页可以作为值来使用。函数作为参数,函数作为返回值均可。

  • 要访问函数的指针,必须去掉函数后的圆括号。
function com(name){
    return function(obj1,obj2){
        var val1 = obj1[name];
        var val2 = obj2[name];
        if(val1 < val2){
            return -1;
        }else if(val1 > val2){
            return 1;
        }else{
            return 0;
        }
    }
}
var data = [{"name":"zaza","age":"12"},{"name":"red","age":"14"}];
data.sort(com("name"));
console.log(data);    //[{"name":"red","age":"14"},{"name":"zaza","age":"12"}];

4、函数内部属性

  • arguments:保存函数参数
  • callee:一个指针,指向拥有arguments对象的函数。
  • this:函数执行时的环境对象。
function factorial(num){
    if(num<=1){
        return 1; 
    }else{
        //函数名不变的请款下可以写 num*factorial(num - 1);callee 消除耦合。无论引用函数时使用的什么名字 都可以正确完成递归调用。 
        return num*arguments.callee(num-1);
    }
}
//this 
window.color="red";
var o = {"color":"blue"};
function sayColor(){
    console.log(this.color);
}
sayColor();    //"red"
o.sayColor= sayColor;
o.sayColor();    //"blue"

----------ECMAScript 5----------
caller:调用当前函数的引用,如果全局作用域中调用当前函数,返回null;

function outer(){
    inner();
}
function inner(){
    console.log(arguments.callee.caller);
}
outer();
    /*严格模式下
    1、arguments.callee 报错;arguments.caller报错;
    2、非严格模式 undefined,为了分清arguments.caller 和函数 caller;
     以上都是为了加强安全性,第三方代码不能在相同的环境窥视其他代码!
    3、不能为函数的caller属性赋值,否则报错。
    */

5、函数属性和方法
属性:length(函数希望接受的参数的个数);prototype(对于引用类型,prototype保存它们所有实例方法)(ECMAScript5中,prototype不可枚举,for-in无法发现);
方法:
非继承的方法:call(),apply()用于在特定的作用域中调用函数。等价于设置函数体的this对象的值。
扩充函数赖以运行的作用域。有点对象不需要与方法有任何耦合关系。

bind()this值会被绑定到传给bind函数的值。

function sum(num1,num2){
    return num1 + num2;
};
function callsum1(num1,num2){
    return sum.apply(this,arguments)
};
function callsum2(num1,num2){
      return sum.apply(this,[num1,num2])
};
//全局调用 this 为 window
//严格模式下,未指定环境对象,this不会转型为window,而是undefined。除非明确把函数添加到某个对象或者调用call(),apply();
console.log(callsum1(10,12));    //22
console.log(callsum2(10,12));    //22

//call 参数与 apply 参数不同。call 参数需要全部枚举。
window.color="red";
var o = {"color":"blue"};
function sayColor(){
    console.log(this.color);
}
var bindColor = sayColor.bind(o);
bindColor();    //"blue"

serializeArr 转为 serializeJson

$.fn.serializeJson = function() {
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};

js

javascript 数组以及对象的深拷贝

原作者地址:javascript 数组以及对象的深拷贝(复制数组或复制对象)的方法

var arr = [1,2,3,4,5]
var arr2 = arr;
arr[2] = 5;
console.log(arr);    //[1, 2, 5, 4, 5]
console.log(arr2);    //[1, 2, 5, 4, 5]

在js中,数组和对象的复制如果使用 = 号来进行复制,那只是浅拷贝。

arr 指针及 arr2 指针同时指向同一个空间

  • 数组的深拷贝

1、for 循环实现数组的深拷贝

var arr = [1,2,3,4,5]
var arr2 = copyArr(arr)
function copyArr(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
     res.push(arr[i])
    }
    return res
}

2、slice 方法实现数组的深拷贝: 将原数组中抽离部分出来形成一个新数组;

var arr = [1,2,3,4,5]
var arr2 = arr.slice(0)
arr[2] = 5
console.log(arr)
console.log(arr2)

3、concat 方法实现数组的深拷贝: 用于连接多个数组组成一个新的数组的方法。那么,我们只要连接它自己,即可完成数组的深拷贝。

var arr = [1,2,3,4,5]
var arr2 = arr.concat(0)
arr[2] = 5
console.log(arr)
console.log(arr2)

4、ES6扩展运算符实现数组的深拷贝

var arr = [1,2,3,4,5]
var [ ...arr2 ] = arr
arr[2] = 5
console.log(arr)
console.log(arr2)
  • 对象的深拷贝

1、for 循环实现对象的深拷贝

var obj = {
  name: 'FungLeo',
  sex: 'man',
  old: '18'
}
var obj2 = copyObj(obj)
function copyObj(obj) {
  let res = {}
  for (var key in obj) {
    res[key] = obj[key]
  }
  return res
}

2、转换成json再转换成对象实现对象的深拷贝

var obj = {
  name: 'FungLeo',
  sex: 'man',
  old: '18'
}
var obj2 = JSON.parse(JSON.stringify(obj));

3、扩展运算符实现对象的深拷贝

var obj = {
  name: 'FungLeo',
  sex: 'man',
  old: '18'
}
var { ...obj2 } = obj
obj.old = '22'
console.log(obj)
console.log(obj2)

ES6数组去重的方法

function dedupe(array) {
  return [...new Set(array)]
}
var arr = [1,2,2,3,3,4,4,5,5]
console.log(dedupe(arr));

常用正则

去掉空格

    str = str.replace(/\s*/g,"");    // 去除字符串内所有的空格
    str = str.replace(/^\s*|\s*$/g,"");    // 去除字符串内两头的空格
    str = str.replace(/^\s*/,"");    // 去除字符串内左侧的空格
    str = str.replace(/(\s*$)/g,"");    // 去除字符串内右侧的空格 

jquery 学习之路之$.fn,$.fx

$.fn是指jquery的命名空间,加上fn上的方法及属性,会对jquery实例每一个有效。

$.fx是指jquery的特效。如使用显示、滑动、淡入淡出、动画等。

$.fx.off可以关闭动画,其实是直接显示结果。

jquery的extend和fn.extend

jQuery为开发插件提拱了两个方法,分别是:

jQuery.fn.extend(object);

jQuery.extend(object);

jQuery.extend(object); 为扩展jQuery类本身.为类添加新的方法。

jQuery.fn.extend(object);给jQuery对象添加方法。

fn 是什么东西呢。查看jQuery代码,就不难发现。

jQuery.fn = jQuery.prototype = {

   init: function( selector, context ) {//…. 

   //……

};

原来 jQuery.fn = jQuery.prototype.对prototype肯定不会陌生啦。

虽然 javascript 没有明确的类的概念,但是用类来理解它,会更方便。

jQuery便是一个封装得非常好的类,比如我们用 语句 $(“#btn1″) 会生成一个 jQuery类的实例。

jQuery.extend(object); 为jQuery类添加添加类方法,可以理解为添加静态方法。如:
$.extend({
  add:function(a,b){return a+b;}
});
便为 jQuery 添加一个为 add 的 “静态方法”,之后便可以在引入 jQuery 的地方,使用这个方法了,

$.add(3,4); //return 7

jQuery.fn.extend(object); 对jQuery.prototype进得扩展,就是为jQuery类添加“成员函数”。jQuery类的实例可以使用这个“成员函数”。

比如我们要开发一个插件,做一个特殊的编辑框,当它被点击时,便alert 当前编辑框里的内容。可以这么做:
$.fn.extend({
alertWhileClick:function(){
$(this).click(function(){
alert($(this).val());
});
}
});
$("#input1").alertWhileClick();

//页面上为:

$(“#input1″) 为一个jQuery实例,当它调用成员方法 alertWhileClick后,便实现了扩展,每次被点击时它会先弹出目前编辑里的内容。

真实的开发过程中,当然不会做这么小白的插件,事实上jQuery提拱了丰富的操作文档,事件,CSS ,Ajax、效果的方法,结合这些方法,便可以开发出更加 Niubility 的插件。

jquery(function(){})与(function(){}(jQuery)的区别

1.first

jQuery(function(){});

全写为

jQuery(docunemt).ready(function(){

});

意义为在DOM加载完毕后执行ready()方法

(funtion(){

}(jQuery);

实际执行()(para)匿名方法,只不过传递了jQuery对象。

总结:jQuery(funtion(){});用于存放DOM对象的代码,执行其中代码时DOM对象已经存在。

不可用于存放开发插件代码。因为jQuery对象没有得到传递,外部通过jQuery.methodye

调用不来其中方法。

(funtion(){

}(jQuery);

用于存放开发插件的代码,执行其中代码DOM不一定存在,直接自动执行DOM操作代码请小心使用

原文地址 jQuery的$.fn使用

TCP/IP

参考地址:一篇文章带你熟悉 TCP/IP 协议

计算机网络体系结构分层

TCP/IP 与 OSI 在分层模块上稍有区别。OSI 参考模型注重“通信协议必要的功能是什么”,而 TCP/IP 则更强调“在计算机上实现协议应该开发哪种程序”。

OSI七层 TCP/IP概念层模型 功能 TCP/IP协议族
应用层 应用层 文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telent
表示层 数据格式化,数据加密,代码转换 没有协议
会话层 建立或接触与别的接点的联系 没有协议
传输层 传输层 提供端对端接口 TCP,UDP
网络层 网络层 为数据包选择路由 IP,ICMP,RIP,OSPF,BGP,IGMP
会话层 链路层 传输有地址的帧,及错误检测功能 SLIP,SCLIP,PPP,ARP,RARP,MTU
数据链路层 以二进制数据形式在屋里媒体上传输 ISO2110,IEEE802,IEEE802.2

隐藏 表单记录 多选框选中

html 隐藏表单

<input id="checkedIds" type="hidden">
// js 相关事件
.on('click','#id_table .chk',function(){
                    var $this = $(this),
                        $table = $('#id_table'),
                        $checkedIds = $('#checkedIds');
                        sts = $this.is(':checked') ? true : false,
                        isChkAll = $this.hasClass('chk_all'),
                        checkedIds = $checkedIds.attr('data-chk'),
                        chkIdsArr = (checkedIds && checkedIds.split(',')) || []
                    if(isChkAll){
                        $('#id_table .chk:not(.chk_all)').each(function (i,k) {
                            var $this_chkbox = $(this),
                                this_chk_id = $this_chkbox.val()
                                this_chk_sts = $this_chkbox.is(':checked'),
                                isInArr = $.inArray(this_chk_id,chkIdsArr);     // 没有在数组中返回 -1
                            if(sts && !this_chk_sts && -1 == isInArr){
                                chkIdsArr.push(this_chk_id);
                            }else if(!sts && this_chk_sts && -1 !== isInArr){
                                chkIdsArr.splice(isInArr,1);
                            }
                            $this_chkbox.prop("checked", sts);
                        });
                    }else{
                        var id = $this.val();
                        var chk_len = $('#id_table').find('.chk:not(.chk_all):checked').length;
                        if(sts){
                            var table_len = $('#id_table tbody').find('tr').length;
                            chkIdsArr.push(id);
                            if(chk_len == table_len){
                                $('#id_table .chk_all').prop("checked", true);
                            }
                        }else{
                            chkIdsArr.splice($.inArray(id,chkIdsArr),1);
                            if(1 > chk_len){
                                $('#id_table .chk_all').prop("checked", false);
                            }
                        }
                    }
                    $checkedIds.attr('data-chk',chkIdsArr.join());
                })

GIT

如何恢复丢弃的 git stash 数据

git fsck --unreachable

// git -fsck  验证数据库中对象的连接和有效性
//  --unreachable    显示出所有不可访问的对象
// git   show   SHA1    查看内容(vscode  直接 ctrl + 单击 查看)

然后三种处理方式
// 一、将此 ID 取出来放进一个新的分支,
// 二、直接提交它
git stash apply  SHA1
// 三、更改再次恢复应用到主分支上



微信小程序

原作者地址:微信小程序-template模板使用

模板

一、定义模板
1、新建一个template文件夹用来管理项目中所有的模板;
2、新建一个courseList.wxml文件来定义模板;
3、使用name属性,作为模板的名字。然后在内定义代码片段。

注意:
a.可以看到一个.wxml文件中可以定义多个模板,只需要通过name来区分;
b.模板中的数据都是展开之后的属性。

二、使用模板
1、使用 is 属性,声明需要的使用的模板。

<import src="../../templates/courseList.wxml"/>

2、将模板所需要的 data 传入,一般我们都会使用列表渲染。

<block wx:for="{{courseList}}">
    <template is="{{index%2 === 0 ? 'courseLeft' : 'courseRight'}}" data="{{...item}}"></template>
</block>

注意:
a.可以通过表达式来确定使用哪个模板is="{{index%2 === 0 ? 'courseLeft' : 'courseRight'}}"
或者通过wx:if来确定。index是数组当前项的下标。

<template wx:if="{{index%2 === 0}}" is="courseLeft" data="{{...item}}"></template>
<template wx:else is="courseRight" data="{{...item}}"></template>

b. data 是要模板渲染的数据,data="{{...item}}" 写法是ES6的写法,item是wx:for当前项,... 是展开运算符,在模板中不需要再{{item.courseName}} 而是直接{{courseName}} 。

三、模板样式
1、在新建模板的时候同时新建一个courseList.wxss 的文件,与CSS同样的写法控制样式。
2、在需要使用模板的页面 .wxss文件中import进来;或者直接在app.wxss中引入,这样只需要一次引入,其他文件就不用引入了。

@import "../template/courseList.wxss";

模板添加事件
temp.js

var temp = {
  gotoDetail: function (e) {
    let dataName = e.currentTarget.dataset.gid;
    console.log("刚刚您点击了temp,id为:" + dataName);
    wx.navigateTo({
      url: '../eventDetails/eventDetails',
    })
  }
}
export default temp

使用模板 index.js

import tempObj from '../common/temp.js';

onLoad: function (options) {
    let that = this;
    that["gotoDetail"] = tempObj.gotoDetail;
  }

设计模式

责任链模式

原文地址:[设计模式] javascript 之 责任链模式

function Handler() {
            this.next = null;
            this.setNext = function (_handler) {
                this.next = _handler;
            };

            this.handleRequest = function (money) {

            }
        };
        var CGBHandler = function () {};
        CGBHandler.prototype = new Handler();
        CGBHandler.prototype.handleRequest = function (money) {
            console.log('采购部');
            //处理权限最多10000
            if (money < 10000) {
                console.log('同意');
            } else {
                console.log('金额太大,只能处理一万以内的采购');
                if (this.next) {
                    this.next.handleRequest(money);
                }
            }
        };
        var ZJLHandler = function () {};
        ZJLHandler.prototype = new Handler();
        ZJLHandler.prototype.handleRequest = function (money) {
            console.log('总经理');
            //处理权限最多100000
            if (money < 100000) {
                console.log('10万以内的同意');
            } else {
                console.log('金额太大,只能处理十万以内的采购');
                if (this.next) {
                    this.next.handleRequest(money);
                }
            }
        };
        var DSZHandler = function () {}
        DSZHandler.prototype = new Handler();
        DSZHandler.prototype.handleRequest = function (money) {
            console.log('董事长');
            //处理权限至少100000
            if (money >= 100000) {
                console.log('10万以上的我来处理');
                //处理其他逻辑
            }
        };

        // 调用
        function Client(param) {
            console.log('采购机构',param.obj,'采购金额',param.num)
            var cgb = new CGBHandler(),
                zjl = new ZJLHandler(),
                dsz = new DSZHandler();
                cgb.setNext(zjl),
                zjl.setNext(dsz),
                objJson = {
                    'cgb': cgb,
                    'zjl': zjl,
                    'dsz': dsz,
                };
                objJson[param.obj].handleRequest(param.num);
        }
        Client({
            obj: 'cgb',
            num: 800000
        })

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.