├── interview ├── p5.md ├── p4.md ├── p3.md ├── p6.md ├── p2.md └── p1.md ├── es6 ├── class.md ├── arrow.md ├── let&const.md └── destructuring.md ├── about_css ├── flow.md ├── less.md ├── sass.md ├── cascade.md ├── hack.md ├── hvcenter.md ├── layout.html ├── layout.md ├── vcenter.md ├── center.md ├── collapsedmargin.md ├── css3.md ├── fc.md └── flex.md ├── about_js ├── clone.md ├── polyfill.md ├── duplication.md ├── andor.md ├── chain.md ├── prototype.md ├── traverse.md ├── delegation.md ├── tr.js ├── jsonp.md ├── comet.md ├── lazyman.md ├── string.md ├── closure.md ├── array.md ├── websocket.md ├── bubble.md ├── operation.md ├── sameorigin.md ├── extend.md ├── program.md ├── this.md ├── optimize.md ├── convert.md ├── context.md └── event.md ├── overall ├── flex.md ├── iframe.md ├── fiddler.md ├── generator.md ├── message.md ├── promise.md ├── session.md ├── test.html ├── enhancement.md ├── cookie.md ├── storage.md ├── cache.md └── introduce.md ├── about_html ├── doctype.md ├── head.md ├── semantic.md ├── replaced.md └── viewport.md ├── framework ├── nodejs │ ├── fs.md │ ├── http.md │ └── nodejs.md └── vue │ └── vue_router.md ├── test.md ├── getname.js ├── readDir.js ├── dom ├── domattr.md ├── dom.md └── size.md ├── test.html ├── browser ├── http.md ├── optimize.md ├── getpost.md ├── responsecode.md └── tcp.md ├── test.js ├── algorithm ├── sort.md └── tree.md ├── mobile └── problems.md ├── toc.js ├── security └── xss.md └── README.md /interview/p5.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /es6/class.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /about_css/flow.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /about_css/less.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /about_css/sass.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /about_js/clone.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /overall/flex.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /overall/iframe.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /about_html/doctype.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /about_html/head.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /about_html/semantic.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /about_js/polyfill.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /framework/nodejs/fs.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /overall/fiddler.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /overall/generator.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /overall/message.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /overall/promise.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /overall/session.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /about_js/duplication.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /framework/nodejs/http.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /framework/nodejs/nodejs.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /framework/vue/vue_router.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | --- 4 | 5 | -------------------------------------------------------------------------------- /test.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [目录](#目录) 4 | - [目录](#目录) 5 | --- 6 | 7 | ## 目录 8 | 9 | --- 10 | 11 | - [目录](#目录) 12 | 13 | --- 14 | 15 | ## 目录 16 | 17 | --- 18 | 19 | --- 20 | 21 | -------------------------------------------------------------------------------- /about_css/cascade.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [目录](#目录) 4 | - [目录](#目录) 5 | --- 6 | 7 | ## 目录 8 | 9 | --- 10 | 11 | - [目录](#目录) 12 | 13 | --- 14 | 15 | ## 目录 16 | 17 | --- 18 | 19 | --- 20 | 21 | -------------------------------------------------------------------------------- /about_js/andor.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [与或操作符](#与或操作符) 4 | - [a||b](#a||b) 5 | --- 6 | 7 | ## 与或操作符 8 | 9 | ## && 10 | 11 | - 如果a为true(隐式转换),**返回b** 12 | 13 | - 如果a为false,**返回a**,并且**短路**(不执行后面,后面出错也没关系) 14 | 15 | ## a||b 16 | 17 | - 如果a为true(隐式转换),**返回a**,并且**短路**(不执行后面,后面出错也没关系) 18 | 19 | - 如果a为false,**返回b** 20 | 21 | -------------------------------------------------------------------------------- /interview/p4.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## forEach,map,$.each区别 4 | - forEach没有返回值,直接修改数组 5 | - map不会修改当前数组,通过返回值来返回一个新数组 6 | - forEach和map的参数都是(value,index,input) 7 | - $.each也是直接修改数组,没有返回值,参数为(index/key,value) (注意,顺序和forEach不一致) 8 | - $.map 有返回值。$.map()里面的匿名函数支持2个参数(value,index)和$.each()里的参数位置相反,如果是$("span").map()形式,参数顺序和$.each(),$("span").each()一样。 -------------------------------------------------------------------------------- /getname.js: -------------------------------------------------------------------------------- 1 | let fs = require('fs') 2 | let path = require('path') 3 | let process = require('process'); 4 | let readDir = require('./readDir'); 5 | let toc = require('./toc'); 6 | 7 | var files = []; 8 | var str = ''; 9 | 10 | readDir(process.cwd(), function (file) { 11 | toc(file); 12 | // files.push(file); 13 | // var tmp = file.replace(process.cwd(), ''); 14 | // str += `[](${tmp})\n`; 15 | // console.log(file.replace(process.cwd(), '')); 16 | }, { 17 | filters: [/\.git/g] 18 | }); 19 | 20 | // fs.writeFileSync('files.md',str); 21 | // console.log(files); 22 | -------------------------------------------------------------------------------- /about_html/replaced.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [替换元素](#替换元素) 4 | --- 5 | 6 | # 替换元素 7 | 8 | >在CSS中,替换元素是表示在CSS范围之外的元素。这是一种外部对象,其表示与CSS无关。通常它都有一些内置的属性(内置width,内置height,内置ratio) 9 | 10 | - 典型的替换元素是: 11 | 12 | ` 20 | 21 | ## 单行文字——使用line-height 22 | 23 | 如果只有单行文字,并且你知道不会断行,有一个,把line-height设置成和外框一样高度就可以实现文字垂直居中 24 | 25 | ```css 26 | .center-text-trick { 27 | height: 100px; 28 | line-height: 100px; 29 | white-space: nowrap; 30 | ``` 31 | 32 | 35 | 36 | **注意:**只能用于你确定不会超过一行的文字内容,否则!就会出现很尴尬的情况!! 37 | 38 | ## table大法 39 | 40 | table里面有一个`vertical-align:middle` 的属性可以实现居中,你只要模拟一个table出来就行了,即外面套一个`table`里面套一个`table-cell` 41 | 42 | 45 | 46 | ## 神奇的伪类居中 47 | 48 | ```css 49 | .ghost-center { 50 | position: relative; 51 | .ghost-center::before { 52 | content: " "; 53 | display: inline-block; 54 | height: 100%; 55 | width: 1%; 56 | vertical-align: middle; 57 | .ghost-center p { 58 | display: inline-block; 59 | vertical-align: middle; 60 | ``` 61 | 62 | 65 | 66 | ## flex大法 67 | 68 | 用flex一切都简单了 69 | 70 | ```css 71 | .flex-center-vertically { 72 | display: flex; 73 | justify-content: center; 74 | flex-direction: column; 75 | height: 400px; 76 | ``` 77 | 78 | ## 参考文章 79 | 80 | [https://css-tricks.com/centering-css-complete-guide/](https://css-tricks.com/centering-css-complete-guide/) 81 | 82 | -------------------------------------------------------------------------------- /about_js/array.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [常用方法(改变原数组)](#常用方法改变原数组) 4 | - [用map创建数组](#用map创建数组) 5 | - [用reduce压缩数组](#用reduce压缩数组) 6 | - [用fliter过滤数组](#用fliter过滤数组) 7 | - [数组排序sort(改变原数组)](#数组排序sort改变原数组) 8 | - [逆转数组reverse(改变数组)](#逆转数组reverse改变数组) 9 | - [数组拼接concat](#数组拼接concat) 10 | - [字符串和数组转换](#字符串和数组转换) 11 | - [splice函数(改变数组)](#splice函数改变数组) 12 | - [slice函数](#slice函数) 13 | --- 14 | 15 | ## 常用方法(改变原数组) 16 | 17 | js的数组和python的list一样可以存不同类型不同维度个数据,除了可以用下标查看修改数据外,还有几个方法: 18 | 19 | - push():加到最后 20 | 21 | - pop(): 从最后取 22 | 23 | - shift(): 从开头取 24 | 25 | - unshift(): 加入开头 26 | 27 | 构造数组的方式还有如下:(除了特别说明的外,都不改变原数组) 28 | 29 | ### 用map创建数组 30 | 31 | ```js 32 | var oldArray = [1,2,3,4] 33 | var timesFour = oldArray.map(function(val){ 34 | return val * 4; 35 | }); 36 | ``` 37 | 38 | ### 用reduce压缩数组 39 | 40 | reduce的第2个参数(初始值)可选,如果没有,就从数组第一个开始 41 | 42 | ```js 43 | var array = [4,5,6,7,8]; 44 | var sum = 0; 45 | sum = array.reduce(function(pre,cur){ 46 | return pre+cur; 47 | },0); 48 | ``` 49 | 50 | ### 用fliter过滤数组 51 | 52 | 如果我们只需要数组中小于6的元素 53 | 54 | ```js 55 | var oldArray = [1,2,3,4,5,6,7,8,9,10]; 56 | var newArray = oldArray.fliter(function(val){ 57 | return val < 6; 58 | }); 59 | ``` 60 | 61 | ### 数组排序sort(改变原数组) 62 | 63 | 数组有排序的功能(会`改变原数组`,并且也会返回),如果不带参数,默认是按字符串排序,如果要改变排序方式,可以在里面增加比较函数,规则如下 64 | 65 | - 负数:a在b前 66 | 67 | - 大于:b在a前 68 | 69 | ```js 70 | var array = [1, 12, 21, 2]; 71 | //降序排序 72 | array.sort(function(a,b){ 73 | return b-a; 74 | }); 75 | //升序排序 76 | array.sort(function(a,b){ 77 | return a-b; 78 | }); 79 | ``` 80 | 81 | ### 逆转数组reverse(改变数组) 82 | 83 | `改变原数组` 84 | 85 | ```js 86 | var array = [1,2,3,4,5,6,7]; 87 | array.reverse(); 88 | ``` 89 | 90 | ### 数组拼接concat 91 | 92 | ```js 93 | var oldArray = [1,2,3]; 94 | var newArray = []; 95 | var concatMe = [4,5,6]; 96 | newArray = oldArray.concat(concatMe); 97 | ``` 98 | 99 | ### 字符串和数组转换 100 | 101 | - 用split切割字符串 102 | 103 | ```js 104 | var string = "Split me into an array"; 105 | var array = []; 106 | array = string.split(' '); 107 | ``` 108 | 109 | - 用joint把数组拼接成字符串 110 | 111 | ```js 112 | var joinMe = ["Split","me","into","an","array"]; 113 | var joinedString = ''; 114 | joinedString = joinMe.join(' '); 115 | ``` 116 | 117 | ### splice函数(改变数组) 118 | 119 | >array.splice(start, deleteCount[, item1[, item2[, ...]]]) 120 | 121 | js提供了一个splice函数,用来删除`index`位置处的`deleteCount`数目的元素,并且在index处加入item1,2,3……(可以不加入) 122 | 123 | 这个函数可以用来替换数组内的部分元素 124 | 125 | ```js 126 | var myFish = ['angel', 'clown', 'mandarin', 'surgeon']; 127 | // removes 0 elements from index 2, and inserts 'drum' 128 | var removed = myFish.splice(2, 0, 'drum'); 129 | // myFish is ['angel', 'clown', 'drum', 'mandarin', 'surgeon'] 130 | // removed is [], no elements removed 131 | removed = myFish.splice(3, 1); 132 | // myFish is ['angel', 'clown', 'drum', 'surgeon'] 133 | // removed is ['mandarin'] 134 | removed = myFish.splice(2, 1, 'trumpet'); 135 | // myFish is ['angel', 'clown', 'trumpet', 'surgeon'] 136 | // removed is ['drum'] 137 | ``` 138 | 139 | ### slice函数 140 | 141 | >arr.slice([begin[, end]]) 142 | 143 | 取出数组的从begin到end的元素,重新组成数组。 144 | 145 | ```js 146 | var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']; 147 | var citrus = fruits.slice(1, 3);// ['Orange','Lemon'] 148 | ``` 149 | 150 | -------------------------------------------------------------------------------- /browser/responsecode.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [常用的HTTP状态码](#常用的HTTP状态码) 4 | - [1、状态码的类别](#1、状态码的类别) 5 | - [详细说明](#详细说明) 6 | - [3XX 重定向](#3XX-重定向) 7 | - [1.3、4XX 客户端错误](#13、4XX-客户端错误) 8 | - [5XX 服务器错误](#5XX-服务器错误) 9 | --- 10 | 11 | ## 常用的HTTP状态码 12 | 13 | 状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。 14 | 15 | 状态码如 200 OK,以 3 位数字和原因短语组成。 16 | 17 | 数字中的第一位指定了响应类别,后两位无分类。响应类别有以下 5 种。 18 | 19 | ## 1、状态码的类别 20 | 21 | **1XX Informational(信息性状态码)**接收的请求正在处理 22 | 23 | **2XX Success(成功状态码)** 请求正常处理完毕 24 | 25 | **3XX Redirection(重定向状态码**) 需要进行附加操作以完成请求 26 | 27 | **4XX Client Error(客户端错误状态码)**服务器无法处理请求 28 | 29 | **5XX Server Error(服务器错误状态码)**服务器处理请求出错 30 | 31 | 只要遵守状态码类别的定义,即使改变 RFC2616 中定义的状态码,或服务器端自行创建状态码都没问题。 32 | 33 | 简单说明 34 | 35 | 200:请求被正常处理 36 | 37 | 204:请求被受理但没有资源可以返回 38 | 39 | 206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行GET方法,相应报文中通过Content-Range指定范围的资源。 40 | 41 | 301:永久性重定向 42 | 43 | 302:临时重定向 44 | 45 | 303:与302状态码有相似功能,只是它希望客户端在请求一个URI的时候,能通过GET方法重定向到另一个URI上 46 | 47 | 304:发送附带条件的请求时,条件不满足时返回,与重定向无关(**缓存**) 48 | 49 | 307:临时重定向,与302类似,只是强制要求使用POST方法 50 | 51 | 400:请求报文语法有误,服务器无法识别 52 | 53 | 401:请求需要认证 54 | 55 | 403:请求的对应资源禁止被访问 56 | 57 | 404:服务器无法找到对应资源 58 | 59 | 500:服务器内部错误 60 | 61 | 503:服务器正忙 62 | 63 | ## 详细说明 64 | 65 | ### 2XX 成功 66 | 67 | 2XX 的响应结果表明请求被正常处理了。 68 | 69 | > 200 OK 70 | 71 | 表示从客户端发来的请求在服务器端被正常处理了。在响应报文内,随状态码一起返回的信息会因方法的不同而发生改变。比如,使用GET 方法时,对应请求资源的实体会作为响应返回;而使用 HEAD 方法时,对应请求资源的实体首部不随报文主体作为响应返回(即在响应中只返回首部,不会返回实体的主体部分)。 72 | 73 | > 204 No Content 74 | 75 | 该状态码代表服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。另外,也不允许返回任何实体的主体。比如,当从浏览器发出请求处理后,返回 204 响应,那么浏览器显示的页面不发生更新。 76 | 77 | 一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用。 78 | 79 | > 206 Partial Content 80 | 81 | 该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求。响应报文中包含由 Content-Range 指定范围的实体内容。 82 | 83 | ### 3XX 重定向 84 | 85 | 3XX 响应结果表明浏览器需要执行某些特殊的处理以正确处理请求。 86 | 87 | > 301 Moved Permanently 88 | 89 | 永久性重定向。该状态码表示请求的资源已被分配了新的 URI,以后应使用资源现在所指的 URI。也就是说,如果已经把资源对应的 URI 保存为书签了,这时应该按Location 首部字段提示的 URI 重新保存。 90 | 91 | 像下方给出的请求 URI,当指定资源路径的最后忘记添加斜杠“/”,就会产生 301 状态码。 92 | 93 | http://example.com/sample 94 | 95 | > 302 Found 96 | 97 | 临时性重定向。该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。 98 | 99 | 和 301 Moved Permanently 状态码相似,但 302 状态码代表的资源不是被永久移动,只是临时性质的。换句话说,已移动的资源对应的 URI 将来还有可能发生改变。比如,用户把 URI 保存成书签,但不会像 301 状态码出现时那样去更新书签,而是仍旧保留返回 302 状态码的页面对应的 URI。 100 | 101 | ## 1.3、4XX 客户端错误 102 | 103 | 4XX 的响应结果表明客户端是发生错误的原因所在。 104 | 105 | > 400 Bad Request 106 | 107 | 该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码。 108 | 109 | > 401 Unauthorized 110 | 111 | 该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。另外若之前已进行过 1 次请求,则表示用 户认证失败。 112 | 113 | 返回含有 401 的响应必须包含一个适用于被请求资源的 WWW-Authenticate 首部用以质询(challenge)用户信息。当浏览器初次接收到 401 响应,会弹出认证用的对话窗口。 114 | 115 | > 403 Forbidden 116 | 117 | 该状态码表明对请求资源的访问被服务器拒绝了。服务器端没有必要给出拒绝的详细理由,但如果想作说明的话,可以在实体的主体部分对原因进行描述,这样就能让用户看到了。未获得文件系统的访问授权,访问权限出现某些问题(从未授权的发送源 IP 地址试图访问)等列举的情况都可能是发生 403 的原因。 118 | 119 | > 404 Not Found 120 | 121 | 该状态码表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。 122 | 123 | ### 5XX 服务器错误 124 | 125 | 5XX 的响应结果表明服务器本身发生错误。 126 | 127 | > 500 Internal Server Error 128 | 129 | 该状态码表明服务器端在执行请求时发生了错误。也有可能是 Web 应用存在的 bug或某些临时的故障。 130 | 131 | > 503 Service Unavailable 132 | 133 | 该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入 RetryAfter 首部字段再返回给客户端。 134 | 135 | -------------------------------------------------------------------------------- /about_js/websocket.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [WebSocket](#WebSocket) 4 | - [基本认识](#基本认识) 5 | - [WebSocket握手](#WebSocket握手) 6 | - [WebSocket API](#WebSocket-API) 7 | - [搭建简易实验环境](#搭建简易实验环境) 8 | --- 9 | 10 | # WebSocket 11 | 12 | websocket的出现是为了弥补http的不足,如今这项技术已被广泛应用于我们熟悉的网站,例如github、stackoverflow等等。 13 | 14 | ## 基本认识 15 | 16 | 1. WebSocket是Web应用程序的传输协议,它提供了`双向的、按序到达的数据流`。 17 | 18 | 2. 高层的协议能够在WebSocket上运行。 19 | 20 | 3. 作为Web的一部分,WebSocket连接的是URL。 21 | 22 | ## WebSocket握手 23 | 24 | [![WebSocket](https://github.com/zhangguixu/front-end/raw/master/image/websocket.png)](https://github.com/zhangguixu/front-end/blob/master/image/websocket.png) 25 | 26 | 为了建立WebSocket通信,客户端和服务器在初始握手时,将HTTP协议升级到了WebSocket协议。 27 | 28 | **从客户端到服务器** 29 | 30 | ``` 31 | GET /chat HTTP/1.1 32 | Host: example.com 33 | Connection: Upgrade 34 | Sec-WebSocket-Protocol: Sample 35 | Upgrade: websocket 36 | Sec-WebSocket-Version: 13 37 | Sec-WebSocket-Key: ..... 38 | Origin: http://example.com 39 | [8-byte security key] 40 | ``` 41 | 42 | **从服务器到客户端** 43 | 44 | ``` 45 | HTTP/1.1 101 WebSocket Protocol Handshake 46 | Upgrade: websocket 47 | Connection: Upgrade 48 | Sec-WebSocket-Accept: ... 49 | WebSocket-Protocol: sample 50 | ``` 51 | 52 | 一旦连接成功,就可以在全双工模式下在客户端和服务器之间来回传送Websocket消息。这就意味着,在同一时间、任何方向,都可以全双工发送基于文本的消息。在网络中,每个消息以Ox00字节开头,以OxFF结尾,中间数据采用UTF-8编码格式。 53 | 54 | ## WebSocket API 55 | 56 | 采用Websocket API的流程 57 | 58 | 1. 创建Socket 59 | 60 | ``` 61 | var socket = new WebSocket('ws://www.example.com:1234/resource'); 62 | ``` 63 | 64 | 2. 注册事件处理程序 65 | 66 | ``` 67 | socket.onopen = function(e){/*socket已经连接*/} 68 | socket.onclose = function(e){/*socket已经关闭*/} 69 | socket.onerror = function(e){/*出错了*/} 70 | socket.onmessage = function(e){ 71 | var message = e.data; /*服务器发送一条消息*/ 72 | } 73 | ``` 74 | 75 | 3. 发送数据 76 | 77 | ``` 78 | socket.send('Hello World'); 79 | ``` 80 | 81 | 4. 关闭Socket 82 | 83 | ``` 84 | socket.close(); 85 | ``` 86 | 87 | ## 搭建简易实验环境 88 | 89 | 基于node的`Socket.IO`来搭建服务器端。 90 | 91 | 客户端 92 | 93 | ```js 94 | $(function () { 95 | var socket = io(); 96 | $('form').submit(function(){ 97 | socket.emit('chat message', $('#m').val()); //发送 98 | $('#m').val(''); 99 | return false; 100 | }); 101 | socket.on('chat message', function(msg){ //接受 102 | $('#messages').append($('
  • ').text(msg)); 103 | window.scrollTo(0, document.body.scrollHeight); 104 | }); 105 | }); 106 | ``` 107 | 108 | 服务端 109 | 110 | ```js 111 | var app = require('express')(); 112 | var http = require('http').Server(app); 113 | var io = require('socket.io')(http); 114 | var port = process.env.PORT || 3000; 115 | app.get('/', function(req, res){ 116 | res.sendFile(__dirname + '/index.html'); 117 | }); 118 | io.on('connection', function(socket){ 119 | socket.on('chat message', function(msg){ 120 | io.emit('chat message', msg); 121 | }); 122 | }); 123 | http.listen(port, function(){ 124 | console.log('listening on *:' + port); 125 | }); 126 | ``` 127 | 128 | Socket.IO可以接收所有与服务器端相连接的客户端发送的消息,也可以向这些客户端发送消息。它可以实现以下几种通信方式: 129 | 130 | - HTML5的Websocket 131 | 132 | - 在Flash中使用WebSocket通信 133 | 134 | - XHR轮询 135 | 136 | - JSONP轮询 137 | 138 | - Forever Iframe 139 | 140 | 安装 `npm install socket.io` 141 | 142 | -------------------------------------------------------------------------------- /about_js/bubble.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [目录](#目录) 4 | - [html冒泡和事件捕获机制](#html冒泡和事件捕获机制) 5 | - [DOM事件流](#DOM事件流) 6 | - [冒泡顺序](#冒泡顺序) 7 | - [不触发冒泡的事件](#不触发冒泡的事件) 8 | - [target¤tTarget](#target¤tTarget) 9 | - [阻止冒泡](#阻止冒泡) 10 | - [IE](#IE) 11 | - [兼容写法](#兼容写法) 12 | - [阻止冒泡应用](#阻止冒泡应用) 13 | --- 14 | 15 | ## 目录 16 | 17 | --- 18 | 19 | - [html冒泡和事件捕获机制](#html冒泡和事件捕获机制) 20 | 21 | - [DOM事件流](#DOM事件流) 22 | 23 | - [冒泡顺序](#冒泡顺序) 24 | 25 | - [不触发冒泡的事件](#不触发冒泡的事件) 26 | 27 | - [target¤tTarget](#target¤tTarget) 28 | 29 | - [阻止冒泡](#阻止冒泡) 30 | 31 | - [IE](#IE) 32 | 33 | - [兼容写法](#兼容写法) 34 | 35 | - [阻止冒泡应用](#阻止冒泡应用) 36 | 37 | --- 38 | 39 | ## html冒泡和事件捕获机制 40 | 41 | > 事件冒泡: 当一个元素上的事件被触发的时候,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发。这一过程被称为事件冒泡;这个事件从原始元素开始一直冒泡到DOM树的最上层 42 | 43 | > 事件捕获:与冒泡刚好相反 44 | 45 | 比如一个简单的代码: 46 | 47 | ``` 48 | 49 | 58 | ``` 59 | 60 | 我点击按钮后,同时也触发了`document`的事件。这不是我们想要的结果 61 | 62 | ## DOM事件流 63 | 64 | (IE8之前的不支持) 65 | 66 | DOM2事件流规定事件流包括3个阶段:`捕获阶段`,`目标阶段`,`冒泡阶段`,可以根据第二个参数判断是否在捕获阶段。 67 | 68 | ```js 69 | addEventListener('click',fn(),false) //冒泡阶段 70 | addEventListener('click',fn(),true) //捕获阶段 71 | ``` 72 | 73 | ### 冒泡顺序 74 | 75 | IE 6.0: 76 | 77 | **div -> body-> html -> document** 78 | 79 | 其他浏览器,会冒到window 80 | 81 | **div -> body-> html -> document -> window** 82 | 83 | ### 不触发冒泡的事件 84 | 85 | 但是并不是所有的的事件都会触发冒泡,以下事件不冒泡:`blur`、`focus`、`load`、`unload` 86 | 87 | 要实现`blur`和`focus`的代理: 88 | 89 | `blur`和`focus`在ie下可以通过focusin和focusout事件(支持冒泡) 90 | 91 | ```js 92 | el.onfocusin = focusHandler; 93 | el.onfocusout = blurHandler; 94 | ``` 95 | 96 | 其他的情况下,可以使用捕获实现代理 97 | 98 | ```js 99 | el.addEventListener('focus', focusHandler, true); 100 | el.addEventListener('blur', blurHandler, true); 101 | ``` 102 | 103 | ## target¤tTarget 104 | 105 | target在事件流的目标阶段;currentTarget在事件流的捕获,目标及冒泡阶段。只有当事件流处在目标阶段的时候,两个的指向才是一样的, 而当处于捕获和冒泡阶段的时候,target指向被单击的对象而currentTarget指向当前事件活动的对象(一般为父级)。 106 | 107 | ## 阻止冒泡 108 | 109 | ### 正常浏览器 110 | 111 | 正常浏览器使用的是`stopPropagation`方法, 112 | 113 | event.stopPropagation() 114 | 115 | ### IE 116 | 117 | ie低版本的使用的是`cancelBubble` 属性 118 | 119 | event.cancelBubble =true 120 | 121 | ### 兼容写法 122 | 123 | ``` 124 | if(event && event.stopPropagation) 125 | { 126 | event.stopPropagation(); // w3c 标准 127 | } 128 | else 129 | { 130 | event.cancelBubble = true; // ie 678 ie浏览器 131 | ``` 132 | 133 | ## 阻止冒泡应用 134 | 135 | 最简单的用法就是**弹出对话框点击空白处隐藏**。我们肯定会在`document`上绑定一个`onclick`事件,用来**隐藏对话框**,但是我们页面上肯定也有一个元素(比如`注册按钮`),用来**点击弹出对话框**。 136 | 137 | 这时候就有问题了,我们点击`注册按钮`本来想弹出一个对话框,但是同时响应了document的onclick事件,直接隐藏了。所以这个时候,就要对`注册按钮`进行冒泡的阻止。 138 | 139 | ```js 140 | login.onclick = function(event) { 141 | $("mask").style.display = "block"; 142 | $("show").style.display = "block"; 143 | document.body.style.overflow = "hidden"; // 不显示滚动条 144 | //取消冒泡 145 | var event = event || window.event; 146 | if(event && event.stopPropagation) 147 | { 148 | event.stopPropagation(); 149 | } 150 | else 151 | { 152 | event.cancelBubble = true; 153 | } 154 | } 155 | ``` 156 | 157 | -------------------------------------------------------------------------------- /about_css/center.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [内联元素 - text-align:center](#内联元素---text-align:center) 4 | - [块状元素 ](#块状元素-) 5 | - [使用定位,设置left/right](#使用定位,设置left/right) 6 | - [不定宽水平居中](#不定宽水平居中) 7 | - [使用table](#使用table) 8 | - [设置行内元素](#设置行内元素) 9 | - [【推荐】使用定位 ](#【推荐】使用定位-) 10 | - [css3-transform](#css3-transform) 11 | - [多套一层,绝对+相对定位](#多套一层,绝对+相对定位) 12 | - [【推荐】flex大法](#【推荐】flex大法) 13 | - [参考文章](#参考文章) 14 | --- 15 | 16 | # 内联元素 - text-align:center 17 | 18 | 内联元素`
    87 | 92 |
    93 | ``` 94 | 95 | ```css 96 | .container{text-align:center;} 97 | .container ul{list-style:none;margin:0;padding:0;display:inline;} 98 | .container li{margin-right:8px;display:inline;} 99 | ``` 100 | 101 | ### 【推荐】使用定位 102 | 103 | 不定宽的元素就是不知道到底多宽,使用定位无法调整,所以有2种解决方案 104 | 105 | #### css3-transform 106 | 107 | 设置 position:relative/absolute 和 left:50%:利用 相对定位 的方式,将元素向左偏移 50% (此时50%是自身长宽),即达到居中的目的,然后通过transform的位移translate**这个移动端用的比较多因为css3兼容好** 108 | 109 | ```css 110 | div{ 111 | position:absolute/relative; 112 | top:50%; 113 | left:50%; 114 | transform:translate(-50%,-50%); 115 | background:red; 116 | ``` 117 | 118 | #### 多套一层,绝对+相对定位 119 | 120 | 兼容性较好,基本都兼容 121 | 122 | ```html 123 |
    124 |
    125 | 126 |
    127 |
    128 | ``` 129 | 130 | ```css3 131 | .outer{ 132 | position:absolute/relative; 133 | top:50%; 134 | left:50%; 135 | .inner{ 136 | position:relative; 137 | margin-left:-50%; 138 | margin-top:-50%; 139 | ``` 140 | 141 | # 【推荐】flex大法 142 | 143 | 外面套一个flex的container,直接使用justify-conent:center就可以了 144 | 145 | ```css 146 | .flex-center { 147 | display: flex; 148 | justify-content: center; 149 | ``` 150 | 151 | ## 参考文章 152 | 153 | [https://css-tricks.com/centering-css-complete-guide/](https://css-tricks.com/centering-css-complete-guide/) 154 | 155 | -------------------------------------------------------------------------------- /about_css/collapsedmargin.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [margin](#margin) 4 | - [margin塌陷(collapsing margins)](#margin塌陷collapsing-margins) 5 | - [相邻规则](#相邻规则) 6 | - [规则拆开](#规则拆开) 7 | --- 8 | 9 | ## margin 10 | 11 | - margin可以取**负值**(布局常用,比如双飞翼和圣杯布局,或是做居中的时候,小范围位移) 12 | 13 | - 如果margin取auto,则要看 14 | 15 | - margin初始为0 16 | 17 | ## margin塌陷(collapsing margins) 18 | 19 | 在CSS中,两个或多个盒子(**或可能不是兄弟姐妹**)的相邻边可以组合成一个边。这种组合方式被称为collapse(塌陷),由此产生的合并margin称为`collapsed margin` 20 | 21 | - 水平margin不会塌陷 22 | 23 | - root element's box 不会塌陷 24 | 25 | 如果有`clearance`的元素的顶部和底部margin相邻,则其边距与后面的兄弟姐妹的相邻**边距折叠**,但由此产生的边距**不会与父块的底部边距折叠**。 26 | 27 | ### 相邻规则 28 | 29 | 两个margin是**相邻的**,当且仅当: 30 | 31 | 1. 都属于**流内**(in-flow)[**块级盒**](./fc.md#块级元素Block-level-elements与块级盒Block-level-boxes) ,处于**同一个**[块格式化上下文**BFC**](./fc.md) 32 | 33 | 2. **没有行盒** (line box),**没有空隙(clearance)**,**没有padding**并且**没有border把它们隔开**(注意,因此某些0高度行盒会被忽略) 34 | 35 | 3. 都属于竖直相邻盒边(vertically-adjacent box edges),即来自下列某一对: 36 | 37 | - 一个**盒的top margin**和它的第一个流内(in-flow)**孩子的top margin** 38 | 39 | - 一个盒的**bottom margin**和它的下一个流内后面的**兄弟的top margin** 40 | 41 | - **最后**一个流内**孩子的bottom margin**和它的**父级的bottom margin**,**如果父级的高度的计算值为'auto'** 42 | 43 | - 一个盒的top和bottom margin**自己折叠** : 该盒没有建立一个新的块格式化上下文并且['min-height'](http://www.ayqy.net/doc/css2-1/visudet.html#propdef-min-height)的**计算值为0**,['height'](http://www.ayqy.net/doc/css2-1/visudet.html#propdef-height)的计**算值为0或者'auto'**,并且没有流内孩子。 44 | 45 | 如果一个margin的任何部分margin与另一个margin相邻的话,就认为它与那个margin相邻,是合并(collapsed)margin 46 | 47 | **注意:**相邻margin可以通过**非兄弟或者祖先关系**的元素生成 48 | 49 | ```css 50 | .parent-box { 51 | margin: 100px; 52 | padding: 0px; 53 | width: 500px; 54 | background: pink; 55 | } 56 | .child-box { 57 | margin: 10%; 58 | padding: 1%; 59 | width: 200px; 60 | background: greenyellow; 61 | } 62 | ``` 63 | 64 | 此时明显,父亲和孩子的上下margin都重合了,要想打破这写重合,就打破相邻规则 65 | 66 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1499745383958) 67 | 68 | 给父亲加1px padding 69 | 70 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1499745499468) 71 | 72 | 给父亲加border 73 | 74 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1499745519630) 75 | 76 | 加入一个文字行盒(底部没有元素,所以margin-bottom依然重叠) 77 | 78 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1499745570551) 79 | 80 | ### 规则拆开 81 | 82 | - 一个[浮动的](http://www.ayqy.net/doc/css2-1/visuren.html#floats)盒(**非流内**)与任何其它盒之间的margin不会合并(甚至一个浮动盒与它的流内子级之间也不会) 83 | 84 | - 建立了新的块格式化上下文的元素(例如,浮动盒与['overflow'](http://www.ayqy.net/doc/css2-1/visufx.html#propdef-overflow)不为'visible'的元素)的margin不会与它们的流内子级合并(**非同一BFC**) 85 | 86 | - [绝对定位的](http://www.ayqy.net/doc/css2-1/visuren.html#absolutely-positioned)盒 (**非流内**)的margin不会合并(甚至与它们的流内子级也不会) 87 | 88 | - 内联盒的margin不会合并(**非块级元素**)(甚至与它们的流内子级也不会) 89 | 90 | - 一个流内块级元素的bottom margin总会与它的下一个流内块级兄弟的top margin合并,**除非兄弟有空隙** 91 | 92 | - 一个流内块级元素的top margin会与它的第一个流内块级子级的top margin合并,如果该元素**没有top border**,没有**top padding**并且该子级**没有空隙** 93 | 94 | - **一个height为'auto'并且min-height为0**的流内块级盒的bottom margin会与它的最后一个流内块级子级的bottom margin合并,如果该盒没有bottom padding并且没有bottom border并且子级的bottom margin不与有空隙的top margin合并 95 | 96 | - 盒自身的margin也会合并,如果['min-height'](http://www.ayqy.net/doc/css2-1/visudet.html#propdef-min-height)属性为0,并且既没有top或者bottom border也没有top或者bottom padding,并且其['height'](http://www.ayqy.net/doc/css2-1/visudet.html#propdef-height)为0或者'auto',并且不含行盒,并且其所有流内子级的margin(如果有的话)都合并了 97 | 98 | 当两个或多个边距折叠,所得到的边距宽度是**折叠边距宽度的最大值**。 99 | 100 | 在负边距的情况下,负相邻边距的绝对值的最大值从正相邻边距的最大值中扣除。如果没有正的边距,则将相邻边距的绝对值的最大值从零中扣除。 101 | 102 | -------------------------------------------------------------------------------- /overall/cookie.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [cookie操作](#cookie操作) 4 | - [服务端设置cookie](#服务端设置cookie) 5 | - [cookie和session](#cookie和session) 6 | - [cookie跨域](#cookie跨域) 7 | - [Cookie跨域单点登录 ](#Cookie跨域单点登录--) 8 | - [总结](#总结) 9 | - [参考文章](#参考文章) 10 | --- 11 | 12 | ## cookie操作 13 | 14 | ### JS 15 | 16 | ```js 17 | document.cookie 18 | ``` 19 | 20 | 返回是一个字符串,"key1=value1; key2=value2; " 21 | 22 | 每个key,value之后有一个`;`和`空格`, 23 | 24 | `document.cookie`只会执行添加或者修改操作,不能删除里面已添加的值,设置document.cookie不会覆盖cookie,除非cookie的名称已经存在。 25 | 26 | ```js 27 | // 设置document.cookie 28 | document.cookie = ""; 29 | document.cookie; 30 | 运行结果依旧是之前的值 31 | ``` 32 | 33 | 将cookie设置为空,并不能清除cookie,因为是不会覆盖的 34 | 35 | ### 服务端设置cookie 36 | 37 | 会在响应头里加入`Set-Cookie`,然后浏览器会把这个加入cookie中,name和value都必须是URL编码 38 | 39 | ```html 40 | HTTP/1.1 200 OK 41 | Content-Type: text/html 42 | Set-Cookie: name=value 43 | ``` 44 | 45 | ## cookie和session 46 | 47 | 可以说cookie就是seession,服务器在遇到一个http连接的时候,就会检查是否携带了cookie,其中有没有seessionID,如果有就去查自己的数据库(redis)看是否匹配,匹配了就知道该用户是谁。 48 | 49 | 否则就生成一个新的key,服务器会把sessionID种在浏览器的cookie中,这样,当用户再次访问的时候,服务器就能标示该用户是否浏览过。 50 | 51 | ## cookie跨域 52 | 53 | ### 同域单点登录 54 | 55 | 在cookie相关文档信息中,提到cookie是不能跨域访问的,**但是在二级域名是可以共享cookie的。** 这样就是我们的项目有了局限性,必须将多个系统的域名统一,作为二级域名,统一平台提供使用主域名。这样就可以实现cookie的单点登录了。 56 | 57 | cookie的四个可选属性: 58 | 59 | - cookie的生存期属性:expires; 60 | 61 | 默认情况下,cookie只在浏览器会话期存在.退出浏览器就丢失;可以用expires设置时间;退出浏览器后就不会丢失并存为客户端浏览器的cookie文件;过了时间后cookie失效,还会自动删除cookie文件. 62 | 63 | - path属性:默认情况下,在同一个目录下文件可以调用; 64 | 65 | >例如:http://hanj.com/c1/1.html设置的cookie可以被http://hanj.com/c1/2.html调用.但不能被http://hanj.com/c2/目录下的文件调用; 66 | 67 | > 但如把path属性设成"/";则在http://hanj.com/下的所有文件都可调用此cookie. 68 | 69 | - domain属性:例如设成".hanj.com"则在.hanj.com下的所有服务器下的文件都可以调用cookie. 70 | 71 | - secure安全属性:默认情况下为false;用http协议不安全传输;true:用https等协议安全传输. 72 | 73 | 所以设置了domain就可以实现二级域名共享cookie 74 | 75 | ### Cookie跨域单点登录 76 | 77 | 为了快速、简单的实现这一功能,首先想到就是通过JS操作Cookie并让两个不同域的cookie能够相互访问,这样就可达到了上述的效果,具体实现过程大致可分以下两个步骤: 78 | 79 | 1、在A系统下成功登录后,利用JS动态创建一个隐藏的iframe,通过iframe的src属性将A域下的cookie值作为 get参数重定向到B系统下b.aspx页面上; 80 | 81 | ```js 82 | var _frm = document.createElement("iframe"); 83 | _frm.style.display="none"; 84 | _frm.src="http://b.com/b.jsp?test_cookie=xxxxx"; 85 | document.body.appendChild(_frm); 86 | ``` 87 | 88 | 2、在B系统的b.aspx页面中来获取A系统中所传过来的cookie值,并将所获取到值写入cookie中,这样就简单的实现了cookie跨域的访问; 不过这其中有个问题需要注意,就是在IE浏览器下这样操作不能成功,需要在b.aspx页面中设置P3P HTTP Header就可以解决了(具体詳細信息可以参考:http://www.w3.org/P3P/),P3P设置代码为: 89 | 90 | ```js 91 | /* 92 | *也可以在html加入标记 93 | 94 | Response.AppendHeader("P3P", "CP='IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA'"); 95 | ``` 96 | 97 | ## 总结 98 | 99 | - 服务端设置了http-only属性的Cookie,客户端JS无法读取,更别说更改了。 100 | 101 | - 跨域的Cookie会存取失败(跨二级域名不包括在内)。 102 | 103 | - 如果浏览器设置了阻止网站设置任何数据, 客户端无法接收Cookie,当然JS对Cookie的操作会失败。 104 | 105 | - Cookie的数量超过最大限制,之前的Cookie被自动删除,JS无法读取到。Cookie过期被浏览器自动删除了。 106 | 107 | - cookie是一种WEB服务器通过浏览器在访问者的硬盘上存储信息的手段。 108 | 109 | - cookie个数限制30-50个 (20个不再正确), 大小约4k 110 | 111 | - 不同浏览器对过多cookie的处理方式不同,opera,ie是LRU方式,firefox是随机替换 112 | 113 | - cookie会包含在http的请求头,发送到服务器端,与h5存储最大的区别 114 | 115 | cookie只能给同个域名下的js访问 116 | 117 | - 会话cookie:如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间 118 | 119 | - 持久cookie:如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过了设定的时间 120 | 121 | 存储在硬盘上的cookie可以在不同的浏览器进程间共享 122 | 123 | ## 参考文章 124 | 125 | [浏览器 cookie 限制](http://www.planabc.net/2008/05/22/browser_cookie_restrictions/) 126 | 127 | [cookie 跨域访问的解决方案](http://www.cnblogs.com/sueris/p/5674169.html) 128 | 129 | -------------------------------------------------------------------------------- /about_js/operation.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [js常用事件操作](#js常用事件操作) 4 | - [event 常见属性](#event--常见属性) 5 | - [pageX clientX screenX 区别](#pageX--clientX-screenX-区别) 6 | - [常用事件](#常用事件) 7 | - [如何实现拖动](#如何实现拖动) 8 | - [ 防止选择拖动](#-防止选择拖动) 9 | - [完整代码](#完整代码) 10 | - [如何实现屏幕滚动检测](#如何实现屏幕滚动检测) 11 | --- 12 | 13 | # js常用事件操作 14 | 15 | ## 事件对象 16 | 17 | 我们学过一些事件 : onmouseover onmouseout onclick ..... 18 | 19 | ```javascript 20 | btn.onclick =function(event) { 语句 } 21 | ``` 22 | 23 | `event` 就是事件的对象 指向的是 事件 是 onclick 24 | 25 | 再触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。所有浏览器都支持event对象,但支持的方式不同。 26 | 27 | 比如鼠标操作时候,会添加鼠标位置的相关信息到事件对象中。普通浏览器支持 event , ie 678 支持 window.event 28 | 29 | 所以我们采取兼容性的写法 : 30 | 31 | ```js 32 | var event = event || window.event; 33 | ``` 34 | 35 | ### event 常见属性 36 | 37 | | 属性 | 作用 | 38 | 39 | | ----------- | -------------------------- | 40 | 41 | | data | 返回拖拽对象的URL字符串(dragDrop) | 42 | 43 | | width | 该窗口或框架的高度 | 44 | 45 | | height | 该窗口或框架的高度 | 46 | 47 | | pageX | 光标相对于该网页的水平位置(ie无) | 48 | 49 | | pageY | 光标相对于该网页的垂直位置(ie无) | 50 | 51 | | screenX | 光标相对于该屏幕的水平位置 | 52 | 53 | | screenY | 光标相对于该屏幕的垂直位置 | 54 | 55 | | **target** | **该事件被传送到的对象** | 56 | 57 | | **type** | **事件的类型** | 58 | 59 | | **clientX** | **光标相对于该网页的水平位置** (当前可见区域) | 60 | 61 | | **clientY** | **光标相对于该网页的垂直位置** | 62 | 63 | ### pageX clientX screenX 区别 64 | 65 | screen X screenY 66 | 67 | 是以我们的电脑屏幕 为基准点 测量 68 | 69 | pageX pageY 70 | 71 | 以我们的 文档 (绝对定位) 的基准点对齐 ie678 不认识 72 | 73 | clientX clientY 74 | 75 | 以可视区域 为基准点 类似于 固定定位 76 | 77 | ## 常用事件 78 | 79 | ### move 80 | 81 | `onmousemove` 当鼠标移动的时候 就是说,**鼠标移动一像素就会执行的事件** 82 | 83 | 当鼠标再div 身上移动的时候,就会执行 84 | 85 | div.onmouseover 和 div.onmousemove 区别 86 | 87 | 他们相同点 都是经过 div 才会触发 88 | 89 | div.onmouseover **只触发一次** 90 | 91 | div.onmousemove **每移动一像素,就会触发一次** 92 | 93 | `onmouseup` 当鼠标弹起 94 | 95 | `onmousedown` 当鼠标按下的时候 96 | 97 | ## 如何实现拖动 98 | 99 | ### 拖动 原理 100 | 101 | > 鼠标按下 接着 移动鼠标。 102 | 103 | ```javascript 104 | bar.onmousedown =function(){ 105 | document.onmousemove = function(){ 106 | } 107 | ``` 108 | 109 | ### 防止选择拖动 110 | 111 | 我们知道按下鼠标然后拖拽可以选择文字 的。 112 | 113 | 清除选中的内容 114 | 115 | ```javascript 116 | window.getSelection? window.getSelection().removeAllRanges() : document.selection.empty(); 117 | ``` 118 | 119 | ### 完整代码 120 | 121 | ```js 122 | window.onload = function (argument) { 123 | function $(id){return document.getElementById(id);} 124 | var drag=$('drag_area'), 125 | move=$('box'); 126 | DragThis(drag,move); 127 | function DragThis(drag_obj, move_obj) 128 | { 129 | drag_obj.onmousedown = function(event){ 130 | var x = event.clientX - move_obj.offsetLeft - 100; // 坐标补偿 131 | var y = event.clientY - move_obj.offsetTop - 100; 132 | document.onmousemove = function(){ 133 | var event = event || window.event; 134 | move_obj.style.left = event.clientX - x +'px'; //计算移动后的物体位置 135 | move_obj.style.top = event.clientY - y +'px'; 136 | window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty(); //清除拖拽选中文字 137 | } 138 | } 139 | } 140 | document.onmouseup = function () { 141 | document.onmousemove = null; 142 | } 143 | ``` 144 | 145 | ## 如何实现屏幕滚动检测 146 | 147 | -------------------------------------------------------------------------------- /overall/storage.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [localstorage](#localstorage) 4 | - [sessionStorage](#sessionStorage) 5 | - [应用缓存](#应用缓存) 6 | - [application cache](#application-cache) 7 | --- 8 | 9 | ## localstorage 10 | 11 | localStorage是Html5的一种新的本地缓存方案,目前用的比较多,一般用来存储ajax返回的数据,加快下次页面打开时的渲染速度。 12 | 13 | |浏览器|最大长度| 14 | 15 | |-----|-----| 16 | 17 | |IE9以上|5M| 18 | 19 | |Firefox8以上|5.24M| 20 | 21 | |Opera|2M| 22 | 23 | |Safari/WebKit|2.6M| 24 | 25 | ```js 26 | //localStorage核心API: 27 | localStorage.setItem(key, value) //设置记录 28 | localStorage.getItem(key) //获取记录 29 | localStorage.removeItem(key) //删除该域名下单条记录 30 | localStorage.clear() //删除该域名下所有记录 31 | ``` 32 | 33 | 值得注意的是,localstorage大小有限制,不适合存放过多的数据,如果数据存放超过最大限制会报错,并移除最先保存的数据。 34 | 35 | ## sessionStorage 36 | 37 | 和localstorage差不多,不过是会话结束就关闭 38 | 39 | ## 应用缓存 40 | 41 | ### 离线检测 42 | 43 | ```js 44 | window.navigator.onLine //true表示能上网 但是在chrome11及之前的版本上始终为true 45 | window.ononline = fn() //html5的新事件 46 | window.onoffline = fn() // 47 | ``` 48 | 49 | ### application cache 50 | 51 | application cahce是将大部分图片资源、js、css等静态资源放在`manifest`文件配置中。当页面打开时通过manifest文件来读取本地文件或是请求服务器文件。 52 | 53 | 离线访问对基于网络的应用而言越来越重要。虽然所有浏览器都有缓存机制,但它们并不可靠,也不一定总能起到预期的作用。HTML5 使用ApplicationCache 接口可以解决由离线带来的部分难题。**前提是你需要访问的web页面至少被在线访问过一次。** 54 | 55 | 使用缓存接口可为您的应用带来以下三个优势: 56 | 57 | - 离线浏览 – 用户可在离线时浏览您的完整网站。 58 | 59 | - 速度 – 缓存资源为本地资源,因此加载速度较快。 60 | 61 | - 服务器负载更少 – 浏览器只会从发生了更改的服务器下载资源。 62 | 63 | 一个简单的离线页面主要包含以下几个部分: 64 | 65 | index.html 66 | 67 | ```html 68 | 69 | 70 | AppCache Test 71 | 72 | 73 | 74 | 75 |

    76 | 77 | 78 |

    79 |
    80 |
    81 | 82 | 83 | ``` 84 | 85 | test.manifest 86 | 87 | manifest 文件是简单的文本文件,它告知浏览器被缓存的内容(以及不缓存的内容)。 88 | 89 | manifest 文件可分为三个部分: 90 | 91 | - CACHE MANIFEST - 在此标题下列出的文件将在首次下载后进行缓存(必须) 92 | 93 | - NETWORK - 在此标题下列出的文件需要与服务器的连接,且不会被缓存 94 | 95 | - FALLBACK - 在此标题下列出的文件规定当页面无法访问时的回退页面(比如 404 页面) 96 | 97 | ```js 98 | CACHE MANIFEST 99 | /# 2012-02-21 v1.0.0 100 | /theme.css 101 | /logo.gif 102 | /main.js 103 | NETWORK: 104 | login.asp 105 | FALLBACK: 106 | /html5/ /404.html 107 | ``` 108 | 109 | clock.js和clock.css为独立的另外文件。 110 | 111 | 另外,需要注意的是更新缓存。在程序中,你可以通过window.applicationCache 对象来访问浏览器的app cache。你可以查看 status 属性来获取cache的当前状态: 112 | 113 | ```js 114 | var appCache = window.applicationCache; 115 | switch (appCache.status) { 116 | case appCache.UNCACHED: // UNCACHED == 0 117 | return 'UNCACHED'; 118 | break; 119 | case appCache.IDLE: // IDLE == 1 120 | return 'IDLE'; 121 | break; 122 | case appCache.CHECKING: // CHECKING == 2 123 | return 'CHECKING'; 124 | break; 125 | case appCache.DOWNLOADING: // DOWNLOADING == 3 126 | return 'DOWNLOADING'; 127 | break; 128 | case appCache.UPDATEREADY: // UPDATEREADY == 4 129 | return 'UPDATEREADY'; 130 | break; 131 | case appCache.OBSOLETE: // OBSOLETE == 5 132 | return 'OBSOLETE'; 133 | break; 134 | default: 135 | return 'UKNOWN CACHE STATUS'; 136 | break; 137 | }; 138 | ``` 139 | 140 | 为了通过编程更新cache,首先调用 applicationCache.update()。这将会试图更新用户的 cache(要求manifest文件已经改变)。最后,当 applicationCache.status 处于 UPDATEREADY 状态时, 调用applicationCache.swapCache(),旧的cache就会被置换成新的。 141 | 142 | ```js 143 | var appCache = window.applicationCache; 144 | appCache.update(); // Attempt to update the user’s cache. … 145 | if (appCache.status == window.applicationCache.UPDATEREADY) { 146 | appCache.swapCache(); // The fetch was successful, swap in the new cache. 147 | } 148 | ``` 149 | 150 | 这里是通过更新menifest文件来控制其它文件更新的。 151 | 152 | -------------------------------------------------------------------------------- /browser/tcp.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [TCP连接的三次握手,四次挥手](#TCP连接的三次握手,四次挥手) 4 | - [三次握手](#三次握手) 5 | - [四次挥手](#四次挥手) 6 | - [为什么关闭需要四次](#为什么关闭需要四次) 7 | - [TCP窗口](#TCP窗口) 8 | - [TCP拥塞控制](#TCP拥塞控制) 9 | - [慢启动,拥塞控制](#慢启动,拥塞控制) 10 | - [快重传,快恢复](#快重传,快恢复) 11 | --- 12 | 13 | 14 | 15 | 16 | 17 | ## TCP连接的三次握手,四次挥手 18 | 19 | 20 | 21 | ### 三次握手 22 | 23 | 24 | 25 | ![](http://blog.chinaunix.net/attachment/201304/8/22312037_1365405910EROI.png) 26 | 27 | 28 | 29 | 30 | 31 | 1. 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。 32 | 33 | 2. 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。 34 | 35 | 3. 第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。 36 | 37 | 38 | 39 | 40 | 41 | ### 四次挥手 42 | 43 | 44 | 45 | ![](http://blog.chinaunix.net/attachment/201304/9/22312037_1365503104wDR0.png) 46 | 47 | 48 | 49 | 50 | 51 | 由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。 52 | 53 | 54 | 55 | 1. 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。 56 | 57 | 2. 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。 58 | 59 | 3. 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。 60 | 61 | 4. 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。 62 | 63 | 64 | 65 | 66 | 67 | ### 为什么关闭需要四次 68 | 69 | 70 | 71 | TCP建立连接要进行3次握手,而断开连接要进行4次,这是由于TCP的半关闭造成的,因为TCP连接是全双工的(即数据可在两个方向上同时传递)所以进行关闭时每个方向上都要单独进行关闭,这个单方向的关闭就叫半关闭. 72 | 73 | 74 | 75 | 关闭的方法是一方完成它的数据传输后,就发送一个FIN来向另一方通告将要终止这个方向的连接.当一端收到一个FIN,它必须通知应用层TCP连接已终止了这个方向的数据传送,发送FIN通常是应用层进行关闭的结果. 76 | 77 | 78 | 79 | 我的理解: 80 | 81 | 由于TCP是全双工的,当一方发起关闭请求的时候,说明一方没有可以传送的数据了,己方确认OK,告诉对方可以关闭你那边的连接(只是不发送,还可以接收)。但是我这边还可能有数据发送,所以等我这边需要关闭连接的时候,我会再发送FIN报文,告诉对方,我这里也没什么想说的了。所以FIN和ACK一般是分开发送的 82 | 83 | 84 | 85 | 86 | 87 | ### TCP窗口 88 | 89 | 90 | 91 | TCP默认以1段为单位发送数据,每一段需要接收一个确认,这样的效率比较低下,所以引入了滑动窗口的概念。窗口大小是无需等待就可发送的最大单位。当接受的应答后,窗口会滑动到对应的应答序号。所以,就算中途有几个ACK的回复丢失了。但是接收到了序号更大的ACK报文。那么依然可以确认之前的数据都接受了。所以窗口可以直接滑动。 92 | 93 | 94 | 95 | 如果某一段数据真的丢失了,那么发送端会一直收到该序号的应答,表示“我需要收到该序号报文, 你老给我发其他的干嘛?”,当连续3次收到这样的报文后,发送端会将对应的数据重发。 96 | 97 | 98 | 99 | ![](https://gss1.bdstatic.com/9vo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=f5e2be9ad388d43fe4a499a01c77b97e/42166d224f4a20a44fc2252895529822730ed004.jpg) 100 | 101 | 102 | 103 | ### TCP拥塞控制 104 | 105 | 有了窗口的概念后,收发主机发送的数据就不再是以一个段为单位了。可能会发送大量数据包,但是如果通信刚开始就发送大量数据包,可能会阻塞其他通信。当网络出现阻塞的时候,如果突然发送大量数据,可能会导致网络瘫痪。 106 | 107 | 108 | 109 | 所以为了解决这个问题,引入了一个慢启动的概念,对发送数据进行控制。 110 | 111 | 1. 慢开始、拥塞控制 112 | 113 | 2. 快重传、快恢复 114 | 115 | 116 | 117 | #### 慢启动,拥塞控制 118 | 119 | 1. 发送方维持一个叫做“拥塞窗口”的变量,该变量和接收端口共同决定了发送者的发送窗口; 120 | 121 | 2. 当主机开始发送数据时,避免一下子将大量字节注入到网络,造成或者增加拥塞,选择发送一个1字节的试探报文; 122 | 123 | 3. 当收到第一个字节的数据的确认后,就发送2个字节的报文; 124 | 125 | 4. 若再次收到2个字节的确认,则发送4个字节,依次递增2的指数级; 126 | 127 | 5. 最后会达到一个提前预设的“慢开始门限”,比如24,即一次发送了24个分组,此时遵循下面的条件判定: 128 | 129 | 1. cwnd < ssthresh, 继续使用慢开始算法; 130 | 131 | 2. cwnd > ssthresh,停止使用慢开始算法,改用拥塞避免算法; 132 | 133 | 3. cwnd = ssthresh,既可以使用慢开始算法,也可以使用拥塞避免算法; 134 | 135 | 6. 所谓拥塞避免算法就是:每经过一个往返时间RTT就把发送方的拥塞窗口+1,即让拥塞窗口缓慢地增大,按照线性规律增长; 136 | 137 | 7. 当出现网络拥塞,比如丢包时,将慢开始门限设为原先的一半,然后将cwnd设为1,执行慢开始算法(较低的起点,指数级增长); 138 | 139 | 140 | 141 | ![](http://blog.chinaunix.net/attachment/201402/17/26275986_1392629245IG6b.png?_=3554182) 142 | 143 | 144 | 145 | 146 | 147 | #### 快重传,快恢复 148 | 149 | 150 | 151 | 1. 接收方建立这样的机制,如果一个包丢失,则对后续的包继续发送针对该包的重传请求; 152 | 153 | 2. 一旦发送方接收到三个一样的确认,就知道该包之后出现了错误,立刻重传该包; 154 | 155 | 3. 此时发送方开始执行“快恢复”算法: 156 | 157 | 1. 慢开始门限减半; 158 | 159 | 2. cwnd设为慢开始门限减半后的数值; 160 | 161 | 3. 执行拥塞避免算法(高起点,线性增长); 162 | 163 | ![](http://blog.chinaunix.net/attachment/201402/17/26275986_1392629231ue0O.png?_=3554182) 164 | 165 | -------------------------------------------------------------------------------- /overall/cache.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [Web缓存](#Web缓存) 4 | - [缓存分类](#缓存分类) 5 | - [浏览器的缓存机制](#浏览器的缓存机制) 6 | - [缓存策略](#缓存策略) 7 | - [存储策略](#存储策略) 8 | - [过期策略](#过期策略) 9 | - [对比策略](#对比策略) 10 | - [用户操作行为与缓存](#用户操作行为与缓存) 11 | - [太多的304](#太多的304) 12 | - [5. 总结](#5-总结) 13 | - [参考文章](#参考文章) 14 | --- 15 | 16 | # Web缓存 17 | 18 | 在前端开发中,性能一直都是被大家所重视的一点,然而判断一个网站的性能最直观的就是看网页打开的速度。其中提高网页反应速度的一个方式就是使用缓存。一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。 19 | 20 | ## 缓存分类 21 | 22 | Web缓存有: 23 | 24 | 1. 数据库缓存 25 | 26 | 2. 代理服务器缓存(共享缓存) 27 | 28 | 3. CDN缓存 29 | 30 | 4. 浏览器缓存 31 | 32 | ## 浏览器的缓存机制 33 | 34 | 浏览器会分别从三个方面定义缓存: 35 | 36 | 1. 是否需要缓存副本(缓存存储策略) 37 | 38 | 2. 缓存副本是否过期(缓存过期策略); 39 | 40 | 3. 与服务器验证缓存副本是否可用(缓存对比策略)如下图: 41 | 42 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1500796319004) 43 | 44 | ### 缓存策略 45 | 46 | 页面的缓存状态是由`header`决定的,header的参数有四种。 47 | 48 | - cache-control (替代pragma) 49 | 50 | - expires (被cache-control里的max-age替代) 51 | 52 | - last-modified 53 | 54 | - etag (替代last-modified) 55 | 56 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1500797355879) 57 | 58 | ## 存储策略 59 | 60 | 由上图可以看出:`no-store`,`no-cache`,`max-age`这三个消息头的字段由服务器返回给浏览器,其中no-cache,max-age表示需要缓存副本, 61 | 62 | **no-store则表示不必缓存到副本之中。** 63 | 64 | **no-cache表示每次在向客户端(浏览器)提供响应数据时,缓存都要向服务器评估缓存响应的有效性。** 65 | 66 | **no-cache的目的是防止从缓存中返回过期信息** 67 | 68 | 可能有人会问为什么no—cache还会缓存,这里通过实验加上自己的理解为:服务器返回no-cache浏览器缓存之后第二次请求会带上no-cache字段表示不使用缓存,必须与服务器进行验证,如果验证命中(对比策略中会提到)还是会返回304状态码使用缓存副本的。一定要与no-store分清楚啊。 69 | 70 | ## 过期策略 71 | 72 | 缓存过期策略主要跟两字消息的字段由关 73 | 74 | - `Expires(http 1.0)` : 过期绝对时间(零时区,是服务器返回的时间,可能会有时间误差) 75 | 76 | - `max-age(http 1.1)` : **在http1.1中优先级高**,随着而来的max-age(单位为s)就能解决这个问题,当时间为相对时间而且相对的是服务器返回的时间所以不会出现有误差,并且max-age和Expires同时存在的时候max-age权值更大,Expires将失效。 77 | 78 | 其中还有一个启发式过期策略:当Expires和max-age这两个字段都不存在的时候,会根据服务器返回时间Date和文件最后修改时间last-modified差值的百分之十作为过期时间。 79 | 80 | ## 对比策略 81 | 82 | 当缓存在设定的时间过期之后,会发送请求给服务器,但是这不代表缓存就真的“过期”,如果请求的文件到现在 还能用服务器会直接返回304状态码,告诉浏览器继续使用缓存副本从而节省了发送消息题的带宽。 83 | 84 | 对于对比策略主要与两对字段有关分别为 85 | 86 | - last-Modified,if-Modified-since 87 | 88 | - Etag,if-None-Match。服务器返回的hash值(**优先级高**) 89 | 90 | 在response中:服务器返回last-Modified,和Etag字段给浏览器,在response中 91 | 92 | 在request中:当浏览器需要与服务器进行验证时用`if-Modified-since`和`if-None-Match`两个字段带上上次返回的last-Modified,Etag字段进行比对。(把response的那两个字段复制过来) 93 | 94 | 比对成功返回304,不成功则重新返回请求文件状态码为200。与存储策略一样两个字段有优先级,当有Etag时则只需要比对Etag。 95 | 96 | Etag主要解决几个Last-Modified比较难解决的问题: 97 | 98 | 1. 某些服务器不能精确得到资源的最后修改时间; 99 | 100 | 2. 如果资源修改非常频繁,且在秒以下的时间内进行修改; 101 | 102 | 3. 一些资源的最后修改事件改变了,但是内容没有改变; 103 | 104 | ## 用户操作行为与缓存 105 | 106 | 说清了过期策略结合下图说明用户使用浏览器的时候,对缓存的操作的影响。 107 | 108 | 操作行为对缓存的影响 109 | 110 | | **用户操作** | **Expires/Cache-Control** | **Last-Modified/Etag** | 111 | 112 | | ------------- | ------------------------- | ---------------------- | 113 | 114 | | **地址栏回车** | 有效 | 有效 | 115 | 116 | | **页面链接跳转** | 有效 | 有效 | 117 | 118 | | **新开窗口** | 有效 | 有效 | 119 | 120 | | **前进、后退** | 有效 | 有效 | 121 | 122 | | **F5刷新** | 无效 | 有效 | 123 | 124 | | **Ctrl+F5刷新** | 无效 | 无效 | 125 | 126 | 关于`F5`和`Ctrl+F5`强制刷新的说明 127 | 128 | - F5主要是在请求头里加上一个max-age:0,由于max-age权限最高,设置为0则表示过期策略失效必须与服务器进行验证如果验证成功则会返回304继续使用缓存。 129 | 130 | - Ctrl+F5强制刷新则会在请求头里添加Cache-control:no-cache和Param:no-cache表示无论如何都不会使用缓存副本,必须重新返回最新文件并覆盖原先缓存副本。 131 | 132 | ## 太多的304 133 | 134 | 由于F5刷新所有请求都会重新发送一遍,尽管我们知道太多的文件修改的可能性很低。 135 | 136 | 为了解决这个问题,firefox和chorme有各自的优化,比如firefox会在Cache-control:max-age后面添加immutable字段,表示f5刷新永远不会设置max-age:0 这样会继续使用副本。 137 | 138 | 而chorme则在max-age值较大的情况下都不会去设置max-age为0减少一些不必要的请求 139 | 140 | ## 5. 总结 141 | 142 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1500799067808) 143 | 144 | ## 参考文章 145 | 146 | http://www.alloyteam.com/2016/03/discussion-on-web-caching/ 147 | 148 | [【缓存技术原理】浏览器端缓存机制详解](http://blog.csdn.net/moshenglv/article/details/52020563) 149 | 150 | http://www.cnblogs.com/skynet/archive/2012/11/28/2792503.html 151 | 152 | http://web.jobbole.com/82997/ 153 | 154 | http://www.alloyteam.com/2012/03/web-cache-1-web-cache-overview/ 155 | 156 | -------------------------------------------------------------------------------- /about_js/sameorigin.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [同源策略 和 部分其他跨域方法](#同源策略-和-部分其他跨域方法) 4 | - [不严格的同源策略](#不严格的同源策略) 5 | - [跨域资源共享(CORS)](#跨域资源共享CORS) 6 | - [跨文档消息](#跨文档消息) 7 | - [nginx反向代理 ](#nginx反向代理-) 8 | - [图像Ping](#图像Ping) 9 | - [JSONP](#JSONP) 10 | - [comet](#comet) 11 | - [websocket](#websocket) 12 | - [window.name跨域](#windowname跨域) 13 | - [参考资料](#参考资料) 14 | --- 15 | 16 | > 这部分大部分是张贵旭同学整理的(https://github.com/zhangguixu) 17 | 18 | ## 同源策略 和 部分其他跨域方法 19 | 20 | 同源策略是对JavaScript代码能够操作哪些Web内容的一条完整的安全限制。具体来说,脚本只能读取和所属文档来源相同的窗口和文档的属性。 21 | 22 | 文档来源 23 | 24 | 协议 主机 端口 25 | 26 | *脚本本身的来源和同源策略并不相关,相关的是脚本所嵌入的文档的来源* 27 | 28 | 作用场景 29 | 30 | 1. 使用多个 31 | 32 | 2. 打开其他浏览器窗口 33 | 34 | 3. 使用XmlHttpRequest 35 | 36 | ## 不严格的同源策略 37 | 38 | ### 子域问题(document.domian) 39 | 40 | 同源策略给使用多个子域的大站点带来一些问题。 41 | 42 | 例如:来自 `home.example.com` 的文档里的脚本想要合法地读取`developer.example.com`载入的文档的属性 43 | 44 | 为了支持这种类型的多域名站点,可以使用Document对象的`domain`属性。在默认情况下,domain存放的是载入文档的服务器的主机名。可以设置这一属性,不过使用的字符串必须具有有效的域前缀或它本身。 45 | 46 | ```javascript 47 | //设置home.example.com的文档 48 | document.domain = 'example.com'; 49 | //设置developer.example.com的文档 50 | document.domain = 'example.com'; 51 | ``` 52 | 53 | 这样,两个子域就具有同源性,就可以互相读取对方的属性了。 54 | 55 | *domain值中必须有一个点号,不能设置为com或其他顶级域名。* 56 | 57 | ### 跨域资源共享(CORS) 58 | 59 | Cross-Origin Resource Sharing这项技术已经成为一项标准,参见:[http://www.w3.org/TR/cors/](http://www.w3.org/TR/cors/) 60 | 61 | 这个标准对HTTP进行扩展: 62 | 63 | 1. 新的`Origin:`请求头 64 | 65 | 2. 新的`Access-Control-Allow-Origin`响应头 66 | 67 | 它允许服务器用头信息显示地列出源,或使用通配符来匹配所有源并允许跨域HTTP请求,已经运用到`XMLHttpRequest Level 2`。这样就不会被同源策略所限制了。 68 | 69 | 但是默认跨域请求是不提供凭据的(coookie,ssl证明),通过把`withCredentials`属性设为true可以执行某个请求发送凭证。如果服务器接受,可以用以下http头响应 70 | 71 | Access-Control-Allow-Credentials:true 72 | 73 | ### 跨文档消息 74 | 75 | 跨文档消息(cross-document messaging),允许来自一个文档的脚本可以传递文本消息到另一个文档里的脚本,而不管脚本的来源是否不同。调用window对象的`postMessage()`,方法,可以异步传递消息,利用`onmessage`事件处理函数来处理它。采用`域判断`来确定信任源。 76 | 77 | **注意:** 貌似只对使用iframe或者window.open打开的窗口有效。直接用window.postMessage到别的域无效 78 | 79 | postMessage第二个参数可以为'*' ,这样可以不管对方的网址是否对应。否则发送目的要对应的网址。 80 | 81 | event对象中比较重要的就是:`event.data`是数据,`event.orgin`是来源地址, 82 | 83 | `window.parent.postMessage('msg from child','*') `可以从frame里向父亲发信息 84 | 85 | ```javascript 86 | //window.open方式 87 | var pop = window.open('http://www.example.com/') 88 | pop.postMessage('hello','http://www.example.com') 89 | //文档A发送消息给文档B 90 | chatFrame.contentWindow.postMessage('hello','http://www.example.com/') 91 | //文档B监听message事件 92 | window.addEventListener('message',messageHandler,true); 93 | function messageHandler(e){ 94 | if(checkWhiteList(e.origin)){ 95 | //处理消息 96 | processMessage(e.data); 97 | 98 | }else{ 99 | //忽略来自未知源的消息 100 | } 101 | //进行源的判断 102 | var originWhiteList=['portal.example.com','games.example.com', 103 | 'www.example.com']; 104 | function checkWhiteList(origin){ 105 | var i; 106 | for(i = 0;i < originWhiteList.length;i++){ 107 | if(origin === originWhiteList[i]){ 108 | return true 109 | } 110 | } 111 | return false; 112 | ``` 113 | 114 | ### nginx反向代理 115 | 116 | nginx反向代理 这个方法一般很少有人提及,但是他可以不用目标服务器配合,不过需要你搭建一个中转nginx服务器,用于转发请求 117 | 118 | ### 图像Ping 119 | 120 | 利用图像的src标签跨域,一般用来做跟踪用户点击或者动态广告曝光次数。 121 | 122 | 缺点: 123 | 124 | - 只能发送get请求 125 | 126 | - 无法访问服务器响应文本 127 | 128 | ### JSONP 129 | 130 | 详情见[jsonp](/about_js/jsonp.md) 131 | 132 | ### comet 133 | 134 | 详情见[comet](/about_js/comet.md) 135 | 136 | ### websocket 137 | 138 | 详情见[websocket](/about_js/websocket.md) 139 | 140 | ### window.name跨域 141 | 142 | 通过window.open打开一个窗口,第二个参数就是name,另一个窗口通过window.name就可以拿到这个值。 143 | 144 | 或者使用iframe打开网页,传递name 145 | 146 | window.name 传输技术,原本是 Thomas Frank 用于解决 cookie 的一些劣势(每个域名 4 x 20 Kb 的限制、数据只能是字符串、设置和获取 cookie 语法的复杂等等)而发明的 147 | 148 | window.name 的美妙之处:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。 149 | 150 | window.name原理: 151 | 152 | ![](http://www.planabc.net/wp-content/uploads/2008/08/windowname.png) 153 | 154 | ![](http://www.planabc.net/wp-content/uploads/2008/08/windowname.png) 155 | 156 | ## 参考资料 157 | 158 | [https://github.com/zhangguixu/front-end](https://github.com/zhangguixu/front-end) 159 | 160 | [使用 window.name 解决跨域问题](http://www.planabc.net/2008/09/01/window_name_transport/) 161 | 162 | [HTML5 postMessage 和 onmessage API 详细应用](https://www.ibm.com/developerworks/cn/web/1301_jiangjj_html5message/) 163 | 164 | -------------------------------------------------------------------------------- /about_js/extend.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [目录](#目录) 4 | - [对象的构造](#对象的构造) 5 | - [继承](#继承) 6 | - [create实现方法](#create实现方法) 7 | - [es6的class](#es6的class) 8 | - [参考文章](#参考文章) 9 | --- 10 | 11 | ## 目录 12 | 13 | --- 14 | 15 | - [对象的构造](#对象的构造) 16 | 17 | - [继承](#继承) 18 | 19 | - [es6的class](#es6的class) 20 | 21 | - [create实现方法](#create实现方法) 22 | 23 | - [参考文章](#参考文章) 24 | 25 | --- 26 | 27 | 28 | 29 | ## 对象的构造 30 | 31 | 32 | 33 | 根据红宝书上的介绍,一共有7种方法 34 | 35 | 36 | 37 | - 工厂模式 38 | 39 | 40 | 41 | - 构造函数模式 42 | 43 | 44 | 45 | - 组合模式 46 | 47 | 48 | 49 | - 动态原型模式 50 | 51 | 52 | 53 | - 寄生构造函数模式 54 | 55 | 56 | 57 | - 稳妥构造函数模式 58 | 59 | 60 | 61 | ```js 62 | 构造对象的方法 63 | //////////////// 工厂模式 64 | function createA(name){ 65 | var a = new A(); 66 | a.name = name; 67 | a.say = function(){ 68 | console.log(this.name); 69 | } 70 | return a; 71 | } 72 | //////////////// 一般是组合使用构造函数和原型模式 73 | //构造函数式 74 | // -没有显式构造 75 | // -可以实现对象检测 76 | // -可以初始化变量 77 | // 属性没有存在原型上,只跟自己有关不共享 78 | function A(name) { 79 | this.name = name; 80 | this.haha = 'haha'; 81 | } 82 | //原型模式(用于构造函数,防止多次实例化函数) 83 | // 原型对象属性都是共享的,所以用来定义属性不合适(特别是引用类型) 84 | A.prototype.say = function(){ 85 | console.log(this.name); 86 | // or 87 | A.prototype = { 88 | constructor:A, //如果constructor真的很重要的话(不过这样会导致constructor是enumerable) 89 | sayName:function(){ 90 | console.log(this.name); 91 | } 92 | //////////////// 动态模式(把原型放在构造函数内部,加判断只第一次使用的时候执行) 93 | function A(name) { 94 | this.name = name; 95 | if(typeof this.sayName != "function"){ //只是判断原型是否初始化创建了这些方法 96 | A.prototype.sayName = function(){ 97 | console.log(this.name); 98 | } 99 | A.prototype.…… 100 | } 101 | //////////////// 寄生模式,类似工厂模式,只是返回了值 102 | function SpecialArray(){ 103 | var value = new Array(); 104 | value.push.apply(value,arguments); 105 | value.newMethod = function(){}; 106 | return value; 107 | } 108 | ``` 109 | 110 | 111 | 112 | ## 继承 113 | 114 | 115 | 116 | 红宝书提到的继承方式有以下几种 117 | 118 | 119 | 120 | - 原型链 121 | 122 | 123 | 124 | - 借用构造函数 125 | 126 | 127 | 128 | - 组合继承 129 | 130 | 131 | 132 | - 原型式继承 133 | 134 | 135 | 136 | - 寄生式继承 137 | 138 | 139 | 140 | - 寄生组合式继承 141 | 142 | 143 | 144 | es6之后可以用class继承 145 | 146 | 147 | 148 | ```js 149 | 继承的方法 150 | // 组合继承(问题是两次调用父类的构造函数) 151 | // 1. 借用构造函数 首先把A的属性继承过来(解决超类引用类型变量被共享问题,解决无法向超类传递参数问题) 152 | function B(name,age){ 153 | A.call(this,name); 154 | this.age = age; 155 | } 156 | //修改B的原型,指向A,继承A的方法 157 | B.prototype = new A(); 158 | //修改B原型的constructor 159 | B.prototype.constructor = B; 160 | //定义B自己的方法 161 | B.prototype.sayhi = function(){ 162 | console.log('hi'); 163 | // 寄生组合式继承(圣杯继承) 最优方式!!! 164 | // 1. 借用构造函数 165 | function B(name,age){ 166 | A.call(this,name); 167 | this.age = age; 168 | // 2. 调用寄生继承 169 | inherit(B,A); 170 | //定义B自己的方法 171 | B.prototype.sayhi = function(){ 172 | console.log('hi'); 173 | } 174 | 175 | function inherit(subType,superType){ 176 | var prototype = Object.create(superType.prototype); //专门有个中间函数来传递原型链(不损坏super原型,又能添加方法) 177 | prototype.constructor = subType; 178 | subType.prototype = prototype; 179 | } 180 | ``` 181 | 182 | 183 | 184 | ## create实现方法 185 | 186 | 187 | 188 | ```js 189 | // create实现方法 190 | function create(A){ 191 | function F(){}; 192 | F.prototype = A; 193 | return new F(); 194 | } 195 | var a = new A('a'); 196 | var b = new B('b'); 197 | ``` 198 | 199 | 200 | 201 | ## es6的class 202 | 203 | 204 | 205 | 利用class实现继承 206 | 207 | 208 | 209 | 下面利用ES6引入的新语法糖,class、extends关键字对上述实现继承的代码进行改写: 210 | 211 | 212 | 213 | ```js 214 | class Person { 215 | constructor (name, age) { 216 | this.name = name; 217 | this.age = age; 218 | } 219 | sayName () { 220 | console.log('my name is ' + this.name); 221 | } 222 | } 223 | class Student extends Person { 224 | constructor (name, age, school) { 225 | super(name, age); 226 | this.school = school; 227 | } 228 | saySchool () { 229 | console.log('my school is ' + this.school); 230 | } 231 | } 232 | ``` 233 | 234 | 235 | 236 | class里的constructor 对应原来的构造函数 237 | 238 | 239 | 240 | class里面的其他方法都是写在原来构造函数的prototype中的 241 | 242 | 243 | 244 | 子类直接通过extends 关键字进行继承 245 | 246 | 247 | 248 | 子类中可以通过super来调用父类中的方法 249 | 250 | 251 | 252 | ## 参考文章 253 | 254 | 255 | 256 | 《javascript高级程序设计》 257 | 258 | 259 | 260 | [彻底理解Javascript中的原型链与继承](https://segmentfault.com/a/1190000007906832) 261 | 262 | 263 | 264 | [白话解释 Javascript 原型继承(prototype inheritance)](https://segmentfault.com/a/1190000008226777) 265 | 266 | 267 | 268 | -------------------------------------------------------------------------------- /about_html/viewport.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [viewport简介](#viewport简介) 4 | - [layout viewport](#layout-viewport) 5 | - [visual viewport](#visual-viewport) 6 | - [ideal viewport](#ideal-viewport) 7 | - [viewport特性](#viewport特性) 8 | - [width](#width) 9 | - [height](#height) 10 | - [initial-scale](#initial-scale) 11 | - [maximum-scale](#maximum-scale) 12 | - [minimum-scale](#minimum-scale) 13 | - [user-scalable](#user-scalable) 14 | - [参考文章](#参考文章) 15 | --- 16 | 17 | ## viewport简介 18 | 19 | 没错,就是`viewport`特性,一个移动专属的`Meta`值,用于定义视口的各种行为。 20 | 21 | 该特性最先由`Apple`引入,用于解决移动端的页面展示问题,后续被越来越多的厂商跟进。 22 | 23 | 举个简单的例子来讲为什么会需要它: 24 | 25 | 我们知道用户大规模使用手机等移动设备来进行网页浏览器,其实得益于智能手持设备的兴起,也就是近几年的事。(还记得不久前的几年,满大街都还是诺基亚的天下么?) 26 | 27 | 这时有一个很现实的问题摆在了厂商面前,用户并不能很好地通过手机等设备访问网页,因为屏幕太小。 28 | 29 | ### layout viewport 30 | 31 | `Apple`也发现了这个问题,并且适时的出现,它提出了一个方案用来解决这个问题。在iOS Safari中定义了一个`viewport meta`标签,用来创建一个虚拟的`布局视口(layout viewport)`,而这个视口的分辨率接近于PC显示器,`Apple`将其定义为`980px`(其他厂商各有不同①)。 32 | 33 | 这就很好的解决了早期的页面在手机上显示的问题,由于两者之间的宽度趋近,CSS只需要像在PC上那样渲染页面就行,原有的页面结构不会被破坏。 34 | 35 | > ①的描述大致如下,数值不一定持续准确,厂商可能更改,但这个绝对值其实并非特别重要: 36 | 37 | > iOS, Android基本都是: 980px 38 | 39 | > BlackBerry: 1024px 40 | 41 | ### visual viewport 42 | 43 | 有了`layout viewport`,我们还需要一个视口用来承载它,这个视口可以简单的认为是手持设备物理屏幕的可视区域,我们称之为`(视觉视口)visual viewport`。这是一个比较直观的概念,因为你能看得见你的手机屏幕。 44 | 45 | 对于`visual viewport`,开发者一般只需要知道它的存在和概念就行,因为无法对它进行任何设置或者修改。很明显,`visual viewport`的尺寸不会是一个固定的值,甚至每款设备都可能不同。大致列几种常见设备的`visual viewport`尺寸: 46 | 47 | - iPhone4~iPhone5S: 320*480px 48 | 49 | - iPhone6~iPhone6S: 375*627px 50 | 51 | - iPhone6 Plus~iPhone6S Plus: 414*736px 52 | 53 | 以`iPhone4S`为例,会在其320px②的`visual viewport`上,创建一个宽`980px`的`layout viewport`,于是用户可以在`visual viewport`中拖动或者缩放网页,来获得良好的浏览效果;布局视口用来配合CSS渲染布局,当我们定义一个容器的宽度为`100%`时,这个容器的实际宽度是`980px`而不是`320px`,通过这种方式大部分网页就能以缩放的形式正常显示在手机屏幕上了。 54 | 55 | > ②的描述大致如下: 56 | 57 | > 早期移动前端开发工程师常能见到宽640px的设计稿,原因就是UI工程师以物理屏幕宽度为320px的`iPhone4-iPhone5S`作为参照设计; 58 | 59 | > 当然,现在你还可能会见到750px和1242px尺寸的设计稿,原因当然是iPhone6的出现 60 | 61 | 当然,为了更好的适配移动端或者只为移动端设计的应用,单有布局视口和视觉视口还是不够的。 62 | 63 | ### ideal viewport 64 | 65 | 我们还需要一个视口,它类似于布局视口,但宽度和视觉视口相同,这就是完美视口(ideal viewport)。 66 | 67 | 有了完美视口,用户不用缩放和拖动网页就能够很好的进行网页浏览。而完美视口也是通过`viewport meta`的某种设置来达到。 68 | 69 | 说了这么一大堆的东西,貌似都和`viewport`有关联,那么`viewport`到底怎么搞,请继续往下。 70 | 71 | > 关于3个视口,PPK已经做了非常棒的阐释,你也可以在`StackOverflow`上找到一些对此描述的相互补充,例如:[1], [2],有兴趣的童鞋也可以看看 72 | 73 | ## viewport特性 74 | 75 | 通常情况下,`viewport`有以下6种设置。当然厂商可能会增加一些特定的设置,比如iOS Safari7.1增加了一种在网页加载时隐藏地址栏与导航栏的设置:`minimal-ui`,不过随后又将之移除了。 76 | 77 | | Name | Value | Description | 78 | 79 | | ------------- | ------------------- | -------------------------------- | 80 | 81 | | width | 正整数或`device-width` | 定义视口的宽度,单位为像素 | 82 | 83 | | height | 正整数或`device-height` | 定义视口的高度,单位为像素 | 84 | 85 | | initial-scale | [0.0-10.0] | 定义初始缩放值 | 86 | 87 | | minimum-scale | [0.0-10.0] | 定义缩小最小比例,它必须小于或等于maximum-scale设置 | 88 | 89 | | maximum-scale | [0.0-10.0] | 定义放大最大比例,它必须大于或等于minimum-scale设置 | 90 | 91 | | user-scalable | yes/no | 定义是否允许用户手动缩放页面,默认值yes | 92 | 93 | ### width 94 | 95 | `width`被用来定义`layout viewport`的宽度,如果不指定该属性(或者移除`viewport meta`标签),则`layout viewport`宽度为厂商默认值。如:iPhone为`980px`; 96 | 97 | 举个例子: 98 | 99 | 此时的`layout viewport`将成为`ideal viewport`,因为`layout viewport`宽度与设备视觉视口宽度一致了。 100 | 101 | 除了`width`之外,还有一个属性定义也能实现`ideal viewport`,那就是`initial-scale`。 102 | 103 | ### height 104 | 105 | 与`width`类似,但实际上却不常用,因为没有太多的use case。 106 | 107 | ### initial-scale 108 | 109 | 如果想页面默认以某个比例放大或者缩小然后呈现给用户,那么可以通过定义`initial-scale`来完成。 110 | 111 | `initial-scale`用于指定页面的初始缩放比例,假定你这样定义: 112 | 113 | 那么用户将会看到2倍大小的页面内容。 114 | 115 | 在说`width`的时候,我们说到`initial-scale`也能实现`ideal viewport`,是的,你只需要这样做,也可以得到完美视口: 116 | 117 | ### maximum-scale 118 | 119 | 在移动端,你可能会考虑用户浏览不便,然后给予用户放大页面的权利,但同时又希望是在一定范围内的放大,这时就可以使用`maximum-scale`来进行约束。 120 | 121 | `maximum-scale`用于指定用户能够放大的比例。 122 | 123 | 举个例子来讲: 124 | 125 | 假设页面的默认缩放值`initial-scale`是`1`,那么用户最终能够将页面放大到这个初始页面大小的5倍。 126 | 127 | ### minimum-scale 128 | 129 | 类似`maximum-scale`的描述,不过`minimum-scale`是用来指定页面缩小比例的。 130 | 131 | 通常情况下,为了有更好地体验,不会定义该属性的值比`1`更小,因为那样页面将变得难以阅读。 132 | 133 | ### user-scalable 134 | 135 | 如果你不想页面被放大或者缩小,通过定义`user-scalable`来约束用户是否可以通过手势对页面进行缩放即可。 136 | 137 | 该属性的默认值为`yes`,即可被缩放(如果使用默认值,该属性可以不定义);当然,如果你的应用不打算让用户拥有缩放权限,可以将该值设置为`no`。 138 | 139 | 使用方法如下: 140 | 141 | ```html 142 | 143 | ``` 144 | 145 | ### 参考文章 146 | 147 | [移动前端第一弹:viewport详解](http://blog.doyoe.com/2015/10/13/mobile/%E7%A7%BB%E5%8A%A8%E5%89%8D%E7%AB%AF%E7%AC%AC%E4%B8%80%E5%BC%B9%EF%BC%9Aviewport%E8%AF%A6%E8%A7%A3/) 148 | 149 | -------------------------------------------------------------------------------- /interview/p1.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [一道经典的js面试题](#一道经典的js面试题) 4 | - [答](#答) 5 | - [代码执行前](#代码执行前) 6 | - [执行"第一行"代码](#执行"第一行"代码) 7 | - [执行"第二行"代码](#执行"第二行"代码) 8 | - [执行"第三行"代码](#执行"第三行"代码) 9 | - [执行"第四行"代码(第一问)](#执行"第四行"代码第一问) 10 | - [执行"第五行"代码(第二问)](#执行"第五行"代码第二问) 11 | - [执行"第六行"代码(第三问)](#执行"第六行"代码第三问) 12 | - [执行"第七行"代码(第四问)](#执行"第七行"代码第四问) 13 | - [执行"最后三行"代码(第五、六、七问)](#执行"最后三行"代码第五、六、七问) 14 | --- 15 | 16 | # 一道经典的js面试题 17 | 18 | ## 题 19 | 20 | ```js 21 | function Foo(){ 22 | getName = function () {alert(1);} 23 | return this; 24 | } 25 | Foo.getName = function() {alert(2);}; 26 | Foo.prototype.getName = function(){alert(3);}; 27 | var getName = function(){alert(4);}; 28 | function getName(){alert(5)}; 29 | Foo.getName(); 30 | getName(); 31 | Foo().getName(); 32 | getName(); 33 | new Foo.getName(); 34 | new Foo().getName(); 35 | new new Foo().getName(); 36 | ``` 37 | 38 | ## 答 39 | 40 | ```js 41 | 2 ----Foo.getName(); 42 | 4 ----getName(); 43 | 1 ----Foo().getName(); 44 | 1 ----getName(); 45 | 2 ----new Foo.getName(); 46 | 3 ----new Foo().getName(); 47 | 3 ----new new Foo().getName(); 48 | ``` 49 | 50 | ## 代码执行前 51 | 52 | 首先,由于函数表达式会提前,`function getName(){alert(5)};` 53 | 54 | 上述代码未执行时,变量对象是这样的。 55 | 56 | ```js 57 | VO = { 58 | Foo: { 59 | , 60 | return this 61 | } 62 | getName: 63 | } 64 | ``` 65 | 66 | ### 执行"第一行"代码 67 | 68 | ![img](https://segmentfault.com/img/bVsWb1) 69 | 70 | 该行代码执行后VO会变成这样。 71 | 72 | ```js 73 | VO = { 74 | Foo: { 75 | , 76 | getName: 80 | } 81 | ``` 82 | 83 | VO的Foo图示是这样的 84 | 85 | ![img](https://segmentfault.com/img/bVsWcr) 86 | 87 | ### 执行"第二行"代码 88 | 89 | ![img](https://segmentfault.com/img/bVsWcw) 90 | 91 | 该行代码执行后VO会变成这样。 92 | 93 | ``` 94 | VO = { 95 | Foo: { 96 | , 97 | getName: 105 | } 106 | ``` 107 | 108 | VO的Foo图示是这样 109 | 110 | ![img](https://segmentfault.com/img/bVsWcR) 111 | 112 | ### 执行"第三行"代码 113 | 114 | ![img](https://segmentfault.com/img/bVsWcV) 115 | 116 | 该行代码执行后VO会变成这样。 117 | 118 | ``` 119 | VO = { 120 | Foo: { 121 | , 122 | getName: 129 | } 130 | ``` 131 | 132 | ### 执行"第四行"代码(第一问) 133 | 134 | ![img](https://segmentfault.com/img/bVsWc3) 135 | 136 | 直接去VO里寻找结果发现alert 2。 137 | 138 | ### 执行"第五行"代码(第二问) 139 | 140 | ![img](https://segmentfault.com/img/bVsWdc) 141 | 142 | ``` 143 | getName() //等于 144 | window.getName(); 145 | ``` 146 | 147 | 同样直接在VO里可以直接找到答案 alert 4。 148 | 149 | ### 执行"第六行"代码(第三问) 150 | 151 | ![img](https://segmentfault.com/img/bVsWdh) 152 | 153 | 这里比上述多了一个函数调用,Foo()调用返回this(指向window),所以此时 154 | 155 | ``` 156 | Foo().getName(); //等于 157 | window.getName() 158 | ``` 159 | 160 | 同时注意: 161 | 162 | 由于Foo()调用,导致VO发生了变化。最后alert 1. 163 | 164 | ``` 165 | VO = { 166 | Foo: { 167 | , 168 | getName: 175 | } 176 | ``` 177 | 178 | ### 执行"第七行"代码(第四问) 179 | 180 | ![img](https://segmentfault.com/img/bVsWdo) 181 | 182 | 结果同上 183 | 184 | ### 执行"最后三行"代码(第五、六、七问) 185 | 186 | ![img](https://segmentfault.com/img/bVsWdW) 187 | 188 | 最后三问考察了new、属性访问符、及函数调用优先顺序和new运算符的作用。 189 | 190 | `优先顺序`参考如下,或[点这](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) 191 | 192 | ![img](https://segmentfault.com/img/bVsWd9) 193 | 194 | 无论是用哪种属性访问表达式,在"."和"[]"之前的表达式总是会先计算的。 195 | 196 | 对于`new Foo.getName()`来说,点运算级最高,所以先进行计算`表达式`Foo的值。如果先运算new的话,就证明了new优先级高于点号,与规范不和。 197 | 198 | 而对于`new Foo().getName()`来说,Foo()与new Foo()相比,new优先级更高,所以先算new Foo(),new出来的新对象`继承`了Foo.prototype属性,因此新对象访问getName时会弹出3. 199 | 200 | 此处要明白new的作用 201 | 202 | 1. 创建新的空对象 203 | 204 | 2. 将新对象继承构造函数的prototype属性,并调用构造函数初始化 205 | 206 | 3. 将构造函数的this指针指向新建对象。 207 | 208 | 最后一个问题同理倒数第二个。 209 | 210 | -------------------------------------------------------------------------------- /about_js/program.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [如何实现sum(1,2),sum(1)(2)](#如何实现sum1,2,sum12) 4 | - [如何实现数组去重](#如何实现数组去重) 5 | - [如何实现深浅拷贝](#如何实现深浅拷贝) 6 | - [如何实现页面关闭通知后台](#如何实现页面关闭通知后台) 7 | - [如何删除数组中的多个特定元素(必须用splice)](#如何删除数组中的多个特定元素必须用splice) 8 | - [求数组中的最大,最小值](#求数组中的最大,最小值) 9 | - [如何扁平化数组](#如何扁平化数组) 10 | - [如何实现(2).plus(3).minus(1) //4](#如何实现2plus3minus1-//4) 11 | - [如何判断一个字符串是回文串](#如何判断一个字符串是回文串) 12 | - [如何实现任意进制转换](#如何实现任意进制转换) 13 | --- 14 | 15 | ## 如何实现sum(1,2),sum(1)(2) 16 | 17 | 这个函数的关键难点在与sum(1)(2),其实我们可以很容易的想到闭包,这就是很经典的闭包实现,只要返回一个函数就可以连续调用,关键是如何取得最后的总和值?这里就涉及到对toString和valueOf进行改造。 18 | 19 | ```js 20 | var sum = function () { 21 | var total = 0; 22 | // 先初始化值 23 | total = [].reduce.call(arguments, (a, b) => a + b); 24 | function tmp() { 25 | //用reduce方法可以不管参数的个数,进行累加 26 | total += [].reduce.call(arguments, (a, b) => a + b); 27 | return tmp; //一定要把自己返回出去,不然无法实现链式调用了 28 | } 29 | //因为是不断的返回函数,所以,如果需要输出或求值的时候,需要调用toString和valuOf 30 | tmp.toString = function () { 31 | return total; 32 | } 33 | tmp.valueOf = function () { 34 | return total; 35 | } 36 | return tmp; 37 | console.log(sum(1,2,3)); 38 | console.log(sum(1)(2,3)); 39 | ``` 40 | 41 | ## 如何实现数组去重 42 | 43 | ```js 44 | var array = [1,2,3,02,'02',true,'true',{a:1},'{a:1}',{a:1}] 45 | var newArr = []; 46 | ``` 47 | 48 | 1. 用Set 49 | 50 | ```js 51 | [...new Set(array)] 52 | ``` 53 | 54 | 2. 用Map 55 | 56 | ```js 57 | //用map 58 | var m = new Map(); 59 | array.forEach(e =>{ 60 | if(!m.has(e)){ 61 | newArr.push(e); 62 | m.set(e,1); 63 | } 64 | console.log(newArr); 65 | ``` 66 | 67 | 3. 用Object,需要做一些判断(object的key只能是字符串,需要区分本身是字符串和类型转换成字符串) 68 | 69 | ```js 70 | //用Set 71 | [...new Set(array)] 72 | console.log([...new Set(array)]); 73 | //用Object 74 | newArr = []; 75 | var tmpObj = {}; 76 | array.forEach((e,idx) =>{ 77 | var tmpVal = e; 78 | switch(typeof(e)){ 79 | case 'string' : tmpVal = 's'+e; //保证string元素不和Number和Boolean元素一样 80 | break; 81 | case 'object' : tmpVal = 'o'+idx+e; //保证每个ojbect元素都不一样 82 | } 83 | if(!tmpObj[tmpVal]){ 84 | newArr.push(e); 85 | tmpObj[tmpVal] = 1; 86 | } 87 | console.log(newArr); 88 | ``` 89 | 90 | ## 如何实现深浅拷贝 91 | 92 | 1. 浅拷贝 93 | 94 | 父对象修改方法,会影响子对象 95 | 96 | **注意:** Object.assign就是浅拷贝,只拷贝一层!深层对象不拷贝 97 | 98 | ```js 99 | function extendCopy(p) {     100 | var c = {};     101 | for (var i in p) {       102 | c[i] = p[i];     103 | }     104 | c.uber = p;     105 | return c;   106 | ``` 107 | 108 | 2. 深拷贝: 109 | 110 | 比较简单的实现是直接使用JSON.stringify和parse 111 | 112 | ```js 113 | var cloneObj = function(obj){ 114 | var str, newobj = obj.constructor === Array ? [] : {}; 115 | if(typeof obj !== 'object'){ 116 | return; 117 | } else if(window.JSON){ 118 | str = JSON.stringify(obj), //系列化对象 119 | newobj = JSON.parse(str); //还原 120 | } else { 121 | for(var i in obj){ 122 | newobj[i] = typeof obj[i] === 'object' ? 123 | cloneObj(obj[i]) : obj[i]; 124 | } 125 | } 126 | return newobj; 127 | ``` 128 | 129 | ## 如何实现页面关闭通知后台 130 | 131 | 1. 定时发送心跳 132 | 133 | ```js 134 | setInterval(function () { 135 | //send meg to server 136 | },1000) 137 | ``` 138 | 139 | 2. onbeforeunload()事件 140 | 141 | ```js 142 | window.onbeforeunload = function(){ 143 | //send msg to server 144 | return 'close'; //必须要返回,有的浏览器会用这个文字作提示,但是chrome用默认的 145 | ``` 146 | 147 | 一个判断页面是否真的关闭和刷新的好方法: 148 | 149 | ```js 150 | window.onbeforeunload=function (){ 151 | alert("===onbeforeunload==="); 152 | if(event.clientX>document.body.clientWidth && event.clientY < 0 || event.altKey){ 153 | alert("你关闭了浏览器"); 154 | }else{ 155 | alert("你正在刷新页面"); 156 | ``` 157 | 158 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1500819726098) 159 | 160 | ## 如何删除数组中的多个特定元素(必须用splice) 161 | 162 | 关键是要注意splice之后,arr的长度会变化 163 | 164 | ```js 165 | var arr = [1,2,4,4,6,7] 166 | var target = 4; 167 | for (var i = 0;arr[i];){ //如果i超过length,arr[i] = undefined, 或者用i < arr.length也行,length会动态变化 168 | if (arr[i] === target){ 169 | arr.splice(i,1); //此时不需要i移动,因为删除后等于i自动后移 170 | }else { 171 | i++; 172 | } 173 | ``` 174 | 175 | ## 求数组中的最大,最小值 176 | 177 | 可以使用reduce或者直接用Math.max 178 | 179 | ```js 180 | var arr = [1,2,4,4,6,7] 181 | //用reduce 182 | arr.reduce(function (a, b) { 183 | return a > b?a:b; 184 | //直接使用Math.max([value1[, value2[, ...]]]) 185 | Math.max.apply(null,arr); 186 | //扩展运算符 187 | Math.max(...arr); 188 | ``` 189 | 190 | ## 如何扁平化数组 191 | 192 | 数组的toString很神奇,可以扁平化数组 193 | 194 | ```js 195 | var arr = [1,2,[3,[4]]]; 196 | arr.toString() // 1,2,3,4 197 | var newArr = arr.toString().split(',').map( i => parseInt(i) ); 198 | ``` 199 | 200 | 我想了一个很另类的方法,用正则 201 | 202 | ```js 203 | var arr = [1,2,[3,[4]]]; 204 | var str = '[' + JSON.stringify(arr).replace(/[\[|\]]/g,'') + ']' 205 | var newArr = JSON.parse(str); 206 | ``` 207 | 208 | ## 如何实现(2).plus(3).minus(1) //4 209 | 210 | (2).plus,其实是调用Number的plus方法,数字通过包装对象可以使用相应的方法,所以只用把Number的原型中加入相应的方法就行了 211 | 212 | ```js 213 | Number.prototype.plus = function(x){return this + x;} 214 | Number.prototype.minus = function(x){return this - x;} 215 | ``` 216 | 217 | ## 如何判断一个字符串是回文串 218 | 219 | ```js 220 | function isPalindrome(str){ 221 | return str === str.split('').reverse().join(''); 222 | } 223 | ``` 224 | 225 | ## 如何实现任意进制转换 226 | 227 | parseInt(x,N)可以把N进制的数转换成10进制。 228 | 229 | toString(N)可以把任意10进制的数转换成对应进制字符串 230 | 231 | ```js 232 | //2进制转16进制 233 | parseInt('10110110',2).toString(16); 234 | ``` 235 | 236 | -------------------------------------------------------------------------------- /dom/dom.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [介绍](#介绍) 4 | - [获取DOM节点](#获取DOM节点) 5 | - [孩子节点](#孩子节点) 6 | - [兄弟节点](#兄弟节点) 7 | - [父亲节点](#父亲节点) 8 | - [更新](#更新) 9 | - [innerText / textContent](#innerText-/-textContent) 10 | - [属性](#属性) 11 | - [style属性](#style属性) 12 | - [创建DOM](#创建DOM) 13 | - [插入DOM](#插入DOM) 14 | - [删除DOM](#删除DOM) 15 | - [文本操作](#文本操作) 16 | --- 17 | 18 | [TOC] 19 | 20 | # 介绍 21 | 22 | 由于HTML文档被浏览器解析后就是一棵DOM树,要改变HTML的结构,就需要通过JavaScript来操作DOM。 23 | 24 | 始终记住DOM是一个树形结构。操作一个DOM节点实际上就是这么几个操作: 25 | 26 | - 更新:更新该DOM节点的内容,相当于更新了该DOM节点表示的HTML的内容; 27 | 28 | - 遍历:遍历该DOM节点下的子节点,以便进行进一步操作; 29 | 30 | - 添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点; 31 | 32 | - 删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及它包含的所有子节点。 33 | 34 | ## 获取DOM节点 35 | 36 | 在操作一个DOM节点前,我们需要通过各种方式先拿到这个DOM节点。最常用的方法是 37 | 38 | - document.getElementById() : 唯一 39 | 40 | - document.getElementsByTagName() : 一组 41 | 42 | - document.getElementsByClassName() : 一组 (6 7 8不支持) 43 | 44 | - **querySelector**() :第一个出现的 (6 7 8不支持) 45 | 46 | - **querySelectorAll**() : 全部 (6 7 8不支持) 47 | 48 | ### 孩子节点 49 | 50 | - firstChild 51 | 52 | - lastChild 53 | 54 | - firstElementChild (带element的都是其他浏览器认识ie678不认) 55 | 56 | - lastElementChild 57 | 58 | - childNodes (它是**标准属性**,它返回指定元素的子元素集合,包括`HTML节点`,`所有属性`,`文本`节点 (嫡出)火狐谷歌等高本版会把**换行也看做是子节点**) 59 | 60 | - **children** (尽量用这个,只返回**元素节点(NodeType === 1)**) 61 | 62 | ### 兄弟节点 63 | 64 | - previousSlbling 获取已知节点的前一个节点 65 | 66 | - nextSibling 获取已知节点的下一个节点 67 | 68 | - nextElementSlbling (带element的都是其他浏览器认识ie678不认) 69 | 70 | - previousElementSlbling 71 | 72 | ### 父亲节点 73 | 74 | - **parentNode** 已知节点的父节点 75 | 76 | - parentElement (ie认,不用它了) 77 | 78 | ```js 79 | // 返回ID为'test'的节点: 80 | var test = document.getElementById('test'); 81 | // 先定位ID为'test-table'的节点,再返回其内部所有tr节点: 82 | var trs = document.getElementById('test-table').getElementsByTagName('tr'); 83 | // 先定位ID为'test-div'的节点,再返回其内部所有class包含red的节点: 84 | var reds = document.getElementById('test-div').getElementsByClassName('red'); 85 | // 获取节点test下的所有直属子节点: 86 | var cs = test.children; 87 | // 获取节点test下第一个、最后一个子节点: 88 | var first = test.firstElementChild; 89 | var last = test.lastElementChild; 90 | ``` 91 | 92 | 严格地讲,我们这里的DOM节点是指`Element`,但是DOM节点实际上是`Node`,在HTML中,`Node`包括`Element`、`Comment`、`CDATA_SECTION`等很多种,以及根节点`Document`类型,但是,绝大多数时候我们只关心`Element`,也就是实际控制页面结构的`Node`,其他类型的`Node`忽略即可。根节点`Document`已经自动绑定为全局变量`document`。 93 | 94 | ## 更新 95 | 96 | ### innerHTML 97 | 98 | 这个方式非常强大,不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树: 99 | 100 | ### innerText / textContent 101 | 102 | 第二种是修改innerText或textContent属性,这样可以自动对字符串进行HTML编码,保证无法设置任何HTML标签: 103 | 104 | 两者的区别在于读取属性时,innerText不返回隐藏元素的文本,而textContent返回所有文本。另外注意IE<9不支持textContent。 105 | 106 | ### 属性 107 | 108 | - getAttribute(属性名) 109 | 110 | - removeAttribute(属性名) 111 | 112 | - setAttribute(属性名,属性值) 113 | 114 | **有一些属性的值可以直接获取和修改**(标签默认就带的属性,比如id基本标签都带,还有img的src,input的value,name等) 115 | 116 | ### style属性 117 | 118 | 修改CSS也是经常需要的操作。DOM节点的`style`属性对应所有的CSS,可以直接获取或设置。因为CSS允许font-size这样的名称,但它并非JavaScript有效的属性名,所以需要在JavaScript中改写为驼峰式命名`fontSize`: 119 | 120 | ```js 121 | // 获取

    ...

    122 | var p = document.getElementById('p-id'); 123 | // 设置CSS: 124 | p.style.color = '#ff0000'; 125 | p.style.fontSize = '20px'; 126 | p.style.paddingTop = '2em'; 127 | ``` 128 | 129 | 或者直接使用style批量更新,用;分隔 130 | 131 | ```js 132 | // 获取

    ...

    133 | var p = document.getElementById('p-id'); 134 | // 设置CSS: 135 | p.style = "color:#ff0000;fontsize:20px"; 136 | ``` 137 | 138 | ## 创建DOM 139 | 140 | - **createElement** 141 | 142 | ```js 143 | document.createElement(‘img’) 144 | ``` 145 | 146 | - createAttribute 147 | 148 | ```js 149 | document.createAttribute('class') 150 | ``` 151 | 152 | - **createTextNode** 153 | 154 | ```js 155 | var h=document.createElement("H1") 156 | var t=document.createTextNode("Hello World"); 157 | h.appendChild(t); 158 | ``` 159 | 160 | ## 插入DOM 161 | 162 | 如果原来的DOM树为空,则可以直接使用InnerHTML进行添加,如果不为空则不行,会覆盖里面原来的节点 163 | 164 | - **appendChild** 165 | 166 | 直接把一个原来的节点插入新的位置 167 | 168 | ```js 169 | var 170 | js = document.getElementById('js'), 171 | list = document.getElementById('list'); 172 | list.appendChild(js); 173 | ``` 174 | 175 | - **insertBefore** 176 | 177 | 如果我们要把子节点插入到指定的位置怎么办?可以使用`parentElement.insertBefore(newElement, referenceElement);` 178 | 179 | ```js 180 | varlist = document.getElementById('list'), 181 | ref = document.getElementById('python'), 182 | haskell = document.createElement('p'); 183 | haskell.id = 'haskell'; 184 | haskell.innerText = 'Haskell'; 185 | list.insertBefore(haskell, ref); 186 | ``` 187 | 188 | - replaceChild 189 | 190 | replaceChild(要插入的新元素,被替换的元素) 191 | 192 | - **cloneNode** 193 | 194 | cloneNode(true[复制当前节点及其所有字节点],false[仅复制当前节点]) 195 | 196 | ## 删除DOM 197 | 198 | - **parentNode + removeChild** 199 | 200 | 要删除一个节点,首先要获得该节点本身以及它的父节点,然后,调用父节点的removeChild把自己删掉: 201 | 202 | ```js 203 | // 拿到待删除节点:var self = document.getElementById('to-be-removed'); 204 | // 拿到父节点:var parent = self.parentElement; 205 | // 删除:var removed = parent.removeChild(self); 206 | removed === self; // true 207 | ``` 208 | 209 | 注意: 删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置。 210 | 211 | ## 文本操作 212 | 213 | - insertData(offset,string) 从offset指定的位置插入string 214 | 215 | - appendData(string) 将string插入到文本结点的末尾处 216 | 217 | - deleteDate(offset,count) 从offset删除count个字符 218 | 219 | - replaceData(off,count,string) 从offset将count个字符。用string替代 220 | 221 | - splitData(offset) 从offset将文本结点分成两个节点 222 | 223 | - substring(offset,count) 返回由offset起得count个结点 224 | 225 | -------------------------------------------------------------------------------- /es6/let&const.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [目录](#目录) 4 | - [let & const](#let-&-const) 5 | - [重复定义会报错](#重复定义会报错) 6 | - [for的特殊性](#for的特殊性) 7 | - [无变量提升](#无变量提升) 8 | - [!暂时性死区(temporal dead zone,简称 TDZ)](#!暂时性死区temporal-dead-zone,简称-TDZ) 9 | - [typeof不再绝对安全](#typeof不再绝对安全) 10 | - [立即执行函数不必要](#立即执行函数不必要) 11 | - [不属于顶层对象](#不属于顶层对象) 12 | - [!const本质](#!const本质) 13 | - [参考文章](#参考文章) 14 | --- 15 | 16 | ## 目录 17 | 18 | --- 19 | 20 | - [let & const](#let-&-const) 21 | 22 | - [重复定义会报错](#重复定义会报错) 23 | 24 | - [for的特殊性](#for的特殊性) 25 | 26 | - [无变量提升](#无变量提升) 27 | 28 | - [!暂时性死区(temporal dead zone,简称 TDZ)](#!暂时性死区temporal-dead-zone,简称-TDZ) 29 | 30 | - [typeof不再绝对安全](#typeof不再绝对安全) 31 | 32 | - [立即执行函数不必要](#立即执行函数不必要) 33 | 34 | - [不属于顶层对象](#不属于顶层对象) 35 | 36 | - [!const本质](#!const本质) 37 | 38 | - [参考文章](#参考文章) 39 | 40 | --- 41 | 42 | 43 | 44 | ## let & const 45 | 46 | 47 | 48 | let和const注意:只有在`{}`中才有作用域(if单语句不加{} 不能用let) 49 | 50 | 51 | 52 | ```javascript 53 | if(1) let i = 1 54 | Uncaught SyntaxError: Unexpected identifier 55 | ``` 56 | 57 | 58 | 59 | const表示常量必须在**定义的时候赋值**,且**不能修改**,否则报错 60 | 61 | 62 | 63 | ### 重复定义会报错 64 | 65 | 66 | 67 | - let定义后,不能再用let,var,const重复定义 68 | 69 | 70 | 71 | - 先var再let可以 72 | 73 | 74 | 75 | - 传的参数名默认也是let定义的 76 | 77 | 78 | 79 | ```javascript 80 | // 报错 81 | function () { 82 | let a = 10; 83 | var a = 1; 84 | } 85 | // 不报错 86 | function () { 87 | var a = 10; 88 | let a = 1; 89 | } 90 | // 报错 91 | function () { 92 | let a = 10; 93 |  let a = 1; 94 | } 95 | function func(arg) { 96 |  let arg; // 报错 97 | } 98 | function func(arg) { 99 | { 100 | let arg; // 不报错 101 | } 102 | } 103 | ``` 104 | 105 | 106 | 107 | ### for的特殊性 108 | 109 | 110 | 111 | ```javascript 112 | for (var i = 0; i < 3; i++) { 113 | setTimeout(function(){console.log(i)},0) 114 | } 115 | //3 3 3 116 | for (let i = 0; i < 3; i++) { 117 | setTimeout(function(){console.log(i)},0) 118 | //0 1 2 119 | } 120 | ``` 121 | 122 | 123 | 124 | `for`循环还有一个特别之处,**就是循环语句部分是一个父作用域**,而循环体内部是一个单独的子作用域。 125 | 126 | 127 | 128 | ```js 129 | for (let i = 0; i < 3; i++) { 130 | let i = 'abc'; 131 | console.log(i); 132 | } 133 | ``` 134 | 135 | 136 | 137 | ### 无变量提升 138 | 139 | 140 | 141 | `let`命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。 142 | 143 | 144 | 145 | ```javascript 146 | // var 的情况 147 | console.log(foo); // 输出undefined 148 | var foo = 2; 149 | // let 的情况 150 | console.log(bar); // 报错ReferenceError 151 | let bar = 2; 152 | ``` 153 | 154 | 155 | 156 | ### !暂时性死区(temporal dead zone,简称 TDZ) 157 | 158 | 159 | 160 | 只要块级作用域内存在`let`命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。 161 | 162 | 163 | 164 | ```javascript 165 | var tmp = 123; 166 | if (true) { 167 | tmp = 'abc'; // ReferenceError 168 | let tmp; 169 | } 170 | if (true) { 171 | // TDZ开始 172 | tmp = 'abc'; // ReferenceError 173 | console.log(tmp); // ReferenceError 174 | let tmp; // TDZ结束 175 | console.log(tmp); // undefined 176 | tmp = 123; 177 | console.log(tmp); // 123 178 | } 179 | ``` 180 | 181 | 182 | 183 | ### typeof不再绝对安全 184 | 185 | 186 | 187 | 在没有`let`之前,`typeof`运算符是百分之百安全的,永远不会报错。现在这一点不成立了。如果一个变量用let申明,但是在typeof之后,typeof`运行时就会抛出一个`ReferenceError`。**参考暂时性死区** 188 | 189 | 190 | 191 | ### 立即执行函数不必要 192 | 193 | 194 | 195 | 块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。 196 | 197 | 198 | 199 | ```javascript 200 | // IIFE 写法 201 | (function () { 202 | var tmp = ...; 203 | ... 204 | }()); 205 | // 块级作用域写法 206 | let tmp = ...; 207 | ... 208 | ``` 209 | 210 | 211 | 212 | ### 不属于顶层对象 213 | 214 | 215 | 216 | `let`命令、`const`命令、`class`命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。 217 | 218 | 219 | 220 | ```javascript 221 | var a = 1; 222 | // 如果在Node的REPL环境,可以写成global.a 223 | // 或者采用通用方法,写成this.a 224 | window.a // 1 225 | let b = 1; 226 | window.b // undefined 227 | ``` 228 | 229 | 230 | 231 | ### !const本质 232 | 233 | 234 | 235 | `const`实际上保证的,并不是变量的值不得改动,**而是变量指向的那个内存地址不得改动**。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。 236 | 237 | 238 | 239 | 但对于引用类型(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,`const`只能保证这个指针是固定的,**至于它指向的数据结构是不是可变的,就完全不能控制了**。因此,**将一个对象声明为常量必须非常小心**。 240 | 241 | 242 | 243 | - 赋值操作不被运行 244 | 245 | 246 | 247 | - 修改对象操作可以进行!! 248 | 249 | 250 | 251 | ```javascript 252 | const foo = {}; 253 | // 为 foo 添加一个属性,可以成功 254 | foo.prop = 123; 255 | foo.prop // 123 256 | // 将 foo 指向另一个对象,就会报错 257 | foo = {}; // TypeError: "foo" is read-only 258 | ``` 259 | 260 | 261 | 262 | 上面代码中,常量`foo`储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把`foo`指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。 263 | 264 | 265 | 266 | 下面是另一个例子。 267 | 268 | 269 | 270 | ```javascript 271 | const a = []; 272 | a.push('Hello'); // 可执行 273 | a.length = 0; // 可执行 274 | a = ['Dave']; // 报错 275 | ``` 276 | 277 | 278 | 279 | 上面代码中,常量`a`是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给`a`,就会报错。 280 | 281 | 282 | 283 | 如果真的想将对象冻结,应该使用`Object.freeze`方法。 284 | 285 | 286 | 287 | ```javascript 288 | const foo = Object.freeze({}); 289 | // 常规模式时,下面一行不起作用; 290 | // 严格模式时,该行会报错 291 | foo.prop = 123; 292 | ``` 293 | 294 | 295 | 296 | 上面代码中,常量`foo`指向一个冻结的对象,所以添加新属性不起作用,严格模式时还会报错。 297 | 298 | 299 | 300 | 除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。 301 | 302 | 303 | 304 | ```javascript 305 | var constantize = (obj) => { 306 | Object.freeze(obj); 307 | Object.keys(obj).forEach( (key, i) => { 308 | if ( typeof obj[key] === 'object' ) { 309 | constantize( obj[key] ); 310 | } 311 | }); 312 | ``` 313 | 314 | 315 | 316 | ## 参考文章 317 | 318 | 319 | 320 | [ECMAScript 6 入门](http://es6.ruanyifeng.com/) 321 | 322 | 323 | 324 | -------------------------------------------------------------------------------- /overall/introduce.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [自我介绍](#自我介绍) 4 | - [为什么选vue,vue和react和angular的区别是什么](#为什么选vue,vue和react和angular的区别是什么) 5 | --- 6 | 7 | 8 | 9 | ## 自我介绍 10 | 11 | 12 | 13 | 我叫黄锴,目前在中国科学院大学读研二,明年毕业。目前在搜狐实习,实习大致3-4个月,在搜狐负责一个2C端的项目——搜狐焦点经纪人版块的开发。然后组内目前就我一个前端。所以,基本上是一个人负责所有的前端业务。目前还负责维护搜狐焦点的IM插件。该插件是一个用vue写的。然后平时的话,自己会做一些小项目,比如豆瓣客,英语阅读器,内部使用的周报系统。 14 | 15 | 16 | 17 | 项目难点的话,说实话,我接触的项目难点大多都是业务难点。业务难点多起来,就多了去了,业务上的问题,大多都有变通的方式。比如要 18 | 19 | 20 | 21 | - 因为显示问题大多都不是用的原生的控件:比如我们项目里就要自制select(hover),Input的placeholder不支持ie9,table需要固定宽度,有时候用div就会比较方便。 22 | 23 | - 比较奇葩需求还有**控制内容显示两行**。 24 | 25 | - hover图片变化(设置两张背景图,在hover的时候切换background-img样式,但是会出现闪动,因为是动态加载的,改成使用一张图,切换position就会好很多) 26 | 27 | - 联想搜索(引入**防抖动**)。吸顶。实现页面栏。 28 | 29 | - 动态加载内容时候,过度加载。(加锁) 30 | 31 | - 点赞反馈。 32 | 33 | - 还有一些移动端的问题(300ms和点击穿越,去除点击区域的黄框,还有fixed顶在输入框出来的时候,会失效,固定页面大小) 34 | 35 | - 布局问题,不能使用flex。(从这里**引入flex**) 36 | 37 | - ugly代码调试问题(fiddler) 38 | 39 | 40 | 41 | 技术难点,说实话应该也是有很多的,但是我之前一直都没记录下来。就讲讲最近遇到的吧,都是ie9的问题。就是ie9没有console对象。导致页面整体死掉。 42 | 43 | 44 | 45 | 还有ie9的跨域问题。ie9下无法实现CORS方式跨域。可以使用jsonp解决。或者使用iframe跨域。(**引入跨域**) 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 还有,其实我觉得遇到的技术难点都还好,沟通才是我目前发现最大的难点。前端和后台的沟通,一个接口设计的合理不合理,数据到底是前端取还是后台塞。需求是否合理 54 | 55 | 56 | 57 | - 设计稿是否能实现(量像素问题,是用padding,margin,还是line-height),我自己的经验是:一般来说,明显能看出区域之间的间隔使用margin,但是margin有个问题经常首尾的内容距离其他部分还有一部分的margin,这时候通过计算就很麻烦,最好就直接通过使用margin塌陷(引入**margin塌陷**)。其他的尽量使用padding,不存在塌陷问题。然后line-height一般设置成1:1的关系,方便测量。但是难在多段文字的时候,得通过line-height做出间隔,但是line-height撑开行盒后,段落与其他区域间的距离,就要通过手动计算了。 58 | 59 | 60 | 61 | [scroll优化之防抖与节流](https://segmentfault.com/a/1190000007676390) 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | ## 为什么选vue,vue和react和angular的区别是什么 76 | 77 | 78 | 79 | 只要我面试就一直会被问到这个问题,我私下也查过很多react,angular的特点,和vue的对比。 80 | 81 | 82 | 83 | - 有种说法是angular和vue是强化html,而react是强化js,angular和vue强调的是vm层,利用模板引擎语法,把数据和视图绑定起来。而react是把html嵌入了js中。 84 | 85 | 86 | 87 | - angular和vue都是双向数据绑定,react是单向数据流。但是angular是脏检查机制,不断的watch。在watcher过多的时候,效率低。vue是通过get和set,相对来说效率会高一些。 88 | 89 | 90 | 91 | - react是用JSX语法,而且高度组件化。vue也是提倡组件化。他们两个都没内置核心工具,比如ajax,router,需要进行加载,angular就内置。 92 | 93 | 94 | 95 | - react依赖虚拟dom来做脏检查 96 | 97 | 98 | 99 | ​ 100 | 101 | 102 | 103 | 但是,说实话,我现在知道这些又有什么意义呢?最后,其实不是我决定用什么,而是业务决定的。如果我去了公司,公司用react,那我就从头开始学react呗,反正开发都是看文档。 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 其实说实话,三个框架都是主流的框架,目前来看,大家都发展的很好,也不见得谁要取代谁。而且我觉得**学框架不是为了学而学,而是为了解决问题而学**。如果抛开效率问题,我大可以用原生js去做当时的一切(我也这么做过),大不了自己遇到问题,多造几个轮子,或者用现有的轮子。**我觉得框架这东西,没有最好的,适合的就是最好的。**我当时为什么选择vue,很简单,我对比了一圈,大家都说vue上手简单,而我的需求是什么?是快速构建一款应用。我不需要考虑那么多。我用vue,也只是因为它用起来确实很方便,双向绑定很舒服。模板语法很简单。而且vue2.0也引入了虚拟dom的概念,vue是一个新生儿,意味着它可以吸取react和angular的优点。 112 | 113 | 114 | 115 | 已经了解到vue是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的,无疑这个方法是本文中最重要、最基础的内容之一,如果不熟悉defineProperty,猛戳这里 116 | 整理了一下,要实现mvvm的双向绑定,就必须要实现以下几点: 117 | 1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者 118 | 2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数 119 | 3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图 120 | 4、mvvm入口函数,整合以上三者 121 | ![](https://segmentfault.com/img/bVBQYu) 122 | 123 | 124 | 125 | # 坑 126 | 127 | ## es6 128 | 129 | ### let 130 | 131 | - let和const注意:只有在`{}`中才有作用域(**if单语句不加{} 不能用let**) 132 | 133 | - let定义后,不能再用let,var,const重复定义(先var再let可以),传的**参数名默认也是let**定义的 134 | 135 | - `for`循环还有一个特别之处,**就是循环语句部分是一个父作用域**,而循环体内部是一个单独的子作用域。 136 | 137 | - 无变量提升 138 | 139 | - 暂时性死区TDZ(在{}内部定义之后,在这个块里let定义之前访问这个变量会报`ReferenceError`的错) 140 | 141 | ```js 142 | var tmp = 123; 143 | if (true) { 144 | tmp = 'abc'; // ReferenceError 145 | let tmp; 146 | } 147 | ``` 148 | 149 | - typeof不再绝对安全(因为TDZ) 150 | 151 | - 不属于顶层对象 152 | 153 | - **const只保护地址**(对象内部属性不保证) 154 | 155 | 156 | 157 | ### 箭头 158 | 159 | - 没有this,this会一直查找(对箭头函数用bind,apply,call改变this无效) 160 | 161 | 162 | 163 | ## 类型转换 164 | 165 | 166 | 167 | ``` 168 | parseInt("") //NaN 注意和Number不同,Number("") -> 0 169 | ``` 170 | 171 | - 几乎任何值都有的`toString()`(**除了null和undefined**),但是!String(),**可以将所有的类型转换成字符串**,它会先调用toString(),不能转换(null,undefined)的再特殊处理,不能更改进制。(**字符串的+操作就是利用这个**) 172 | 173 | ``` 174 | String(10) // "10" 175 | String(null) //"null" 176 | String(undefined) //"undefined" 177 | null.toString //报错 178 | ``` 179 | 180 | - Object默认转换成"[object Object]",**除非手动实现了toString函数** 181 | 182 | ### == 和 === 183 | 184 | - == 如果是同一类型,直接比较(**对象比较指针,永远不相等**) 185 | 186 | - null和undefined和非这两者的值,都为false 187 | 188 | - Number和String, String=>Number 189 | 190 | - Boolean和其他类型,Boolean=>Number(0,1) 191 | 192 | - Number,String和Object, Ojbect调用valueOf或toString 193 | 194 | > Object默认转换成"[object Object]",除非手动实现了toString函数 195 | > 196 | > **数组会扁平化!!** 197 | > 198 | > []转换成"" 199 | > 200 | > [1]转换成"1" 201 | > 202 | > [1,2,[3,4],5]转换成"1,2,3,4,5" 203 | 204 | 205 | 206 | `margin-top`和`margin-bottom`对**非替换行内元素无效** 207 | 208 | padding的百分比计算和margin一样,都**只与父亲的width有关** 209 | 210 | ★border设置的时候,**最少需要设置一个样式** 211 | 212 | 边框宽度**默认medium** 213 | 214 | 边框**颜色默认值**为`color`值 215 | 216 | 217 | 218 | 注意:对于那些包**含块基于一个块级元素的绝对定位的元素**,百分比根据**这个元素的padding box的高度来计算**。这与CSS1不同,(CSS1中)百分比总是根据父级元素的*content box*来计算. 219 | 220 | 221 | 222 | 宽度**初始值为auto** 223 | 224 | 225 | 226 | margin塌陷 227 | 228 | 1. 都属于**流内**(in-flow)[**块级盒**](https://github.com/hk029/front-end/blob/master/about_css/fc.md#%E5%9D%97%E7%BA%A7%E5%85%83%E7%B4%A0Block-level-elements%E4%B8%8E%E5%9D%97%E7%BA%A7%E7%9B%92Block-level-boxes) ,处于**同一个**[块格式化上下文**BFC**](https://github.com/hk029/front-end/blob/master/about_css/fc.md) 229 | 2. **没有行盒** (line box),**没有空隙(clearance)**,**没有padding**并且**没有border把它们隔开**(注意,因此某些0高度行盒会被忽略) 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /about_js/this.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [this与作用域](#this与作用域) 4 | - [基本认识](#基本认识) 5 | - [函数有所属对象时:指向所属对象](#函数有所属对象时指向所属对象) 6 | - [(在全局)普通函数调用:指向全局对象](#在全局普通函数调用指向全局对象) 7 | - [构造器中的 this:指向新对象](#构造器中的-this指向新对象) 8 | - [箭头函数this](#箭头函数this) 9 | - [apply 和 call 调用以及 bind 绑定:指向绑定的对象](#apply-和-call-调用以及-bind-绑定指向绑定的对象) 10 | - [this关键字的核心](#this关键字的核心) 11 | - [this使用技巧](#this使用技巧) 12 | - [2. 闭包中的this](#2-闭包中的this) 13 | - [3. 借用方法(类数组常用)](#3-借用方法类数组常用) 14 | - [万物皆对象](#万物皆对象) 15 | - [鸭子类型](#鸭子类型) 16 | - [参考文章](#参考文章) 17 | --- 18 | 19 | 目录: 20 | 21 | [this](#this与作用域) 22 | 23 | # this与作用域 24 | 25 | ## this 26 | 27 | ### 基本认识 28 | 29 | 每个函数在调用的时候,都会自动获取两个特殊变量:`this`和`arguments`,内部函数在搜索这两个变量时,只会搜索到其活动对象为止。 30 | 31 | 所以,我们把this关键字当成一个快捷方式,或者说是引用(reference)。this关键字指向的是**当前上下文(context)** 的主体(subject),或者当前正在被执行的代码块的主体。this关键字始终指向一个对象并持有这个对象的值,尽管它可以出现在全局范围(global scope)以外的地方,但它通常出现在方法体中。 32 | 33 | **注意:** 严格模式(strict mode)下,全局使用this关键字时,this将会指向undefined。 34 | 35 | 除去不常用with和eval情况,实际中this指向大概可以分为4类 36 | 37 | - 对象方法调用 38 | 39 | - 普通函数调用 40 | 41 | - 构造器调用 42 | 43 | - apply,call,bind调用 44 | 45 | ### 函数有所属对象时:指向所属对象 46 | 47 | 函数有所属对象时,通常通过 . 表达式调用,这时 this 自然指向所属对象。比如下面的例子: 48 | 49 | ```js 50 | window.value = 'window' 51 | var myObject = {value: 'myobject'}; 52 | myObject.getValue = function () { 53 | return this.value; 54 | console.log(myObject.getValue()); 55 | // 输出 myobject 56 | ``` 57 | 58 | 属于对象 myObject,并由**myOjbect 进行调用** (体会这句话的含义),因此 this 指向对象 myObject。 59 | 60 | ### (在全局)普通函数调用:指向全局对象 61 | 62 | 只要是不作为对象的属性被调用的时候,我们就称为普通函数调用,默认都是指向全局对象(浏览器中是window,node中是global) 63 | 64 | 注意:setTimeout这类函数,this都是全局 65 | 66 | ```js 67 | window.value = 'window' 68 | var myObject = {value: 'myobject'}; 69 | myObject.getValue = function () { 70 | var foo = function () { 71 | console.log(this); 72 | }; 73 | foo(); // 输出全局对象 window 74 | return this.value; 75 | } 76 | var getValue = myObject.getValue; 77 | console.log(myObject.getValue()); // => myobject 78 | console.log(getValue()); // => window 79 | ``` 80 | 81 | 在上述代码块中,foo 函数虽然定义在 getValue 的函数体内,但实际上它既不属于 getValue 也不属于 myObject。foo 并没有被绑定在任何对象上,所以当调用时,它的 this 指针指向了全局对象 global。 82 | 83 | 这也是为什么不能使用下面代码的原因 84 | 85 | ```js 86 | var getId = document.getElementById 87 | getId('div1') 88 | ``` 89 | 90 | 因为`document.getElementById`的实现用调了this 91 | 92 | (据说这是个设计错误。) 93 | 94 | ### 构造器中的 this:指向新对象 95 | 96 | js 中,我们通过`new`关键词来调用构造函数,此时`this`会绑定在该新对象上。 97 | 98 | ```js 99 | var SomeClass = function(){ 100 | this.value = 100; 101 | } 102 | var myCreate = new SomeClass(); 103 | console.log(myCreate.value); // 输出100 104 | ``` 105 | 106 | 顺便说一句,在 js 中,构造函数、普通函数、对象方法、闭包,这四者没有明确界线。界线都在人的心中。 107 | 108 | ### 箭头函数this 109 | 110 | 详细请看[箭头函数](../es6/arrow.md) 111 | 112 | ### apply 和 call 调用以及 bind 绑定:指向绑定的对象 113 | 114 | - apply(作用域,参数数组) : 适合在函数内直接直接把arguments传入 115 | 116 | - call(作用域,参数1,参数2...) : 比较符合平时函数调用 117 | 118 | - bind(作用域) 119 | 120 | 如果作用域传的是null,那默认绑定全局对象 121 | 122 | 注意:call和apply都是直接执行,但是bind是返回一个绑定了上下文的函数, 123 | 124 | ```js 125 | Function.prototype.bind = function (context) { 126 | var self = this; 127 | return function () { 128 | self.apply(context,arguments); 129 | } 130 | } 131 | ``` 132 | 133 | ```js 134 | var myObject = {value: 100}; 135 | //可以轻松实现借用方法(比如借用构造函数实现继承) 136 | var foo = function(){ 137 | console.log(this); 138 | } 139 | foo(); // 全局变量 global 140 | foo.apply(myObject); // { value: 100 } 141 | foo.call(myObject); // { value: 100 } 142 | var newFoo = foo.bind(myObject); 143 | newFoo(); // { value: 100 } 144 | ``` 145 | 146 | ### this关键字的核心 147 | 148 | 如果一个方法内部使用了this关键字,`当且仅当对象调用方法时this关键字才会被赋值`,而且,当方法被调用时,this的赋值又严格依赖于实际调用这个方法的对象,也就是说,`this通常会被赋予调用对象的值`。 149 | 150 | ### this使用技巧 151 | 152 | #### 1. 作为回调函数传入其他方法 153 | 154 | ```javascript 155 | var user = { 156 | name : 'zhang', 157 | clickHandler : function(){ 158 | console.log(this.name); 159 | } 160 | } 161 | button.onclick = user.clickHandler; //undefined,无法读取对象的name属性 162 | button.onclick = user.clickHandler.bind(user); 163 | button.onclick = function () { 164 | user.clickHandler(); 165 | } 166 | ``` 167 | 168 | #### 2. 闭包中的this 169 | 170 | 内部方法不能直接使用this关键字来访问外部方法的this变量,因为this变量只能被特定的方法本身使用。所以在使用含有匿名回调函数的参数时候,要特别注意this的指向。 171 | 172 | ```javascript 173 | var user = { 174 | tournament: "The Masters", 175 | data: [{ 176 | name: "T. Woods", 177 | age: 37 178 | }, 179 | { 180 | name: "P. Mickelson", 181 | age: 43 182 | }], 183 | clickHandler: function() { 184 | this.data.forEach(function(person) { 185 | console.log("What is This referring to? " + this); 186 | console.log(person.name + " is playing at " + this.tournament); 187 | }) 188 | }, 189 | clickHandler2: function() { 190 | //保存this对象 191 | var that = this; 192 | this.data.forEach(function(person) { 193 | console.log("What is This referring to? " + that); 194 | console.log(person.name + " is playing at " + that.tournament); 195 | }) 196 | } 197 | user.clickHandler(); // What is "this" referring to? [object Window] 198 | user.clickHandler2(); // What is "this" referring to? [object user] 199 | ``` 200 | 201 | #### 3. 借用方法(类数组常用) 202 | 203 | 类数组里是没有数组的方法的,因此可以借用数组的方法。 204 | 205 | ```javascript 206 | var arr = Array.prototype.slice.call(arguments,0) //之后就可以使用数组方法了 207 | [].forEach.call(arguments, function (element) { 208 | console.log(element) 209 | } 210 | ``` 211 | 212 | 类数组对象的实现原理 213 | 214 | ##### 万物皆对象 215 | 216 | 数组和函数的本质是对象,所有对象都可以调用对象的方法,使用点和方括号访问属性 217 | 218 | ##### 鸭子类型 219 | 220 | 如果它走起来像鸭子,叫起来像鸭子,那他就是鸭子 221 | 222 | 对比上述就是只要有length属性,就能当数组用 223 | 224 | ## 参考文章 225 | 226 | - 《javaScript语言精粹》 227 | 228 | - 《javascript设计模式与开发实践》 229 | 230 | - [Understand JavaScript’s “this” With Clarity, and Master It](http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it) 231 | 232 | -------------------------------------------------------------------------------- /es6/destructuring.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [变量解构](#变量解构) 4 | - [右边可以是字符串](#右边可以是字符串) 5 | - [右边不可遍历,出错](#右边不可遍历,出错) 6 | - [解构允许默认值](#解构允许默认值) 7 | - [对象型](#对象型) 8 | - [不在声明使用需要加括号](#不在声明使用需要加括号) 9 | - [嵌套对象](#嵌套对象) 10 | - [允许默认值](#允许默认值) 11 | - [类数组](#类数组) 12 | - [数字,布尔转换成对象](#数字,布尔转换成对象) 13 | - [用途](#用途) 14 | - [从函数返回多个值](#从函数返回多个值) 15 | - [函数参数的定义](#函数参数的定义) 16 | - [提取JSON数据](#提取JSON数据) 17 | - [参数默认值](#参数默认值) 18 | - [遍历Map结构(for..of)](#遍历Map结构forof) 19 | - [参考文章](#参考文章) 20 | --- 21 | 22 | # 变量解构 23 | 24 | ## 数组型 25 | 26 | 只要**形式一样就能结构成功**,右边多没事,右边少就会有`undefined` 27 | 28 | ```javascript 29 | let [foo, [[bar], baz]] = [1, [[2], 3]]; 30 | let [ , , third] = ["foo", "bar", "baz"]; //third "baz" 31 | let [head, ...tail] = [1, 2, 3, 4]; //head 1 //tail [2, 3, 4] 32 | let [x, y, ...z] = ['a']; //x "a" // y undefined // z [] 33 | ``` 34 | 35 | `...`表示rest元素数组。 36 | 37 | ### 右边可以是字符串 38 | 39 | 因为字符串是一个类数组(array-like),有length 40 | 41 | ```javascript 42 | const [a, b, c, d, e] = 'hello'; //a "h"// b "e" 43 | ``` 44 | 45 | ### 右边不可遍历,出错 46 | 47 | 如果等号的右边不是数组(或者严格地说,**不是可遍历的结构**,参见《Iterator》一章),那么将会报错。 48 | 49 | ```javascript 50 | // 报错 51 | let [foo] = 1; 52 | let [foo] = false; 53 | let [foo] = NaN; 54 | let [foo] = undefined; 55 | let [foo] = null; 56 | let [foo] = {}; 57 | ``` 58 | 59 | 事实上,只要某种数**据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。**Generator是原生具有iterator接口的 60 | 61 | ```javascript 62 | function* fibs() { 63 | let a = 0; 64 | let b = 1; 65 | while (true) { 66 | yield a; 67 | [a, b] = [b, a + b]; 68 | } 69 | let [first, second, third, fourth, fifth, sixth] = fibs(); 70 | sixth // 5 71 | ``` 72 | 73 | ### 解构允许默认值 74 | 75 | ES6 内部使用严格相等运算符(`===`),判断一个位置是否有值。所以,如果一个数组成员**不严格**等于`undefined`,默认值是不会生效的。(**比如null**) 76 | 77 | ```javascript 78 | let [foo = true] = []; // foo true 79 | let [x, y = 'b'] = ['a']; // x='a', y='b' 80 | let [x, y = 'b'] = ['a', undefined]; // x='a', y='b' 81 | let [x = 1] = [null]; //x null 82 | ``` 83 | 84 | ## 对象型 85 | 86 | 对象解构看**属性名**!如果变量名和属性名一致可以直接使用属性名,否则要用`属性名:变量名`取值(注意变量名放后面) 87 | 88 | > 其实可以看作通过属性名把值取出来,然后值解构到对应的变量上 89 | 90 | > 所以属性名只是模式 91 | 92 | ```javascript 93 | let { bar, foo } = { foo: "aaa", bar: "bbb" }; 94 | = let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" }; 95 | let { baz } = { foo: "aaa", bar: "bbb" }; //baz undefine 96 | var { foo: baz } = { foo: 'aaa', bar: 'bbb' }; //baz "aaa" 97 | let obj = { first: 'hello', last: 'world' }; 98 | let { first: f, last: l } = obj; //f 'hello' 99 | ``` 100 | 101 | ### 不在声明使用需要加括号 102 | 103 | 由于`{}`的二义性,所以在`{}`开头的特殊语句,需要加上`()` 104 | 105 | ```javascript 106 | let foo; 107 | {foo} = {foo: 1}; //报错 108 | ({foo} = {foo: 1}); // 成功 109 | ``` 110 | 111 | ### 嵌套对象 112 | 113 | 和数组一样,解构也可以用于嵌套结构的对象。 114 | 115 | ``` 116 | let obj = { 117 | p: [ 118 | 'Hello', 119 | { y: 'World' } 120 | ] 121 | let { p: [x, { y }] } = obj; 122 | ``` 123 | 124 | 注意,这时`p`是**模式**,不是变量,因此不会被赋值。 125 | 126 | ### 允许默认值 127 | 128 | ```javascript 129 | var {x = 3} = {}; 130 | x // 3 131 | var {x, y = 5} = {x: 1}; 132 | x // 1 133 | y // 5 134 | ``` 135 | 136 | ### 类数组 137 | 138 | 类似数组的对象都有一个`length`属性,因此还可以对这个属性解构赋值。 139 | 140 | ```javascript 141 | let {length : len} = 'hello'; 142 | len // 5 143 | let arr = [1, 2, 3]; 144 | let {0 : first, [arr.length - 1] : last} = arr; 145 | first // 1 146 | last // 3 147 | ``` 148 | 149 | ### 数字,布尔转换成对象 150 | 151 | 解构赋值时,如果等号右边是数值和布尔值,**则会先转为对象。** 152 | 153 | ```javascript 154 | let {toString: s} = 123; 155 | s === Number.prototype.toString // true 156 | let {toString: s} = true; 157 | s === Boolean.prototype.toString // true 158 | ``` 159 | 160 | 上面代码中,数值和布尔值的包装对象都有`toString`属性,因此变量`s`都能取到值。 161 | 162 | 解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于`undefined`和`null`无法转为对象,所以对它们进行解构赋值,都会报错。 163 | 164 | ```javascript 165 | let { prop: x } = undefined; // TypeError 166 | let { prop: y } = null; // TypeError 167 | ``` 168 | 169 | ## 用途 170 | 171 | ### 交换变量 172 | 173 | 写法不仅简洁,而且易读,语义非常清晰。 174 | 175 | ```javascript 176 | let x = 1; 177 | let y = 2; 178 | [x, y] = [y, x]; 179 | ``` 180 | 181 | ### 从函数返回多个值 182 | 183 | ```javascript 184 | // 返回一个数组 185 | function example() { 186 | return [1, 2, 3]; 187 | let [a, b, c] = example(); 188 | // 返回一个对象 189 | function example() { 190 | return { 191 | foo: 1, 192 | bar: 2 193 | }; 194 | let { foo, bar } = example(); 195 | ``` 196 | 197 | ### 函数参数的定义 198 | 199 | 解构赋值可以方便地将一组参数与变量名对应起来。 200 | 201 | ```javascript 202 | // 参数是一组有次序的值 203 | function f([x, y, z]) { ... } 204 | f([1, 2, 3]); 205 | // 参数是一组无次序的值 206 | function f({x, y, z}) { ... } 207 | f({z: 3, y: 2, x: 1}); 208 | ``` 209 | 210 | ### 提取JSON数据 211 | 212 | 解构赋值对提取JSON对象中的数据,尤其有用。 213 | 214 | ```javascript 215 | let jsonData = { 216 | id: 42, 217 | status: "OK", 218 | data: [867, 5309] 219 | let { id, status, data: number } = jsonData; 220 | console.log(id, status, number); 221 | // 42, "OK", [867, 5309] 222 | ``` 223 | 224 | ### 参数默认值 225 | 226 | ```javascript 227 | jQuery.ajax = function (url, { 228 | async = true, 229 | beforeSend = function () {}, 230 | cache = true, 231 | complete = function () {}, 232 | crossDomain = false, 233 | global = true, 234 | // ... more config 235 | }) { 236 | // ... do stuff 237 | ``` 238 | 239 | 指定参数的默认值,就避免了在函数体内部再写`var foo = config.foo || 'default foo';`这样的语句。 240 | 241 | ### 遍历Map结构(for..of) 242 | 243 | 任何部署了Iterator接口的对象,都可以用`for...of`循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便。 244 | 245 | ```javascript 246 | var map = new Map(); 247 | map.set('first', 'hello'); 248 | map.set('second', 'world'); 249 | for (let [key, value] of map) { 250 | console.log(key + " is " + value); 251 | // first is hello 252 | // second is world 253 | ``` 254 | 255 | 如果只想获取键名,或者只想获取键值,可以写成下面这样。 256 | 257 | ```javascript 258 | // 获取键名 259 | for (let [key] of map) { 260 | // ... 261 | // 获取键值 262 | for (let [,value] of map) { 263 | // ... 264 | ``` 265 | 266 | ## 参考文章 267 | 268 | [ECMAScript 6 入门](http://es6.ruanyifeng.com/) 269 | 270 | -------------------------------------------------------------------------------- /dom/size.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [目录](#目录) 4 | - [offset家族](#offset家族) 5 | - [offsetWidth | Height](#offsetWidth-|-Height) 6 | - [ offsetLeft | Top ](#-offsetLeft-|-Top-) 7 | - [ offsetParent](#-offsetParent) 8 | - [ offsetTop和style.top的区别](#-offsetTop和styletop的区别) 9 | - [scroll家族](#scroll家族) 10 | - [scrollTop scrollLeft](#scrollTop----scrollLeft) 11 | - [scrollWidth | scrollHeight](#scrollWidth-|-scrollHeight) 12 | - [怎么得到scrollTop](#怎么得到scrollTop) 13 | - [scrollTo(x,y)](#scrollTox,y) 14 | - [client家族](#client家族) 15 | - [检测屏幕宽度 (可视区域)](#检测屏幕宽度-可视区域) 16 | - [window.onresize 改变窗口事件 ](#windowonresize-改变窗口事件--) 17 | --- 18 | 19 | ## 目录 20 | 21 | --- 22 | 23 | - [offset家族](#offset家族) 24 | 25 | - [offsetWidth | Height](#offsetWidth-|-Height) 26 | 27 | - [ offsetLeft | Top ](#-offsetLeft-|-Top-) 28 | 29 | - [ offsetParent](#-offsetParent) 30 | 31 | - [ offsetTop和style.top的区别](#-offsetTop和styletop的区别) 32 | 33 | - [scroll家族](#scroll家族) 34 | 35 | - [scrollTop scrollLeft](#scrollTop----scrollLeft) 36 | 37 | - [scrollWidth | scrollHeight](#scrollWidth-|-scrollHeight) 38 | 39 | - [怎么得到scrollTop](#怎么得到scrollTop) 40 | 41 | - [scrollTo(x,y)](#scrollTox,y) 42 | 43 | - [client家族](#client家族) 44 | 45 | - [检测屏幕宽度 (可视区域)](#检测屏幕宽度-可视区域) 46 | 47 | - [window.onresize 改变窗口事件 ](#windowonresize-改变窗口事件--) 48 | 49 | - [检测屏幕宽度(分辨率)](#检测屏幕宽度分辨率) 50 | 51 | --- 52 | 53 | ## offset家族 54 | 55 | **offset 自己的** 56 | 57 | 目的:js中有一套方便的获取**元素尺寸的办法就是offset家族**; 58 | 59 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1490167075616) 60 | 61 | ### offsetWidth | Height 62 | 63 | > 得到**对象的宽度和高度**(自己的,与他人无关) 64 | 65 | ```javascript 66 | offsetWidth= width + border + padding 67 | div { width:220px; border-left:2px solid red; padding:10px;} 68 | div.offsetWidth = 220 + 2 + 20 69 | ``` 70 | 71 | 为什么不用 `div.style.width` 因为**它只能得到行内**的数值 72 | 73 | ### offsetLeft | Top 74 | 75 | > 返回距离上级盒子(**最近的带有定位**)左边的位置,如果父级都没有定位则以body 为准 ,offsetLeft 从**父级的padding 开始算** ,父亲的border 不算 76 | 77 | 这里的父级指的是所有上一级不仅仅指的是 父亲 还可以是 爷爷 曾爷爷 曾曾爷爷。。。。 78 | 79 | 总结一下: 就是子盒子到定位的父盒子边框到边框的距离 80 | 81 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1490167148878) 82 | 83 | ### offsetParent 84 | 85 | > 返回改对象的父级(**带有定位**) 不一定是亲的爸爸,如果当前元素的父级元素没有进行CSS定位(position为absolute或relative),offsetParent为body。如果当前元素的父级元素中有CSS定位(position为absolute或relative),offsetParent取**最近的那个父级元素**。 86 | 87 | ``` 88 | var son = document.getElementById("son"); 89 | //alert(son.parentNode.id); 90 | alert(son.offsetParent.tagName); // tagName标签的名字 91 | ``` 92 | 93 | ### offsetTop和style.top的区别 94 | 95 | 1. 最大区别在于 `offsetLeft` 可以返回**没有定位盒子的距离左侧的位置**。而 `style.top` 不可以只有定位的盒子才有 left top right 96 | 97 | 2. `offsetTop` 返回的是**数字**,而 `style.top` 返回的是**字符串**,除了数字外还带有单位:px。 98 | 99 | 1. `offsetTop` 只读,而 `style.top` 可读写。 100 | 101 | 1. 如果没有给 HTML 元素指定过 top 样式,则 style.top 返回的是空字符串。 102 | 103 | 2. 最重要的区别 style.left 只能得到**行内样式** offsetLeft 随便 104 | 105 | ## scroll家族 106 | 107 | Offset 自己的 108 | 109 | scroll 滚动的 (其实这才算偏移) 110 | 111 | ### scrollTop scrollLeft 112 | 113 | > 被卷去的头或左边 114 | 115 | 它就是当你滑动滚轮浏览网页的时候网页隐藏在屏幕上方的距离 116 | 117 | `scrollLeft` 用的少,很少屏幕横向滚动了。 118 | 119 | ### scrollWidth | scrollHeight 120 | 121 | > 实际内容的宽度或高度 122 | 123 | ### 怎么得到scrollTop 124 | 125 | 我们学习一个事件 : 页面滚动效果 `window.onscroll` 126 | 127 | ```javascript 128 | window.onscroll = function() { 页面滚动语句 } 129 | ``` 130 | 131 | 谷歌浏览器 和没有声明 DTD ` `: 132 | 133 | ```javascript 134 | document.body.scrollTop; 135 | ``` 136 | 137 | 火狐 和其他浏览器 138 | 139 | ```javascript 140 | document.documentElement.scrollTop; 141 | ``` 142 | 143 | ie9+ 和 最新浏览器 都认识 144 | 145 | ```javascript 146 | window.pageXOffset; pageYOffset (scrollTop) 147 | ``` 148 | 149 | 兼容性写法: 150 | 151 | ```javascript 152 | var scrollTop = window.pageYOffset || document.documentElement.scrollTop 153 | || document.body.scrollTop || 0; 154 | ``` 155 | 156 | ### scrollTo(x,y) 157 | 158 | window.scrollTo(x,y) 去往页面的 x 和 y 坐标 的位置(**一般我们只用y,x设为0就好**) 159 | 160 | ## client家族 161 | 162 | **client 可视区域** 163 | 164 | - `offsetWidth`: width + padding + border (披着羊皮的狼) 165 | 166 | - `clientWidth`: width + padding 不包含border 167 | 168 | - `scrollWidth`: 大小是内容的大小 ![your text](http://o7bk1ffzo.bkt.clouddn.com/1490168586390) 169 | 170 | ## 检测屏幕宽度 (可视区域) 171 | 172 | ie9及其以上的版本 173 | 174 | ```js 175 | window.innerWidth 176 | ``` 177 | 178 | 标准模式 179 | 180 | ```js 181 | document.documentElement.clientWidth 182 | ``` 183 | 184 | 怪异模式 185 | 186 | ```js 187 | document.body.clientWidth 188 | ``` 189 | 190 | 自己封装一个返回可视区宽度和高度的函数。 191 | 192 | > 注意: 193 | 194 | > clientWidth 返回的是可视区 大小 浏览器内部的大小 195 | 196 | > window.screen.width 返回的是我们电脑的分辨率 跟浏览器没有关系 197 | 198 | ```javascript 199 | function client() { 200 | if(window.innerWidth != null) // ie9 + 最新浏览器 201 | { 202 | return { 203 | width: window.innerWidth, 204 | height: window.innerHeight 205 | } 206 | } 207 | else if(document.compatMode === "CSS1Compat") // 标准浏览器 208 | { 209 | return { 210 | width: document.documentElement.clientWidth, 211 | height: document.documentElement.clientHeight 212 | } 213 | } 214 | return { // 怪异浏览器 215 | width: document.body.clientWidth, 216 | height: document.body.clientHeight 217 | } 218 | } 219 | ``` 220 | 221 | ## window.onresize 改变窗口事件 222 | 223 | > onresize 事件会在窗口或框架被调整大小时发生 224 | 225 | 这个事件经常用来做响应式布局(css3之前),动态加载css样式表 226 | 227 | ```javascript 228 | function reSize() { 229 | var clientWidth = client().width; 230 | if(clientWidth > 980) 231 | { 232 | styleCss.href = ""; 233 | } 234 | else if(clientWidth > 640) 235 | { 236 | styleCss.href = "css/pad.css"; 237 | } 238 | else 239 | { 240 | styleCss.href = "css/mobile.css"; 241 | } 242 | } 243 | ``` 244 | 245 | -------------------------------------------------------------------------------- /about_js/optimize.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [目录](#目录) 4 | - [js优化](#js优化) 5 | - [防抖动](#防抖动) 6 | - [underscore源码](#underscore源码) 7 | - [简化版](#简化版) 8 | - [节流](#节流) 9 | - [underscore源码](#underscore源码) 10 | - [简化版](#简化版) 11 | - [参考文章](#参考文章) 12 | --- 13 | 14 | ## 目录 15 | 16 | --- 17 | 18 | - [js优化](#js优化) 19 | 20 | - [防抖动](#防抖动) 21 | 22 | - [节流](#节流) 23 | 24 | - [参考文章](#参考文章) 25 | 26 | --- 27 | 28 | 29 | 30 | ## js优化 31 | 32 | 33 | 34 | 在实际工程中间,会用到很多优化的技巧,其中比较重要的两个是去抖动和函数节流。这两个方法都是限制函数执行的方案。 35 | 36 | 37 | 38 | ### 防抖动 39 | 40 | 41 | 42 | 函数防抖就是让某个函数在上一次执行后,满足等待某个时间内不再触发此函数后再执行,而在这个等待时间内再次触发此函数,等待时间会重新计算。 43 | 44 | 45 | 46 | 防抖动大量运用在`联想搜索`里。当用户输入停止后再开始联想,而不是用户随便输入一点什么就开始发送请求,如果用户一下输入大量文字或英文,会在短时间内向后台发送大量请求是很没必要的。 47 | 48 | 49 | 50 | #### underscore源码 51 | 52 | ```js 53 | _.debounce = function(func, wait, immediate) { 54 | // immediate默认为false 55 | var timeout, args, context, timestamp, result; 56 | var later = function() { 57 | // 当wait指定的时间间隔期间多次调用_.debounce返回的函数,则会不断更新timestamp的值,导致last < wait && last >= 0一直为true,从而不断启动新的计时器延时执行func 58 | var last = _.now() - timestamp; 59 | if (last < wait && last >= 0) { 60 | timeout = setTimeout(later, wait - last); 61 | } else { 62 | timeout = null; 63 | if (!immediate) { 64 | result = func.apply(context, args); 65 | if (!timeout) context = args = null; 66 | } 67 | } 68 | }; 69 | return function() { 70 | context = this; 71 | args = arguments; 72 | timestamp = _.now(); 73 | // 第一次调用该方法时,且immediate为true,则调用func函数 74 | var callNow = immediate && !timeout; 75 | // 在wait指定的时间间隔内首次调用该方法,则启动计时器定时调用func函数 76 | if (!timeout) timeout = setTimeout(later, wait); 77 | if (callNow) { 78 | result = func.apply(context, args); 79 | context = args = null; 80 | } 81 | return result; 82 | }; 83 | }; 84 | ``` 85 | 86 | 87 | 88 | #### 简化版 89 | 90 | ```js 91 | var debounce = function ( fn, wait, immdediate) { 92 | var timer = null, 93 | pre = 0; 94 | return function () { 95 | var context = this; 96 | var args = arguments; 97 | var now = +new Date(); 98 | var left = now - pre - wait; 99 | pre = now; 100 | // 如果距离上一次函数调用已经超过了预计时间,或者此时没有设置timer 101 | if ( left > 0 ){ 102 | fn.apply(context,args); 103 | return ; 104 | } 105 | //每次进入函数,都重新计算过期时间 106 | clearTimeout(timer); 107 | timer = setTimeout(function () { 108 | clearTimeout(timer); 109 | timer = null; 110 | fn.apply(context,args); 111 | pre = +new Date(); //调用了函数也更新pre 112 | },wait); 113 | } 114 | } 115 | 116 | ``` 117 | 118 | ### 节流 119 | 120 | 121 | 122 | 每间隔某个时间去执行某函数,避免函数的过多执行,这个方式就叫函数节流。节流和防抖动最大的不同就是,节流保证一个时间段内至少会执行一次。可以想象成把水龙头拧小,它主要用于大量连续事件快速频繁触发的场景,比如:onscroll,onresize。 123 | 124 | 125 | 126 | #### underscore源码 127 | 128 | ```js 129 | _.throttle = function(func, wait, options) { 130 | /* options的默认值 131 | * 表示首次调用返回值方法时,会马上调用func;否则仅会记录当前时刻,当第二次调用的时间间隔超过wait时,才调用func。 132 | * options.leading = true; 133 | * 表示当调用方法时,未到达wait指定的时间间隔,则启动计时器延迟调用func函数,若后续在既未达到wait指定的时间间隔和func函数又未被调用的情况下调用返回值方法,则被调用请求将被丢弃。 134 | * options.trailing = true; 135 | * 注意:当options.trailing = false时,效果与上面的简单实现效果相同 136 | */ 137 | var context, args, result; 138 | var timeout = null; 139 | var previous = 0; 140 | if (!options) options = {}; 141 | var later = function() { 142 | previous = options.leading === false ? 0 : _.now(); 143 | timeout = null; 144 | result = func.apply(context, args); 145 | if (!timeout) context = args = null; 146 | }; 147 | return function() { 148 | var now = _.now(); 149 | if (!previous && options.leading === false) previous = now; 150 | // 计算剩余时间 151 | var remaining = wait - (now - previous); 152 | context = this; 153 | args = arguments; 154 | // 当到达wait指定的时间间隔,则调用func函数 155 | // 精彩之处:按理来说remaining <= 0已经足够证明已经到达wait的时间间隔,但这里还考虑到假如客户端修改了系统时间则马上执行func函数。 156 | if (remaining <= 0 || remaining > wait) { 157 | // 由于setTimeout存在最小时间精度问题,因此会存在到达wait的时间间隔,但之前设置的setTimeout操作还没被执行,因此为保险起见,这里先清理setTimeout操作 158 | if (timeout) { 159 | clearTimeout(timeout); 160 | timeout = null; 161 | } 162 | previous = now; 163 | result = func.apply(context, args); 164 | if (!timeout) context = args = null; 165 | } else if (!timeout && options.trailing !== false) { 166 | // options.trailing=true时,延时执行func函数 167 | timeout = setTimeout(later, remaining); 168 | } 169 | return result; 170 | }; 171 | }; 172 | ``` 173 | 174 | 精彩之处:一般来说remaining <= 0已经足够证明已经到达wait的时间间隔,但这里还考虑到假如客户端修改了系统时间则马上执行func函数. 175 | 176 | 177 | 178 | #### 简化版 179 | 180 | 181 | 182 | 自写简化版(来自javascript设计模式) 183 | 184 | ```js 185 | var throttle = function ( fn, interval ) { 186 | var timer, 187 | first = true; 188 | return function () { 189 | var args = arguments, // 重命名一下,防止迷糊 190 | _me = this; 191 | if ( first ) { // 第一 次直接执行 192 | fn.apply(_me , args); 193 | return first = false; 194 | } 195 | if ( timer ){ // 如果上一次还没执行完,则直接返回 196 | return false; 197 | } 198 | timer = setTimeout(function () { 199 | clearTimeout(timer); // 时间结束后,先取消计时器,然后运行当前函数 200 | timer = null; 201 | fn.apply(_me, args); 202 | }, interval || 500); 203 | }; 204 | }; 205 | ``` 206 | 207 | 208 | 209 | 210 | 211 | ## 参考文章 212 | 213 | 214 | 215 | - ​[JS魔法堂:函数节流(throttle)与函数去抖(debounce)](http://www.cnblogs.com/fsjohnhuang/p/4147810.html) 216 | 217 | 218 | 219 | - [函数防抖与节流](https://segmentfault.com/a/1190000002764479) 220 | 221 | 222 | 223 | - [scroll优化之防抖与节流](https://segmentfault.com/a/1190000007676390) 224 | 225 | 226 | 227 | - 《Javascript设计模式与开发实践》 228 | 229 | -------------------------------------------------------------------------------- /about_css/css3.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [一、css3边框](#一、css3边框) 4 | - [box-shadow(ie9+)](#box-shadowie9+) 5 | - [border-image(ie11+不可,opera)](#border-imageie11+不可,opera) 6 | - [二、css3背景](#二、css3背景) 7 | - [background-origin规定背景图片的定位区域](#background-origin规定背景图片的定位区域) 8 | - [background-clip规定背景图片的绘制区域](#background-clip规定背景图片的绘制区域) 9 | - [允许添加多张图片](#允许添加多张图片) 10 | - [三、css3文本效果](#三、css3文本效果) 11 | - [text-shadow(ie9+)文字阴影](#text-shadowie9+文字阴影) 12 | - [word-break字符换行](#word-break字符换行) 13 | - [word-wrap](#word-wrap) 14 | - [四、css3字体](#四、css3字体) 15 | - [五、css3 2D转换](#五、css3-2D转换) 16 | - [七、过渡transition](#七、过渡transition) 17 | - [八、动画创建动画 @keyframes](#八、动画创建动画-@keyframes) 18 | - [九、多列column](#九、多列column) 19 | - [十、用户界面](#十、用户界面) 20 | - [outline-offset(ie opera不支持)](#outline-offsetie-opera不支持) 21 | - [css3选择器](#css3选择器) 22 | - [使用说明:](#使用说明) 23 | - [实例](#实例) 24 | --- 25 | 26 | # 一、css3边框 27 | 28 | ## border-radius(ie9+) 29 | 30 | % / length 31 | 32 | ## box-shadow(ie9+) 33 | 34 | - h-shadow 水平阴影 35 | 36 | - v-shadow 垂直阴影 37 | 38 | - blur 模糊距离 编剧模糊 39 | 40 | - spread 阴影尺寸 阴影的大小! 41 | 42 | - color 43 | 44 | - inset 内部阴影 45 | 46 | ## border-image(ie11+不可,opera) 47 | 48 | - border-image-source 49 | 50 | - border-image-slice 图片剪裁位置,裁剪,切成九宫格 详解看这里 51 | 52 | - border-image-width border- 53 | 54 | - border-image-outset 原有的图像上向外延展 55 | 56 | - border-image-repeat (repeat[有可能截断],round[调整尺寸,正好铺满],stretch[拉伸],space[调整图片间的间距]) 57 | 58 | # 二、css3背景 59 | 60 | ## background-size(ie9+) 61 | 62 | css3前,背景尺寸由图片的实际尺寸决定,现在可以规定背景图片的尺寸,即可以使其拉伸 63 | 64 | - length 65 | 66 | - % 67 | 68 | - cover(背景图片更大) 69 | 70 | - contain(div更大) 71 | 72 | ## background-origin规定背景图片的定位区域 73 | 74 | - border-box 75 | 76 | - padding-box(默认) 77 | 78 | - content-box 79 | 80 | ## background-clip规定背景图片的绘制区域 81 | 82 | - border-box(默认) 83 | 84 | - padding-box 85 | 86 | - content-box 87 | 88 | ## 允许添加多张图片 89 | 90 | background-image:url(bg*flower.gif),url(bg*flower_2.gif); 91 | 92 | # 三、css3文本效果 93 | 94 | ## text-overflow文本溢出 95 | 96 | 需要与overflow同时使用! 97 | 98 | - clip 修建文本 99 | 100 | - ellipse 省略符号代表修建的文本 101 | 102 | - string 给定字符串代表被修建文本 103 | 104 | ## text-shadow(ie9+)文字阴影 105 | 106 | - h-shadow 107 | 108 | - v-shadow 109 | 110 | - blur 111 | 112 | - color 113 | 114 | ## word-break字符换行 115 | 116 | - normal 117 | 118 | - break-all 允许在单词内换行 119 | 120 | - keep-all 半角空格或连字符换行 121 | 122 | ## word-wrap 123 | 124 | - normal 125 | 126 | - break-word 长单词或url地址内部进行换行 127 | 128 | # 四、css3字体 129 | 130 | ``` 131 | @font-face 132 | font-family: myFirstFont; 133 | src: url('Sansation_Light.ttf'), 134 | url('Sansation_Light.eot'); 135 | div 136 | font-family:myFirstFont; 137 | ``` 138 | 139 | # 五、css3 2D转换 140 | 141 | # 六、css3 3D转换 142 | 143 | # 七、过渡transition 144 | 145 | - transition-property css属性名称 146 | 147 | - transition-duration 过渡效果时间 148 | 149 | - transition-timing-function 速度曲线 (linear ease ease-in ease-out ease-in-out cubic-bezier(n,n,n,n)) 150 | 151 | - transition-delay 何时开始 152 | 153 | # 八、动画创建动画 @keyframes 154 | 155 | ``` 156 | @keyframes myfirst 157 | 0% {background: red; left:0px; top:0px;} 158 | 25% {background: yellow; left:200px; top:0px;} 159 | 50% {background: blue; left:200px; top:200px;} 160 | 75% {background: green; left:0px; top:200px;} 161 | 100% {background: red; left:0px; top:0px;} 162 | @-moz-keyframes myfirst /* Firefox */ 163 | 0% {background: red; left:0px; top:0px;} 164 | 25% {background: yellow; left:200px; top:0px;} 165 | 50% {background: blue; left:200px; top:200px;} 166 | 75% {background: green; left:0px; top:200px;} 167 | 100% {background: red; left:0px; top:0px;} 168 | @-webkit-keyframes myfirst /* Safari 和 Chrome */ 169 | 0% {background: red; left:0px; top:0px;} 170 | 25% {background: yellow; left:200px; top:0px;} 171 | 50% {background: blue; left:200px; top:200px;} 172 | 75% {background: green; left:0px; top:200px;} 173 | 100% {background: red; left:0px; top:0px;} 174 | @-o-keyframes myfirst /* Opera */ 175 | 0% {background: red; left:0px; top:0px;} 176 | 25% {background: yellow; left:200px; top:0px;} 177 | 50% {background: blue; left:200px; top:200px;} 178 | 75% {background: green; left:0px; top:200px;} 179 | 100% {background: red; left:0px; top:0px;} 180 | div 181 | animation: myfirst 5s; 182 | -moz-animation: myfirst 5s; /* Firefox */ 183 | -webkit-animation: myfirst 5s; /* Safari 和 Chrome */ 184 | -o-animation: myfirst 5s; /* Opera */ 185 | ``` 186 | 187 | animation 188 | 189 | - name 190 | 191 | - duration 192 | 193 | - timing-function 194 | 195 | - delay 196 | 197 | - iteration-count 被播放的次数(n / infinite) 198 | 199 | - direction normal/ alternative反向播放 200 | 201 | - play-state paused running 可在js中暂停动画 202 | 203 | # 九、多列column 204 | 205 | - column-count 元素被分割的列数 206 | 207 | - column-gap 列之间的间隔 208 | 209 | - column-rule width(列之间的宽度) style(solid...) color() 210 | 211 | - column-span 横跨列数(n/all) 212 | 213 | - collumn-width 列宽 214 | 215 | # 十、用户界面 216 | 217 | ## box-sizing 218 | 219 | - content-box 220 | 221 | - border-box 222 | 223 | ## outline-offset(ie opera不支持) 224 | 225 | 边框边缘外有一个轮廓 不占用空间 226 | 227 | resize(对元素尺寸调整 大多不支持) 228 | 229 | # css3选择器 230 | 231 | css3选择器引入了通配符的概念,和jQuery一样可以使用^,$操作,用法也类似 232 | 233 | ## 使用说明: 234 | 235 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1473815245277) 236 | 237 | ## 实例 238 | 239 | html 240 | 241 | ```html 242 | 我链接的是PDF文件 243 | 我类名是icon 244 | 我的title是more 245 | ``` 246 | 247 | css 248 | 249 | ```css 250 | a[class^=icon]{ 251 | background: green; 252 | color:#fff; 253 | a[href$=pdf]{ 254 | background: orange; 255 | color: #fff; 256 | a[title*=more]{ 257 | background: blue; 258 | color: #fff; 259 | ``` 260 | 261 | [codepen_embed height="265" theme_id="dark" slug_hash="LbvzOd" default_tab="css,result" user="voidsky"]See the Pen LbvzOd by HuangKai (@voidsky) on CodePen.[/codepen_embed] 262 | 263 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [front-end](#front-end) 4 | - [前端综合](#前端综合) 5 | - [JS相关](#JS相关) 6 | - [常见编程考验](#常见编程考验) 7 | - [常用操作](#常用操作) 8 | - [DOM相关](#DOM相关) 9 | - [css 相关](#css-相关) 10 | - [常见编程考验](#常见编程考验) 11 | - [html 相关](#html-相关) 12 | - [http,浏览器相关](#http,浏览器相关) 13 | - [ES6](#ES6) 14 | - [框架,工具](#框架,工具) 15 | - [jquery](#jquery) 16 | - [react ](#react-) 17 | - [nodejs](#nodejs) 18 | - [算法题:](#算法题) 19 | - [面试题](#面试题) 20 | --- 21 | 22 | # front-end 23 | 24 | 前端基本功以及面试必备知识。 25 | 26 | 大家可以把自己想到的常用知识或者面试题补充在下面。每个topic对应一个md文件。可以在现有的文件上进行修改,也可以新建文件保存到对应的文件目录下。 27 | 28 | 每篇文章的内容都是可以修改的,大家可以增加自己的内容。但是请尽量不要直接复制粘贴博客原文,**最好是自己的思路,整理,总结**。 29 | 30 | 请把**参考的博客,文章地址**放到每篇文章的`参考文章`后面,方便别人进行扩展阅读。(也可以在引用部分进行标注) 31 | 32 | > 注意:请按照下面格式进行文件的添加,readme部分只做目录 33 | 34 | 如果新增或修改,请在当前页进行标注: 35 | 36 | - `+6位时间`表示完成了当前文章(从无到有) 37 | 38 | - `!6位时间`表示修改当前文章 39 | 40 | 例:+170716 表示在2017年7月16日增加了当前文章 41 | 42 | ## 前端综合 43 | 44 | - [web前端性能优化总结](/browser/optimize.md) +170723 45 | 46 | - [同源问题与跨域](/about_js/sameorigin.md) +170715 47 | 48 | - [cache](/overall/cache.md) +170723 49 | 50 | - [cookie](/overall/cookie.md) +170723 51 | 52 | - [cookie和session](/overall/cookie.md/#cookie和session) +170723 53 | 54 | - [iframe](/overall/iframe.md) 55 | 56 | - [通信](/overall/message.md) 57 | 58 | - [正则表达式](/overall/regex.md) +170717 59 | 60 | - [存储相关](/overall/storage.md) +170723 61 | 62 | - [fiddler使用](/overall/fiddler.md) 63 | 64 | ## JS相关 65 | 66 | - [原型(链)](/about_js/prototype.md) +170720 by xiaoch11 67 | 68 | - [创建对象和继承](about_js/extend.md) +170717 69 | 70 | - [This (call apply bind)](about_js/this.md) +170715 71 | 72 | - [执行环境和作用域链](/about_js/context.md) +170717 73 | 74 | - [闭包](/about_js/closure.md) +170721 75 | 76 | - [ajax](/about_js/ajax.md) +170721 77 | 78 | - [jsonp](about_js/jsonp.md) +170715 79 | 80 | - [数组相关](/about_js/array.md) +170721 81 | 82 | - [与和或操作符](/about_js/andor.md) +170723 83 | 84 | - [基本类型和隐式转换](/about_js/convert.md) +170723 85 | 86 | - [字符串相关](/about_js/string.md) +170721 87 | 88 | - [链式调用](/about_js/chain.md) +170723 89 | 90 | - [事件](/about_js/event.md) +170720 by xiaoch11 91 | 92 | - [事件冒泡和捕获](/about_js/bubble.md) +170723 93 | 94 | - [事件委托](/about_js/delegation.md) +170723 95 | 96 | - [函数优化(防抖动和节流)](/about_js/optimize.md) + 170806 97 | 98 | - [polyfill](/about_js/polyfill.md) 99 | 100 | ### 常见编程考验 101 | 102 | - [如何clone一个对象(深拷贝)](about_js/program.md/#如何实现深浅拷贝) +170715 103 | 104 | - [如何实现数组去重](about_js/program.md/#如何实现数组去重) +170722 105 | 106 | - [如何实现sum(1,2),sum(1)(2)](about_js/program.md/#如何实现sum1,2,sum12) +170722 107 | 108 | - [如何删除数组中的多个特定元素(必须用splice)](about_js/program.md/#如何删除数组中的多个特定元素必须用splice) +170722 109 | 110 | - [求数组中的最大,最小值](about_js/program.md/#求数组中的最大,最小值) +170801 111 | 112 | - [如何扁平化数组](about_js/program.md/#如何扁平化数组) +170801 113 | 114 | - [如何实现(2).plus(3).minus(1) //4](about_js/program.md/#如何实现2plus3minus1-//4) +170801 115 | 116 | - [如何判断一个字符串是回文串](about_js/program.md/#如何判断一个字符串是回文串) +170801 117 | 118 | - [如何实现任意进制转换](/about_js/program.md/#如何实现任意进制转换) +170807 119 | 120 | - [实现一个lazyman](about_js/lazyman.md) +170715 121 | 122 | ### 常用操作 123 | 124 | - [遍历DOM节点](about_js/traverse.md) +170807 125 | 126 | - [如何实现拖动](about_js/operation.md/#如何实现拖动) +170727 127 | 128 | - [如何实现屏幕滚动检测](about_js/operation.md/#如何实现屏幕滚动检测) +170727 129 | 130 | ## DOM相关 131 | 132 | - [屏幕和元素尺寸](/dom/size.md) +170727 133 | 134 | - [常用dom操作](dom/dom.md) +17071 135 | 136 | - [DOM属性](dom/domattr.md) +17071 137 | 138 | ## css 相关 139 | 140 | - [盒模型](/about_css/box.md) +170726 141 | 142 | - [marigin塌陷](/about_css/collapsedmargin.md) +170726 143 | 144 | - [层叠](/about_css/cascade.md) 145 | 146 | - [css3相关](/about_css/css3.md) +170726 147 | 148 | - [包含块,盒,格式化上下文](/about_css/fc.md) +170726 149 | 150 | - [flex布局](/about_css/flex.md) +170726 151 | 152 | - [流模型](/about_css/flow.md) 153 | 154 | - [hack](/about_css/hack.md) +170806 155 | 156 | - [less](/about_css/less.md) 157 | 158 | - [sass](/about_css/sass.md) 159 | 160 | - [css选择器](/about_css/selector.md) +170720 by xiaoch11 161 | 162 | ### 常见编程考验 163 | 164 | - [基本布局](/about_css/layout.md) +170718 165 | 166 | - [实现水平居中](/about_css/center.md) +170715 167 | 168 | - [实现垂直居中](/about_css/vcenter.md) +170715 169 | 170 | - [实现水平垂直居中](/about_css/hvcenter.md) +170715 171 | 172 | ## html 相关 173 | 174 | - [doctyp](/about_html/doctype.md) 175 | 176 | - [head](/about_html/head.md) 177 | 178 | - [语义化标签](/about_html/semantic.md) 179 | 180 | - [替换元素](/about_html/replaced.md) +170726 181 | 182 | - [常用标签](/about_html/tags.md) +170715 183 | 184 | - [viewpor](/about_html/viewport.md) +170725 185 | 186 | ## http,浏览器相关 187 | 188 | - [浏览器渲染原理和性能优化](/browser/howitworks.md) +170722 189 | 190 | - [常见相应代码](/browser/responsecode.md) +170723 191 | 192 | - [get和post区别](/browser/getpost.md) +170723 193 | 194 | - http头 195 | 196 | - 浏览器模式(解释清楚算加分项) 197 | 198 | - [安全](/security/xss.md) +170806 199 | 200 | - [http性质,头](/browser/http.md) +170807 201 | 202 | - [TCP相关](/browser/tcp.md) +170807 203 | 204 | ## ES6 205 | 206 | - [let&const](es6/let&const.md) +170715 207 | 208 | - [变量解构](es6/destructuring.md) +170715 209 | 210 | - [箭头函数](/es6/arrow.md) +170715 211 | 212 | - [class](/es6/class.md) 213 | 214 | - [module](/es6/module.md) +170724 215 | 216 | - [promise](/es6/promise.md) +170724 217 | 218 | - [generator](/es6/generator.md) +170724 219 | 220 | ## 框架,工具 221 | 222 | ### vue 223 | 224 | - [vue相关](/framework/vue/vue.md) +170725 225 | 226 | - [vuex](/framework/vue/vuex.md) +170715 227 | 228 | - [vue-router](/framework/vue/vue_router.md) 229 | 230 | ### jquery 231 | 232 | ### angular 233 | 234 | ### react 235 | 236 | ### webpack 237 | 238 | - [webpack基本知识](/framework/webpack.md) +170723 239 | 240 | ## nodejs 241 | 242 | - [nodejs相关](/framework/nodejs/nodejs.md) 243 | 244 | - [fs](/framework/nodejs/fs.md) 245 | 246 | - [http](/framework/nodejs/http.md) 247 | 248 | ## 算法题: 249 | 250 | - 链表判环 251 | 252 | - 翻转链表 253 | 254 | - 链表取倒数第n个 255 | 256 | - 有序链表合并 257 | 258 | - [排序](/algorithm/sort.md) 259 | 260 | - 括号的匹配(栈) 261 | 262 | - [二叉树](/algorithm/tree.md) 263 | 264 | - 背包问题 265 | 266 | ## 面试题 267 | 268 | > 这里可以直接接网址链接,当然还是希望大家发现有新的面试题,但是上面没出现的,补充在上面 269 | 270 | - [一道经典的js面试题](/interview/p1.md) 271 | 272 | - [windows.onload 和 $(document).ready()区别](/interview/p2.md) 273 | 274 | - [你常关注的网站](/interview/p3.md) 275 | 276 | - [forEach,map,$.each区别](/interview/p4.md) 277 | 278 | - [用setTimeout()方法来模拟setInterval()与setInterval()之间的什么区别?](/interview/p5.md) 279 | 280 | - [new Date的兼容性问题](/interview/p6.md) 281 | -------------------------------------------------------------------------------- /about_js/convert.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [基本类型和类型转换](#基本类型和类型转换) 4 | - [Number](#Number) 5 | - [NaN](#NaN) 6 | - [数值转换](#数值转换) 7 | - [pareseInt():](#pareseInt) 8 | - [parseFloat()](#parseFloat) 9 | - [String](#String) 10 | - [转换字符串:](#转换字符串) 11 | - [+](#+) 12 | - [==和===](#==和===) 13 | - [null和undefined和非这两者的值](#null和undefined和非这两者的值) 14 | - [Number和String, String=>Number](#Number和String,-String=>Number) 15 | - [NaN和任何值都不相等](#NaN和任何值都不相等) 16 | - [Number,String和Object, Ojbect调用valueOf或toString](#Number,String和Object,-Ojbect调用valueOf或toString) 17 | --- 18 | 19 | # 基本类型和类型转换 20 | 21 | ## Boolean 22 | 23 | 1. 只有`true`和`false`两个值,这两个值是特殊的值,不完全等于1和0 24 | 25 | 2. **转换规则**(自动使用`Boolean()`函数),在if语句中很有用。 26 | 27 | | 数据类型 | true | false | 28 | 29 | | --------- | -------------- | --------- | 30 | 31 | | Boolean | true | false | 32 | 33 | | String | 非空 | “” | 34 | 35 | | Number | 非0(包括Infinity) | 0和**NaN** | 36 | 37 | | Object | 任何对象 | null | 38 | 39 | | Undefined | / | undefined | 40 | 41 | ## Number 42 | 43 | 1. 0开始表示八进制(首**多余0会自动丢弃**),**无效八进制自动转换成十进制**,在**严格模式下八进制无效。** 44 | 45 | 2. 0x开始表示十六进制(**不可有多余的0**) 46 | 47 | 3. 浮点数会占用2倍整数内存,所以当数没有小数的时候,会转换成整数。 48 | 49 | 4. 小数前0超过6位会用科学表示法 50 | 51 | 5. 不推荐省略浮点数前的0 52 | 53 | 6. 浮点数表示最高精度有17位,但是有精度问题,`千万不能用==来比较!` 54 | 55 | 7. Number.MAX_VALUE和Number.MAX_VALUE 56 | 57 | 8. 超过范围的会转换为`Infinity|-Infinity`这个值,存储在`Number.POSITIVE_INFINITY`和`Number.POSITIVE_INFINITY`中 58 | 59 | 9. 可以用**isFinite()** 函数判断介于最大和最小值的数值 。 60 | 61 | ### NaN 62 | 63 | **所有跟NaN有关的运算全会得到NaN** 64 | 65 | 任何数都不等于NaN,包括自己,只能用**isNaN()** 来判断,isNaN也可用于对象,根据valueOf()判断,如果不行再通过toString()测试。 66 | 67 | ### 数值转换 68 | 69 | | 数据类型 | 数值 | 70 | 71 | | --------- | ----------------- | 72 | 73 | | Boolea | true : 1,false : 0 | 74 | 75 | | Null | null : 0 | 76 | 77 | | Undefined | undefined : NaN | 78 | 79 | | String | 1. 只包含数字(含浮点),且非十六进制,会自动忽略前导0(无法表示八进制) | 80 | 81 | | | 2. `0xf`这样十六进制转换成对应十进制 | 82 | 83 | | | 3. "" : 0 | 84 | 85 | | | 4. 其他 :NaN | 86 | 87 | | Object | 根据valueOf(),结果是NaN再根据toString(),调用上面String规则 | 88 | 89 | ```javascript 90 | Number("Hello") // NaN 91 | Number("000023") // 23 92 | Number(true) //1 93 | ``` 94 | 95 | **在和数字做运算操作的时候会自动调用以上规则**,比如: 96 | 97 | ```javascript 98 | +"0x10" // 16 +的**一元运算** 以直接**等价Number()** 99 | true++ // 2 100 | null + 1 // 1 101 | ``` 102 | 103 | ### pareseInt(): 104 | 105 | - 会**忽略前导空格**,直到遇到第一个数字,否则返回NaN 106 | 107 | - 后面遇到非数字会自动停止,**包括**`.` 108 | 109 | - 可以识别八进制(尽量别尝试,**ES5不识别,会忽略前导0**),十六进制。 110 | 111 | - **尽量使用第二参数来表示进制** ,测试可以使用0-36,0和10一样,其他都会返回NaN。 112 | 113 | ```javascript 114 | parseInt("") //NaN 注意和Number不同,Number("") -> 0 115 | parseInt(" 10a") //10 116 | parseInt("070") // ES3 56 ES5 70 117 | parseInt("0xa") // 10 118 | pareseInt('10',2) // 2 119 | pareseInt('10',3) // 3 120 | pareseInt('10',8) // 8 121 | pareseInt('10',0) // 10 122 | parseInt('10',36) //36 123 | pareseInt('a',10) // NaN 124 | parseInt('10',-1) //NaN 125 | parseInt('10',37) //NaN 126 | ``` 127 | 128 | ### parseFloat() 129 | 130 | - 自动忽略前导0,解析到第一个无效浮点字符。(第一个`.`识别,第二个`.`不识别) 131 | 132 | - **不识别别的进制** 133 | 134 | - 可以用科学表示法 135 | 136 | - 如果发现是**整数,会返回整数** 137 | 138 | ```javascript 139 | pareseFloat('012.23.4') //12.23 140 | pareseFloat('3.12e7') //3120000 141 | pareseFloat('03.') //3 142 | pareseFloat('0xa') //NaN 143 | pareseFloat('a2.3') //NaN 144 | ``` 145 | 146 | ## String 147 | 148 | 1. 特殊字面量 149 | 150 | | 代码 | 输出 | 151 | 152 | | ------ | --------------- | 153 | 154 | | \' | 单引号 | 155 | 156 | | \" | 双引号 | 157 | 158 | | \& | 和号 | 159 | 160 | | \\\ | 反斜杠 | 161 | 162 | | \n | 换行符 | 163 | 164 | | \r | 回车符 | 165 | 166 | | \t | 制表符 | 167 | 168 | | \b | 退格符 | 169 | 170 | | \f | 换页符 | 171 | 172 | | \xnn | 十六进制表示的AscII码 | 173 | 174 | | \unnnn | 十六进制表示的Unicode码 | 175 | 176 | **注意:**用length计算的时候,双字节字符也只算1,得自己编函数用**charCodeAt()**函数判断。 177 | 178 | - 字符串不可变 179 | 180 | ### 转换字符串: 181 | 182 | 1. 几乎任何值都有的`toString()`(**除了null和undefined**),toString()可以加进制(**2-36**,否则报错) 183 | 184 | 注意,对数字直接使用toString()函数不行,必须变成包装对象 185 | 186 | ```javascript 187 | var num = 10; 188 | num.toString(2) // "1010" 189 | num.toString(10) // "10" 190 | num.toString(16) // a 191 | num.toString(37) // 报错 192 | 10.toString() //报错,不能直接这么用 193 | true.toString() //"true" 194 | null.toString //报错 195 | ``` 196 | 197 | 2. String(),**可以将所有的类型转换成字符串**,它会先调用toString(),不能转换(null,undefined)的再特殊处理,不能更改进制。(**字符串的+操作就是利用这个**) 198 | 199 | ```javascript 200 | String(10) // "10" 201 | String(null) //"null" 202 | String(undefined) //"undefined" 203 | ``` 204 | 205 | 3. Object默认转换成"[object Object]",**除非手动实现了toString函数** 206 | 207 | ```javascript 208 | var test = {'a':1}; 209 | test.toString() //"[object Object]" 210 | test.toString = function(){return 'test';} 211 | test.toString() //"test" 212 | String(test) //"test" 213 | ``` 214 | 215 | ## + 216 | 217 | +这个符号到底是什么意思,必须要看左右的东西是什么类型的。如果都是数字,那么就是加;否则,就是连字符。 218 | 219 | 但是,其他的运算符,是完全没有歧义的。比如*、-、/、%。 这些运算符,就是用来计算的!所以,我们的计算机,会帮我们进行一下隐式转换(隐藏的格式转换)。 220 | 221 | ```js 222 | 3*5 223 | 15 224 | "3"*5 225 | 15 226 | "3"*"5" 227 | 15 228 | ``` 229 | 230 | 但是,即使计算机有“隐式转换”,一个靠谱的程序员,一定要自己完成转换。否则,其他人看你的代码,有可能造成误会。 231 | 232 | ## ==和=== 233 | 234 | `==`运算符在判断两个值是否相等时会进行类型转换,但一个值转换为另一个值并不意味着两个值相等。如果是同一类型,直接比较(**对象比较指针,永远不相等**) 235 | 236 | 而`===`恒等运算符在判断相等时并未做任何类型转换。 237 | 238 | ```js 239 | null==undefined 240 | null !== undefined 241 | "0" == 0 242 | "0" !== 0 243 | ``` 244 | 245 | ### null和undefined和非这两者的值 246 | 247 | 都为false 248 | 249 | ### Number和String, String=>Number 250 | 251 | ```js 252 | '' == '0' //false 253 | 0 == ''//true; 254 | 0 == '0'//true 255 | ' \t\r\n '==0 //true 256 | ``` 257 | 258 | ### NaN和任何值都不相等 259 | 260 | ### Boolean和其他类型,Boolean=>Number 261 | 262 | ```js 263 | false == 'false'// 0和不为空的字符串比较 false 264 | false == '0'//0和'0',true 265 | false == null//false 266 | ``` 267 | 268 | ### Number,String和Object, Ojbect调用valueOf或toString 269 | 270 | Object默认转换成"[object Object]",除非手动实现了toString函数 271 | 272 | []转换成"" 273 | 274 | [1]转换成"1" 275 | 276 | [1,2]转换成"1,2" 277 | 278 | ```js 279 | "[object Object]" == {a:1} //true 280 | "" == [] //true 281 | "1" == [1] //true 282 | 1 == [1] //true 283 | "{a:1}" == {a:1} //false 284 | {a:1} == {a:1} //false 285 | ``` 286 | 287 | -------------------------------------------------------------------------------- /about_js/context.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [写开开头](#写开开头) 4 | - [执行环境(也称执行上下文–execution context)](#执行环境也称执行上下文–execution-context) 5 | - [变量提升](#变量提升) 6 | - [作用域](#作用域) 7 | - [执行环境与作用域的区别与联系](#执行环境与作用域的区别与联系) 8 | - [没有块级作用域](#没有块级作用域) 9 | - [延长作用域链](#延长作用域链) 10 | - [参考文章](#参考文章) 11 | --- 12 | 13 | ## 写开开头 14 | 15 | 首先,我们要知道执行环境(execution context)和作用域(scope)是两个完全不同的概念。 16 | 17 | 每个**执行环境**都有与之关联的**变量对象(variable object)**, 最外层的执行环境是全局执行环境(global对象)。环境中定义的所有变量和函数都保存在这个对象中。执行环境始终是this关键字的值,它是拥有当前所执行代码的对象的引用。 18 | 19 | 代码在一个执行环境中执行的时候,会创建变量的一个作用域链(scope chain) 20 | 21 | 换句话说,作用域涉及到所被调用函数中的变量访问,并且不同的调用场景是不一样的。每个执行环境都有一个与之关联的变量对象。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。 22 | 23 | ## 执行环境(也称执行上下文–execution context) 24 | 25 | - 当JavaScript解释器初始化执行代码时,它首先默认进入**全局执行环境**,从此刻开始,函数的每次调用都会创建一个**新的执行环境**。 26 | 27 | - **每个函数都有自己的执行环境**。 28 | 29 | - 当执行流进入一个函数时,函数的环境就会被推入一个**环境栈中**(execution stack)。在函数执行完后,栈将其环境弹出,把控制权返回给之前的执行环境。ECMAScript程序中的执行流正是由这个便利的机制控制着。 30 | 31 | - 执行环境可以分为**定义期**和**执行期**两个阶段。 32 | 33 | ### 定义期 34 | 35 | 函数**定义**的时候,都会创建一个**[[scope]]**属性,这个对象对应的是一个对象的列表(之前作用域链上的**变量对象**),列表中的对象仅能javascript内部访问,没法通过语法访问 36 | 37 | ```js 38 | // 外部函数 39 | function A(){ 40 | var somevar; 41 | // 内部函数 42 | function B(){ 43 | var somevar; 44 | } 45 | } 46 | ``` 47 | 48 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1500300196404) 49 | 50 | ### 执行期 51 | 52 | 当函数被执行的时候,就是**进入这个函数的执行环境** 53 | 54 | - 首先会创一个它自己的**活动对象**【Activation Object】(这个对象中包含了this、参数(arguments)、局部变量(包括命名的参数)的定义,当然全局对象是没有arguments的)和一个变量对象的作用域链[[scope chain]] 55 | 56 | - 然后,把这个执行环境的[scope]按顺序复制到[[scope chain]]里,最后把这个活动对象推入到[[scope chain]]的顶部。这样[[scope chain]]就是一个有序的栈,**这样保了对执行环境有权访问的所有变量和对象的有序访问**。 57 | 58 | ​ 59 | 60 | ```js 61 | function Fn1(){ 62 | function Fn2(){ 63 | alert(document.body.tagName);//BODY 64 | //other code... 65 | } 66 | Fn2(); 67 | Fn1(); 68 | //code here 69 | ``` 70 | 71 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1500299260197) 72 | 73 | 图片来自于[理解Javascript_12_执行模型浅析](http://www.cnblogs.com/fool/archive/2010/10/16/1853326.html) 74 | 75 | 此外还要注意一下几点: 76 | 77 | - 单线程 78 | 79 | - 同步执行 80 | 81 | - 唯一的全局执行环境 82 | 83 | - 局部执行环境的个数没有限制 84 | 85 | - 每次某个函数被调用,就会有个新的局部执行环境为其创建,即使是多次调用的自身函数(即一个函数被调用多次,也会创建多个不同的局部执行环境)。 86 | 87 | ## 变量提升 88 | 89 | > In javascript, every variable declaration is hoisted to the top of its declaration context. 90 | 91 | 其实可以这么理解,在创建了执行环境后,它就要为自己创建一个**活动对象**,就需要**扫描所有的局部变量,加入到对象中**去。 92 | 93 | 这时候,实际上所有的变量就被提前了。此时**活动对象就已经包含了所有的局部变量,由于作用域链的问题,最先访问的都是当前活动对象的变量**,因此当然都是可以直接访问的。但是它们可能就变成了未被赋值的,所以就会出现种种奇怪的现象。 94 | 95 | ```js 96 | var myvar = 'my value'; 97 | (function(){ 98 | alert(myvar); // undefined 99 | var myvar = 'you value'; 100 | })() 101 | ``` 102 | 103 | 同时,函数也会提前,所以可以直接访问。但是如果是**函数表达式** 就要小心了,因为**表达式只有在执行的时候才会赋值**,之前只做变量提升。 104 | 105 | ```js 106 | count(1,2); // 3 107 | function count(a,b) 108 | alert(a+b); 109 | count(1,2); // 会报错误count is not a function 110 | var count = function (a,b) 111 | alert(a+b); 112 | ``` 113 | 114 | 另外一个需要提一下的是,函数的声明是优先于变量的声明的。 115 | 116 | ## 作用域 117 | 118 | - 当代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain)。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。 119 | 120 | - 作用域链包含了执行环境栈中的**每个执行环境对应的变量对象**。通过作用域链,可以决定变量的访问和标识符的解析。 121 | 122 | **注意**:全局执行环境的变量对象始终都是作用域链的**最后一个对象。** 123 | 124 | 在访问变量时,就必须存在一个可见性的问题(内层环境可以访问外层中的变量和函数,而外层环境不能访问内层的变量和函数)。更深入的说,当访问一个变量或调用一个函数时,JavaScript引擎将不同执行环境中的变量对象按照规则构建一个链表,在访问一个变量时,先在链表的第一个变量对象上查找,如果没有找到则继续在第二个变量对象上查找,直到搜索到全局执行环境的变量对象即window对象。这也就形成了Scope Chain的概念。 125 | 126 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1500299451878) 127 | 128 | 图片来自于[理解Javascript_12_执行模型浅析](http://www.cnblogs.com/fool/archive/2010/10/16/1853326.html) 129 | 130 | 作用域链图,清楚的表达了执行环境与作用域的关系(一一对应的关系),作用域与作用域之间的关系(链表结构,由上至下的关系)。 131 | 132 | ```js 133 | //红宝书代码 134 | var color = "blue"; 135 | function changeColor(){ 136 | var anotherColor = "red"; 137 | function swapColors(){ 138 | var tempColor = anotherColor; 139 | anotherColor = color; 140 | color = tempColor; 141 | // 这里可以访问color, anotherColor, 和 tempColor 142 | } 143 | // 这里可以访问color 和 anotherColor,但是不能访问 tempColor 144 | swapColors(); 145 | changeColor(); 146 | // 这里只能访问color 147 | console.log("Color is now " + color); 148 | ``` 149 | 150 | 上述代码一共包括三个执行环境:`全局执行环境`、`changeColor()的局部执行环境`、`swapColors()的局部执行环境`。 151 | 152 | - 全局环境有一个变量color和一个函数changecolor(); 153 | 154 | - changecolor()函数的局部环境中具有一个anothercolor属性和一个swapcolors函数,当然,changecolor函数中可以访问自身以及它外围(即全局环境)中的变量; 155 | 156 | - swapcolor()函数的局部环境中具有一个变量tempcolor。在该函数内部可以访问上面的两个环境(changecolor和window)中的所有变量,因为那两个环境都是它的父执行环境。 157 | 158 | 上述代码的作用域链如下图所示: 159 | 160 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1500299544873) 161 | 162 | 结论: 163 | 164 | - **内部环境可以通过作用域链访问所有的外部环境**,但是外部环境不能访问内部环境中的任何变量和函数。 165 | 166 | - **标识符解析**(变量名或函数名搜索)是沿着作用域链**一级一级地搜索标识符的过程**。搜索过程始终从作用域链的前端开始,然后逐级地向后(全局执行环境)回溯,直到找到标识符为止,或者找到全局执行环境也没找到,undefined。 167 | 168 | ## 执行环境与作用域的区别与联系 169 | 170 | - 执行环境为**全局执行环境**和**局部执行环境**,局部执行环境是函数执行过程中创建的。 (还有一个eval环境) 171 | 172 | - 作用域链是**基于执行环境的变量对象**的,由所有执行环境的变量对象(对于函数而言是活动对象,因为在函数执行环境中,变量对象是不能直接访问的,此时由活动对象(activation object,缩写为AO)扮演VO(变量对象)的角色。)共同组成。 173 | 174 | - 当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途:**是保证对执行环境有权访问的所有变量和函数的有序访问**。作用域链的**前端**,始终都是当前执行的代码所在环境的**变量对象**。 175 | 176 | ## 没有块级作用域 177 | 178 | es6有了,用let,详细的去看es6的[let&const](../es6/let&const.md) 179 | 180 | ## 延长作用域链 181 | 182 | 1. try-catch语句的catch块; 183 | 184 | 2. with语句 185 | 186 | 看下面实例: 187 | 188 | ```js 189 | (function bildUrl(){ 190 | var qs = "?debug=true"; 191 | with(location){ 192 | var url = href + qs; 193 | } 194 | alert(url) 195 | })() 196 | ``` 197 | 198 | with会把location对象的所有属性和方法**包含到变量对象**中,并**加入到作用域链的顶部**。此时访问href实际上就是location.href。 199 | 200 | 但新声明的“url”变量会加入到最近的执行环境的变量对象里。试下面例子,说明url是可以访问到的,只是此时是undefined 201 | 202 | ```js 203 | (function bildUrl(){ 204 | var qs = "?debug=true"; 205 | if (!url) 206 | { 207 | alert("这里可以看到url"); //可以正常显示url已经被声明并且被扫描进函数的变量对象 208 | } 209 | 210 | try{ 211 | if (!a) 212 | { 213 | alert(1);// 报错因为a根本就不存在 214 | } 215 | } 216 | catch(e){ 217 | console.log("作用域链被延长了吧"); 218 | } 219 | 220 | with(location){ 221 | var url = href + qs; 222 | } 223 | 224 | })() 225 | ``` 226 | 227 | 对catch语句来说,会创建一个新的变量对象加入到作用域链的顶部,其中**包含的是被抛出的错误对象的声明。** 228 | 229 | 需要说明的是,ie8之前的版本有个不符合标准的地方,就是被势出的错误对象会被加入到执行环境的变量对象。 230 | 231 | ## 参考文章 232 | 233 | 《Javascript高级程序设计》 234 | 235 | [javascript高级程序第三版学习笔记【执行环境、作用域】](http://www.cnblogs.com/pigtail/archive/2012/07/19/2570988.html) 236 | 237 | [原生JS执行环境与作用域深入理解](http://blog.csdn.net/liujie19901217/article/details/52225025) 238 | 239 | [理解Javascript_12_执行模型浅析](http://www.cnblogs.com/fool/archive/2010/10/16/1853326.html) 240 | 241 | -------------------------------------------------------------------------------- /about_css/fc.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [Box: CSS布局的基本单位](#Box:-CSS布局的基本单位) 4 | - [块级元素(Block-level elements)与块级盒(Block-level boxes)](#块级元素Block-level-elements与块级盒Block-level-boxes) 5 | - [*匿名块盒](#*匿名块盒) 6 | - [内联盒包含块级盒](#内联盒包含块级盒) 7 | - [内联级元素(Inline-level elements)与内联盒( inline boxes)](#内联级元素Inline-level-elements与内联盒-inline-boxes) 8 | - [匿名内联盒](#匿名内联盒) 9 | - [Formatting context](#Formatting-context) 10 | - [包含块(containing block)](#包含块containing-block) 11 | - [包含块规则](#包含块规则) 12 | - [*控制盒子生成](#*控制盒子生成) 13 | - [IFC](#IFC) 14 | - [BFC有一下特性:](#BFC有一下特性) 15 | - [如何触发一个新的BFC](#如何触发一个新的BFC) 16 | - [应用场景](#应用场景) 17 | - [1.解决margin叠加问题](#1解决margin叠加问题) 18 | - [2.用于布局](#2用于布局) 19 | - [3.用于清除浮动,计算BFC高度.](#3用于清除浮动,计算BFC高度) 20 | --- 21 | 22 | ## Box: CSS布局的基本单位 23 | 24 |   Box 是 CSS 布局的对象和基本单位, 直观点来说,就是一个页面是由很多个 Box 组成的。元素的类型和 display 属性,决定了这个 Box 的类型。 不同类型的 Box, 会参与不同的 Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。让我们看看有哪些盒子: 25 | 26 | ## 块级元素(Block-level elements)与块级盒(Block-level boxes) 27 | 28 | 块级元素是源文档中那些被格式化成**视觉上的块**的元素(例如,p)。 29 | 30 | display:block, list-item, table 的元素,会生成 block-level box。 31 | 32 | 块级盒是参与**块格式化上下文**(**BFC**)的盒。每个块级元素生成一个 **主块级盒**(principal block-level box),用来包含后代盒和生成的内容,并且**任何定位模式**都与该盒有关。有些块级元素可能生成除主盒外的**额外的盒**:'list-item'元素。这些额外的盒根据主盒来放置 33 | 34 | 除了**表格盒**与**可替换元素**外,一个**块级盒**也是一个**块容器盒**。 35 | 36 | **重要:** 一个块容器盒要么只包含块级盒,要么建立了**内联格式化上下文(IFC)**并因此只包含内联盒。 37 | 38 | 不是所有的块容器盒都是块级盒:**不可替换的内联块**和**不可替换的表格单元**是块级容器,但不是块级盒。作为**块级容器的块级盒**也叫**块盒(block box)** 39 | 40 | **块盒 要求 比块级盒更加严格** 41 | 42 | ![](https://developer.mozilla.org/@api/deki/files/5995/=venn_blocks.png) 43 | 44 | ### *匿名块盒 45 | 46 | #### 块级盒包含内联和块级盒 47 | 48 | 在一个这样的文档中: 49 | 50 | ``` 51 |
    52 | Some text 53 |

    More text 54 |

    55 | ``` 56 | 57 | (假设DIV和P都有'display: block'),DIV**似乎既有内联内容也有块内容**。为了更容易定义格式,我们假设在"Some text"四周有一个***匿名块盒*** 58 | 59 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1499844512098) 60 | 61 | 换句话说:**如果一个块容器盒(例如,为上面的DIV生成的)里面有一个块级盒(例如上面的P),那么我们强制让它里面只含有块级盒** 62 | 63 | #### 内联盒包含块级盒 64 | 65 | 当一个**内联盒**包含一个流内**块级盒时**,该**内联盒**(及与它处于同一行盒里的内联祖先)会被从周围的块级盒(和任何连续的,或者仅仅被可折叠的空白字符和/或流外元素隔开的块级兄弟)中**拆分出来**,把内联盒**分成两个盒**(即使有一边是空的),**分别位于块级盒的两边**。 66 | 67 | **拆分前的行盒**与**拆分后的行盒**都被包进**匿名块盒**,并且该块级盒**成为了这些匿名盒的兄弟**。当这样一个内联盒受到相对定位的影响时,**任何由此产生的转变也会影响内联盒里面的块级盒** 68 | 69 | ```css 70 | p { display: inline } 71 | span { display: block } 72 | ``` 73 | 74 | 被应用在如下HTML文档的话: 75 | 76 | ```html 77 | 78 | 79 | Anonymous text interrupted by a block 80 | 81 | 82 |

    83 | This is anonymous text before the SPAN. 84 | This is the content of SPAN. 85 | This is anonymous text after the SPAN. 86 |

    87 | 88 | ``` 89 | 90 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1499845936333) 91 | 92 | 产生的盒将会是一个代表BODY的块盒,包含一个环绕着C1的匿名块盒,SPAN块盒和另一个环绕着C2的匿名块盒 93 | 94 | 匿名盒的属性是从**包围**它的**非匿名盒继承**来的,不可继承的属性,取其初始值。例如,匿名盒的字体是从那个DIV继承的,但margin将为0 95 | 96 | **设置在该元素上的属性仍然会应用于该元素生成的匿名盒上**。例如,如果一个border被设置在上例中的P元素上,border将会绘制在C1(在行结束的位置打开)和C2(在行开始的位置打开)周围 97 | 98 | 有些用户代理以它们的方式给内联包含块实现了border。 99 | 100 | 在处理相关的百分比值时,**匿名块盒会被忽略**:**用最近的非匿名祖先盒代替**。例如,如果上面DIV里面的匿名块盒的子级为了处理百分比高度,需要知道其包含块的包含块的高度,那么它将采用DIV形成的包含块的高度,而不是匿名块盒的 101 | 102 | ## 内联级元素(Inline-level elements)与内联盒( inline boxes) 103 | 104 | 内联级元素是源文档中那些不会为其内容形成新块的元素,内容分布于行中(例如,强调段落中的一部分文本,内联图片等等)。 105 | 106 | - 'display'属性的下列值能让一个元素变成**内联级**:'`inline`',`'inline-table`'和'`inline-block`'。 107 | 108 | - **内联级元素可以生成内联级盒(inline-level boxes)**,即参与**内联格式化上下文(IFC)**的盒 109 | 110 | - 一个内联盒(inline-box)是一个(特殊的)内联级盒,其**内容**参与了它的包含**内联格式化上下文**。一个'display'值为'**inline**'的**不可替换元素**会生成一个**内联盒**。 111 | 112 | - 不属于内联盒的内联块级盒(例如,**可替换内联级元素**,inline-block元素和inline-table元素)被称为**原子内联级盒**(atomic inline-level boxes),因为它们作为单一的不透明盒(opaque box)参与其内联格式化上下文(类似**块盒**) 113 | 114 | 内联盒》内联级盒 115 | 116 | #### 匿名内联盒 117 | 118 | 任何被直接包含在一个块容器元素中(不在一个内联元素里面)的**文本**,必须视为一个**匿名内联元素** 119 | 120 | 在一个有如下HTML标记的文档里: 121 | 122 | ``` 123 |

    Some emphasized text

    124 | ``` 125 | 126 | `

    `会生成一个块盒,里面还有几个内联盒: 127 | 128 | - "emphasized"的盒是一个由内联元素(``)生成的**内联盒** 129 | 130 | - 其它盒("Some"和"text")都是由块级元素(`

    `)生成的**匿名内联盒**,因为它们没有与之相关的内联级元素 131 | 132 | 这种匿名内联盒从它们**父级块盒继承了可继承的属性**,不可继承的属性取其初始值。示例中,匿名内联盒的颜色是从P继承的,但背景是透明的 133 | 134 | 后续将根据white-space属性合并起来的空白字符内容,不会生成任何匿名内联盒 135 | 136 | ## Formatting context 137 | 138 | Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。 139 | 140 | CSS2.1 中只有 BFC 和 IFC, CSS3 中还增加了 GFC 和 FFC。 141 | 142 | ## 包含块(containing block) 143 | 144 | 包含块是一个很重要的概念,许多盒子的位置和大小是根据一个称为“包含块”的矩形框的边缘计算的。 145 | 146 | 通常,生成的方块充当子代方块的块;我们说一个**盒子为它的后代建立了包含块**。 147 | 148 | ### 包含块规则 149 | 150 | **没啥特殊的规则,都是之前知道的,注意的就是绝对定位的盒是根据padding盒而不是content盒边** 151 | 152 | 1. [根元素](http://www.ayqy.net/doc/css2-1/conform.html#root)所在的包含块是一个被称为**初始包含块的矩形**。对于连续媒体,尺寸取**视口**的尺寸,并且被固定在画布开始的位置;对于分页媒体就是**页区(page area)**。初始包含块的'direction'属性与根元素的相同 153 | 154 | 2. 对于其它元素,如果该元素的position是'relative'或者'static',包含块由其最近的**块容器**祖先盒的**content边**形成 155 | 156 | 3. 如果元素具有'position: fixed',包含块由连续媒体的**视口**或者分页媒体的**页区**建立 157 | 158 | 4. 如果元素具有'position: absolute',包含块由最近'**position**'为'absolute','relative'或者'fixed'的祖先建立,按照如下方式: 159 | 160 | 1. 如果该祖先是一**个内联元素**,包含块就是环绕着为该元素生成的**第一个**和**最后一个**内联盒的**padding box的边界框(bounding box)**。在CSS 2.1中,如果该内联元素被跨行分割了,那么包含块是未定义的 161 | 162 | 2. 否则,包含块由该祖先的[padding边](http://www.ayqy.net/doc/css2-1/box.html#padding-edge)形成 163 | 164 | 如**果没有这样的祖先,包含块就是初始包含块** 165 | 166 | 每个盒子的position都是依赖其包含块的,但是它不受这个包含块的限制,它可能会溢出(overflow)。 167 | 168 | ### *控制盒子生成 169 | 170 | `display`属性的下列值能让一个元素变成块级的:'`block`',`list-item`和`table` 171 | 172 | 三个术语“`块级盒(block-level box)`”,“`块容器盒(block container box)`”与“`块盒(block box)`”在没有歧义的时候就简称为“块(block)” 173 | 174 | ## IFC 175 | 176 | IFC主要特点是:在一个内联格式化上下文中,**盒是一个接一个水平放置的**,从包含块的顶部开始。这些盒之间的**水平**!!margin,border和padding都有效。 177 | 178 | IFC里有一个重要的概念是Line box(行盒),行盒是包含同一行盒的一个矩形区域。行盒是因为盛放(hold)一个内联格式化上下文中的内联级内容时创建的。 179 | 180 | - 盒可能以不同的方式竖直对齐:以它们的**底部**或者**顶部**对齐,或者以它们里面的**文本的基线对齐**。包含来自**同一行的盒**的矩形区域叫做**行盒**(line box) 181 | 182 | - 行盒默认是占满包含块的所有宽度,所以默认同一IFC中的行盒宽度一致,但是浮动元素会挤行盒的宽度。所以行盒的**宽度**由**包含块**和 **浮动** 情况决定。 183 | 184 | - 同一个内联格式化上下文中的行盒**一般高度各不相同**(例如,一行可能含有一个高图片,而其它的只含文本), 一个**行盒**总是**足够高**,能够容纳它包含的所有盒。然而,它可能比它所包含的最高的盒还要高(例如,如果盒是以基线对齐) 185 | 186 | - 当一行的内联级盒的总宽度小于它们所在的行盒的宽度时,它们在行盒里的**水平分布**由['text-align'](http://www.ayqy.net/doc/css2-1/text.html#propdef-text-align)属性决定。如果该属性值为'justify',用户代理可能会拉伸内联盒(不包括inline-table和inline-block盒)里的空白和字(间距) 187 | 188 | - 当盒B的高度小于它所在的行盒的高度时(**如果等于了也就不存在对齐了**),行盒中B的**竖直对齐**方式由['vertical-align'](http://www.ayqy.net/doc/css2-1/visudet.html#propdef-vertical-align)属性决定。 189 | 190 | - 当一个**内联盒**超出一个**行盒**的宽度时,它会被**分成几个盒**,并且这些盒会**跨多行盒分布**。如果一个内联块无法分割(例如,如果该内联盒含有一个单个字符,或者特定语言的单词分隔规则不允许在该内联盒里分隔,或如果该内联盒受到了一个值为**nowrap**或者pre的**white-space**的影响),那么该内联盒会从**行盒溢出**,当一个内联盒被分割后,**margin**,**border**和**padding**在发生分割的地方(或者在**任何分割处**,如果有多处的话)**不会有可视化**效果 191 | 192 | 注意:分隔处没可视化效果! 193 | 194 | ![Image illustrating the effect of line breaking on thedisplay of margins, borders, and padding.](http://www.ayqy.net/doc/css2-1/images/inline-layout.png) 195 | 196 | ## BFC有一下特性: 197 | 198 | 1. 内部的Box会在垂直方向,从顶部开始一个接一个地放置。 199 | 200 | 2. Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生叠加 201 | 202 | 3. 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。 203 | 204 | 4. BFC的区域不会与float box叠加。 205 | 206 | 5. BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然。 207 | 208 | 6. 计算BFC的高度时,浮动元素也参与计算。 209 | 210 | ## 如何触发一个新的BFC 211 | 212 | 根据W3C的文档(https://www.w3.org/TR/CSS2/visuren.html#block-formatting) 213 | 214 | 以下情况触发BFC: 215 | 216 | 1. float 除了none以外的值 217 | 218 | 2. overflow 除了visible 以外的值(hidden,auto,scroll ) 219 | 220 | 3. display (table-cell,table-caption,inline-block, flex, inline-flex) 221 | 222 | 4. position值为(absolute,fixed) 223 | 224 | 在以上的情况会新创建BFC。 225 | 226 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1501054791196) 227 | 228 | ## 应用场景 229 | 230 | 接下我们看下怎么运用BFC,在哪些场景可以用到BFC. 231 | 232 | ### 1.解决margin叠加问题 233 | 234 | 三P每个p之间的距离为50px,发生了外边距叠加。 要解决这个叠加问题即让每个P之间是100px,我们可以新建一个BFC,怎么建呢?可以给p元素添加一个父元素,让它触发BFC。 235 | 236 | ### 2.用于布局 237 | 238 | 从图中我们会发现上面BFC的第三个特性,就是元素的左外边距会触碰到包含块容器的做外边框,就算存在浮动也会如此。那么我们如何解决这个问题呢?看上面BFC第四个特性,就是BFC不会与浮动盒子叠加,那么我们是不是可以创建一个新的BFC来解决这个问题呢?来看看: 239 | 240 | 发现我们用overflow:hidden触发main元素的BFC之后,效果立马出现了,一个两栏布局就这么妥妥的搞掂… 241 | 242 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1501055515760) 243 | 244 | ### 3.用于清除浮动,计算BFC高度. 245 | 246 | 通过设置overflow:hidden,可以建立一个新的BFC,里面的浮动元素的高度也算在里面(规则6) 247 | 248 | -------------------------------------------------------------------------------- /about_css/flex.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [flex要素](#flex要素) 4 | - [容器属性](#容器属性) 5 | - [flex-direction : row 创建主轴](#flex-direction-:-row-创建主轴) 6 | - [flex-wrap : nowrap单行,多行](#flex-wrap-:-nowrap单行,多行) 7 | - [flex-flow : direction+wrap](#flex-flow-:-direction+wrap) 8 | - [justify-content : flex-start 主轴对齐](#justify-content-:-flex-start-主轴对齐) 9 | - [align-items : stretch 侧轴对齐(单行的排列)](#align-items-:-stretch-侧轴对齐单行的排列) 10 | - [★align-content : stretch 多行侧轴对齐(坑)](#★align-content-:-stretch-多行侧轴对齐坑) 11 | - [伸缩项目](#伸缩项目) 12 | - [flex-grow : 0 放大能力(至少设为非0)](#flex-grow-:-0-放大能力至少设为非0) 13 | - [★flex-shrink:1 收缩的能力(0为不收缩)](#★flex-shrink1-收缩的能力0为不收缩) 14 | - [flex-basis : auto 占主轴的大小(可以百分比)](#flex-basis-:-auto-占主轴的大小可以百分比) 15 | - [flex : flex-grow + flex-shrink + flex-basis 优先设置](#flex-:-flex-grow-+-flex-shrink-+-flex-basis-优先设置) 16 | - [align-self: 覆盖align-items的值](#align-self:-覆盖align-items的值) 17 | - [用途](#用途) 18 | - [布局](#布局) 19 | - [参考文章](#参考文章) 20 | --- 21 | 22 | Flexbox布局(Flexible Box)模块旨在提供一个更加有效的方式制定、调整和分布一个容器里的项目布局,即使他们的大小是未知或者是动态的。(这里我们称为Flex)。 23 | 24 | Flex布局主要思想是让容器有能力让其子项目能够改变其宽度、高度(甚至顺序),以最佳方式填充可用空间(主要是为了适应所有类型的显示设备和屏幕大小)。Flex容器会使子项目(伸缩项目)扩展来填满可用空间,或缩小他们以防止溢出容器。 25 | 26 | ## flex要素 27 | 28 | 一个flex布局包含`flex容器`和`伸缩元素` 29 | 30 | 基本上,伸缩项目是沿着主轴(main axis),从主轴起点(main-start)到主轴终点(main-end)或者沿着侧轴(cross axis),从侧轴起点(cross-start)到侧轴终点(cross-end)排列。 31 | 32 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1501044556271) 33 | 34 | 根据伸缩项目排列方式不同,主轴和侧轴方向也有所变化 35 | 36 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1501044568172) 37 | 38 | ## 容器属性 39 | 40 | ### display: flex | inline-flex; 41 | 42 | 这个是用来定义伸缩容器,是内联还是块取决于设置的值。这个时候,他的所有子元素将变成flex文档流,称为伸缩项目。 43 | 44 | ```css 45 | display: other values | flex | inline-flex; 46 | ``` 47 | 48 | 请注意: 49 | 50 | - CSS的columns在伸缩容器上没有效果。 51 | 52 | - float、clear和vertical-align在伸缩项目上没有效果。 53 | 54 | ### flex-direction : row 创建主轴 55 | 56 | 这个主要用来**创建主轴**,从而定义了伸缩项目放置在伸缩容器的方向。 57 | 58 | ```css 59 | flex-direction: row | row-reverse | column | column-reverse 60 | ``` 61 | 62 | - **row(默认值)**:在“ltr”排版方式下从左向右排列;在“rtl”排版方式下从右向左排列。 63 | 64 | - **row-reverse:**与row排列方向相反,在“ltr”排版方式下从右向左排列;在“rtl”排版方式下从左向右排列。 65 | 66 | - **column:**类似 于row,不过是从上到下排列 67 | 68 | - **column-reverse:**类似于row-reverse,不过是从下到上排列。 69 | 70 | ### flex-wrap : nowrap单行,多行 71 | 72 | 这个主要用来定义伸缩容器里是单行还是多行显示,侧轴的方向决定了新行堆放的方向。 73 | 74 | ```css 75 | flex-wrap: nowrap | wrap | wrap-reverse 76 | ``` 77 | 78 | - **nowrap(默认值):**伸缩容器单行显示,“ltr”排版下,伸缩项目从左到右排列;“rtl”排版上伸缩项目从右向左排列。 79 | 80 | - **wrap:**伸缩容器多行显示,“ltr”排版下,伸缩项目从左到右排列;“rtl”排版上伸缩项目从右向左排列。 81 | 82 | - **wrap-reverse:**伸缩容器多行显示,“ltr”排版下,伸缩项目从右向左排列;“rtl”排版下,伸缩项目从左到右排列。(和wrap相反) 83 | 84 | ​ 85 | 86 | ### flex-flow : direction+wrap 87 | 88 | 这个是“flex-direction”和“flex-wrap”属性的缩写版本。同时定义了伸缩容器的主轴和侧轴。其默认值为“row nowrap”。 89 | 90 | ```css 91 | flex-flow: <‘flex-direction’> || <‘flex-wrap’> 92 | ``` 93 | 94 | ### justify-content : flex-start 主轴对齐 95 | 96 | 这个是用来定义伸缩项目沿着主轴线的对齐方式。当一行上的所有伸缩项目都不能伸缩或可伸缩但是已经达到其最大长度时,这一属性才会对多余的空间进行分配。当项目溢出某一行时,这一属性也会在项目的对齐上施加一些控制。 97 | 98 | ```css 99 | justify-content: flex-start | flex-end | center | space-between | space-around 100 | ``` 101 | 102 | - **flex-start(默认值):**伸缩项目向一行的起始位置靠齐。 103 | 104 | - **flex-end:**伸缩项目向一行的结束位置靠齐。 105 | 106 | - **center:**伸缩项目向一行的中间位置靠齐。 107 | 108 | - **space-between:**伸缩项目会平均地分布在行里。第一个伸缩项目一行中的最开始位置,最后一个伸缩项目在一行中最终点位置。 109 | 110 | - **space-around:**伸缩项目会平均地分布在行里,两端保留一半的空间。 111 | 112 | ![一个完整的Flexbox指南](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/flexbox-guide-2.jpg) 113 | 114 | ### align-items : stretch 侧轴对齐(单行的排列) 115 | 116 | 这个主要用来定义伸缩项目可以在伸缩容器的当前行的侧轴上对齐方式。可以把他想像成侧轴(垂直于主轴)的“justify-content”。 117 | 118 | ```css 119 | align-items: flex-start | flex-end | center | baseline | stretch 120 | ``` 121 | 122 | - **flex-start:**伸缩项目在侧轴起点边的外边距紧靠住该行在侧轴起始的边。 123 | 124 | - **flex-end:**伸缩项目在侧轴终点边的外边距靠住该行在侧轴终点的边 。 125 | 126 | - **center:**伸缩项目的外边距盒在该行的侧轴上居中放置。 127 | 128 | - **baseline:**伸缩项目根据他们的基线对齐。 129 | 130 | - **stretch(默认值):**伸缩项目拉伸填充整个伸缩容器。此值会使项目的外边距盒的尺寸在遵照「min/max-width/height」**属性的限制下尽可能接近所在行的尺寸。** 131 | 132 | ![一个完整的Flexbox指南](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/flexbox-guide-3.jpg) 133 | 134 | ### ★align-content : stretch 多行侧轴对齐(坑) 135 | 136 | 这个属性主要用来调准伸缩行在伸缩容器里的对齐方式。类似于伸缩项目在主轴上使用“justify-content”一样。 137 | 138 | **坑注: 请注意本属性在只有一行的伸缩容器上没有效果,会维持stretch。** 139 | 140 | ```css 141 | align-content: flex-start | flex-end | center | space-between | space-around | stretch 142 | ``` 143 | 144 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1501045558445) 145 | 146 | ## 伸缩项目 147 | 148 | ### order :0 控制出现顺序 149 | 150 | 默认情况下,伸缩项目是按照文档流出现先后顺序排列。然而,“order”属性可以控制伸缩项目在他们的伸缩容器出现的顺序。 151 | 152 | **(-1可以出现在前面,1会出现在默认之后)** 153 | 154 | ``` 155 | order: 156 | ``` 157 | 158 | ### flex-grow : 0 放大能力(至少设为非0) 159 | 160 | 根据需要用来定义**在主轴**伸缩项目的扩展能力。它接受一个不带单位的值做为一个比例。主要用来决定伸缩容器剩余空间按比例应扩展多少空间。 161 | 162 | 注意:**如果设置了宽度/高度,那么最小就是这个宽度/高度,最大可以根据容器大小扩大。如果没设宽度,则会根据内容收缩** 163 | 164 | - 如果所有伸缩项目的“flex-grow”设置了“1”,那么每个伸缩项目将设置为一个大小相等的剩余空间。 165 | 166 | - 如果你给其中一个伸缩项目设置了“flex-grow”值为“2”,那么这个伸缩项目所占的剩余空间是其他伸缩项目所占剩余空间的两倍。 167 | 168 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1501046358670) 169 | 170 | - 如果只部分元素设置了>0的数,那么其他的元素都尽可能收缩(到设置的宽度,或内容宽度),部分元素在**剩余空间内按比例排列**。 171 | 172 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1501046459655) 173 | 174 | ``` 175 | flex-grow: (默认值为: 0) 176 | ``` 177 | 178 | **负值无效(和0的功能一样)**。 179 | 180 | ### ★flex-shrink:1 收缩的能力(0为不收缩) 181 | 182 | 根据需要用来定义伸缩项目收缩的能力,同放大一样 183 | 184 | 注意:**如果元素设置了宽度/高度,那么也无法收缩**,对于没有设置宽度的,也不会收缩的小于内容宽度。 185 | 186 | ``` 187 | flex-shrink: (默认值为: 1) 188 | ``` 189 | 190 | **负值无效** 191 | 192 | ### flex-basis : auto 占主轴的大小(可以百分比) 193 | 194 | 这个用来设置伸缩基准值(就和你设置一个width/height一样),剩余的空间按比率进行伸缩。 195 | 196 | **注:只是基准值,如果设置了flex-grow一样可以扩大。不过它会根据主轴自动设置height/width** 197 | 198 | 如果是row则设置width,如果是column则设置height。 199 | 200 | ``` 201 | flex-basis: | auto (默认值为: auto) 202 | ``` 203 | 204 | ### flex : flex-grow + flex-shrink + flex-basis 优先设置 205 | 206 | 这是“flex-grow”、“flex-shrink”和“flex-basis”三个属性的缩写。其中第二个和第三个参数(flex-shrink、flex-basis)是可选参数。默认值为“0 1 auto”。 207 | 208 | ``` 209 | flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ] 210 | ``` 211 | 212 | ### align-self: 覆盖align-items的值 213 | 214 | 用来在**单独的伸缩项目**上覆写默认的对齐方式。 215 | 216 | ``` 217 | align-self: auto | flex-start | flex-end | center | baseline | stretch 218 | ``` 219 | 220 | ## 用途 221 | 222 | ### 居中 223 | 224 | flex实现居中不要太简单,justify-content:center, align-items:center就可以了 225 | 226 | ```html 227 |

    228 |
    1
    229 |
    230 | ``` 231 | 232 | ```css 233 | .flex-container { 234 | height:400px; 235 | display: -webkit-box; 236 | display: -moz-box; 237 | display: -ms-flexbox; 238 | display: -webkit-flex; 239 | display: flex; 240 | -webkit-flex-flow:row wrap; 241 | justify-content: center; 242 | align-items:center; 243 | ``` 244 | 245 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1501048007057) 246 | 247 | ### 布局 248 | 249 | 现在要实现任何布局都很简单了,双飞翼布局什么都是浮云。(因为有order) 250 | 251 | - 根据排列,设置order 252 | 253 | - 根据显示大小,设置flex(两边的侧栏主要是要设置basis) 254 | 255 | ```html 256 |
    257 |
    Header
    258 |
    259 | main 260 |
    261 | 262 | 263 |
    Footer
    264 |
    265 | ``` 266 | 267 | ```css 268 | .wrapper { 269 | display: -webkit-box; 270 | display: -moz-box; 271 | display: -ms-flexbox; 272 | display: -webkit-flex; 273 | display: flex; 274 | -webkit-flex-flow: row wrap; 275 | flex-flow: row wrap; 276 | font-weight: bold; 277 | text-align: center; 278 | .wrapper > * { 279 | flex: 1 0 100%; 280 | height:60px; 281 | .header { 282 | background: tomato; 283 | order:0; 284 | .main { 285 | text-align: left; 286 | background: deepskyblue; 287 | order:2; 288 | flex: 1 0 auto; 289 | height:200px; 290 | .aside-1 { 291 | background: gold; 292 | order:1; 293 | flex:0 0 200px; 294 | .aside-2 { 295 | background: hotpink; 296 | order:3; 297 | flex:0 0 300px; 298 | .footer { 299 | background: lightgreen; 300 | order:4; 301 | body { 302 | padding: 2em; 303 | ``` 304 | 305 | ![your text](http://o7bk1ffzo.bkt.clouddn.com/1501048744424) 306 | 307 | ## 参考文章 308 | 309 | [一个完整的Flexbox指南](http://www.w3cplus.com/css3/a-guide-to-flexbox.html) 310 | 311 | [Flex 布局教程:语法篇](http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html) 312 | 313 | -------------------------------------------------------------------------------- /about_js/event.md: -------------------------------------------------------------------------------- 1 | ## 目录 2 | --- 3 | - [事件绑定](#事件绑定) 4 | - [事件侦听](#事件侦听) 5 | - [事件委托](#事件委托) 6 | - [各类事件](#各类事件) 7 | - [键盘事件](#键盘事件) 8 | - [html事件](#html事件) 9 | - [touch事件](#touch事件) 10 | - [触摸列表](#触摸列表) 11 | - [ie和w3c不同绑定事件的区别,参数是什么,对象e参数区别](#ie和w3c不同绑定事件的区别,参数是什么,对象e参数区别) 12 | - [ie特色](#ie特色) 13 | - [绑定事件区别](#绑定事件区别) 14 | - [事件对象定位](#事件对象定位) 15 | - [鼠标当前坐标](#鼠标当前坐标) 16 | - [鼠标当前坐标(当前对象)](#鼠标当前坐标当前对象) 17 | - [获取目标](#获取目标) 18 | - [阻止事件默认行为](#阻止事件默认行为) 19 | - [组织事件冒泡](#组织事件冒泡) 20 | - [原生js实现事件代理,兼容浏览器](#原生js实现事件代理,兼容浏览器) 21 | - [自定义事件模型](#自定义事件模型) 22 | - [模拟事件](#模拟事件) 23 | - [初始化事件](#初始化事件) 24 | - [监听事件](#监听事件) 25 | - [触发事件](#触发事件) 26 | --- 27 | 28 | ## 事件绑定 29 | 30 | 1. 元素上绑定 31 | 32 | ``` 33 | 34 | ``` 35 | 36 | 2. JS代码中为元素绑定(DOM0) 37 | 38 | ``` 39 | 42 | ``` 43 | 44 | 3. JS中注册事件侦听器(DOM2) 45 | 46 | ``` 47 | 51 | ``` 52 | 53 | 使用事件侦听器有以下优点: 54 | 55 | - 可以绑定多个事件 56 | 57 | - 可以方便地解除绑定:element.removeEventListener() / detachEvent() 58 | 59 | - 可以指定是否使用事件捕获(useCapture) 60 | 61 | ## 事件侦听 62 | 63 | 事件侦听中的事件传递有两种方式,一种是冒泡事件流,一种是捕获事件流,一般只使用前者。 64 | 65 | 1. 冒泡事件流 66 | 67 | 当事件(鼠标点击等)在某一DOM元素上触发时,事件会沿着DOM树向父节点传递,如冒泡一样向上走,直到遇到绑定该事件处理器的节点。stopPropagation()可以中断冒泡。cancelBubble = true也可。若不中断,则事件会一直冒泡至文档根节点。 68 | 69 | 2. 捕获事件流 70 | 71 | 与冒泡相反,当事件在某一DOM元素上触发时,事件将从DOM根节点开始,向下传递至目标元素(不会被旁支捕获),目标元素的祖先节点若绑定有该事件类型监听器,且useCapture = true,则会对事件进行处理。 72 | 73 | __注:每个事件发生时,会先从捕获事件流开始传递,至目标节点后再冒泡向上传递。这是W3C规范中规定的3个事件阶段:捕获阶段、目标阶段、冒泡阶段。__ 74 | 75 | ## 事件委托 76 | 77 | 基于事件冒泡流,将事件处理器绑定在父元素上,提高JS执行效率,主要应用于以下场景: 78 | 79 | 1. 子元素是一组相似的元素,绑定同样的事件处理器 80 | 81 | 2. 子元素处于动态变化中,新增和删除都需要重新绑定或解绑事件处理器 82 | 83 | 在注册事件侦听器时,通过function的参数event.target可以获取到触发事件的元素。 84 | 85 | ## 各类事件 86 | 87 | ### 鼠标事件 88 | 89 | - onclick 点击或者按下回车键时触发 90 | 91 | - ondbclick 双击鼠标 92 | 93 | - onmousedown 按下鼠标还未弹起 94 | 95 | - onmouseup 用户释放鼠标按钮 96 | 97 | - onmouseover 鼠标移到某个元素上方 98 | 99 | - onmouseout 鼠标移出 100 | 101 | - onmousemove 鼠标指针在元素上移动 102 | 103 | ### 键盘事件 104 | 105 | - onkeydown 106 | 107 | - onkeypress 108 | 109 | - onkeyup 110 | 111 | ### html事件 112 | 113 | - onload:页面完全加载后在window上面触发, 114 | 115 | - onselect:当用户选择文本框中的一个或多个字符触发 116 | 117 | - onchange: 118 | 119 | - onfocus: 120 | 121 | - onblur: 122 | 123 | - onsubmit: 124 | 125 | - onreset: 126 | 127 | - onresize: 128 | 129 | - onscroll: 130 | 131 | ## touch事件 132 | 133 | - touchstart 134 | 135 | - touchmove 136 | 137 | - touchend 138 | 139 | #### 触摸列表 140 | 141 | - touches:当前屏幕所有触摸点的列表 142 | 143 | - targettouches:当前对象上所有的触摸点列表 144 | 145 | - changedtouches:涉及当前事件的触摸点的列表 146 | 147 | ## ie和w3c不同绑定事件的区别,参数是什么,对象e参数区别 148 | 149 | ### event常用属性 150 | 151 | - type 事件名称 152 | 153 | - target 目标节点(ie srcelement) 154 | 155 | - preventDefault 不执行事件关联的默认动作 (ie returnValue =false) 156 | 157 | - stopPropagation 停止传播派发事件 (ie cancelBubble=true) 158 | 159 | - nodeName 找到当前元素的标签名 160 | 161 | - altkey alt是否被按下 ctrlkey metakey 162 | 163 | - button 哪个鼠标按键 164 | 165 | - clientx 可视区域水平坐标 166 | 167 | - screenx 屏幕区 168 | 169 | - keyCode 170 | 171 | ### ie特色 172 | 173 | - cancelBubble 默认为false 174 | 175 | - srcelement 事件对象 176 | 177 | - returnvalue 默认true 178 | 179 | - fromElement toElement 180 | 181 | - offsetx 当前元素的位置 182 | 183 | ### 绑定事件区别 184 | 185 | - addEventListener('click',function(){},false) 186 | 187 | - attachEvent('onclick', function(){}) 188 | 189 | 兼容事件处理 190 | 191 | ```javascript 192 | var addEvent = { 193 | on:function(elem, type, handler){ 194 | if(elem.addEventListener{ 195 | elem.addEventListener(type, handler, false); 196 | }else if(elem.attachEvent){ 197 | elem.attachEvent('on'+type, handler); 198 | } 199 | } 200 | } 201 | var elem = document.getElementById('img'); 202 | addEvent.on(elem, 'click', function(){ 203 | console.log('添加点击事件') 204 | }) 205 | ``` 206 | 207 | ### 事件对象定位 208 | 209 | event 210 | 211 | ie8之前window.event 212 | 213 | ### 鼠标当前坐标 214 | 215 | - ie event.x event.y 相对于最近的父元素的位置 216 | 217 | - ff event.pagex event.pagey 网页 218 | 219 | - 通用 event.clientx event.clienty 220 | 221 | ### 鼠标当前坐标(当前对象) 222 | 223 | - ie event.offsetx event.offsety 224 | 225 | - ff event.layerx event.layery 226 | 227 | ## 获取目标 228 | 229 | - IE:oEvent.srcElement 230 | 231 | - DOM : oEvent.target 232 | 233 | ### 阻止事件默认行为 234 | 235 | - IE:oEvent.returnValue = false 236 | 237 | - DOM : oEvent.preventDefault 238 | 239 | ### 组织事件冒泡 240 | 241 | - IE:oEvent.cancelBubble = true; 242 | 243 | - DOM:oEvent.stopPropagation(); 244 | 245 | ## 原生js实现事件代理,兼容浏览器 246 | 247 | ```javascript 248 | function delegateEvent(interfaceEle, selector, type, fn) { 249 | if(interfaceEle.addEventListener()) { 250 | interfaceEle.addEventListener(type, eventFn); 251 | } 252 | else { 253 | interfaceEle.attachEvent(type, eventFn); 254 | } 255 | function eventFn(fn) { 256 | var e = event || window.event; 257 | var target = e.target || e.srcElement; 258 | if (matchSelector(target, selector)) { 259 | if(fn) { 260 | fn.call(target, e); //改变this指向 261 | } 262 | } 263 | } 264 | function matchSelector(ele, selector) { 265 | 266 | //if use id 267 | if(selector.charAt(0) === '#') { 268 | return ele.id === selector.slice(1); 269 | } 270 | //if use class 271 | if(selector.charAt(0) === '.') { 272 | return ele.className === selector.slice(1); 273 | } 274 | return ele.tagName.toLowerCase() === selector.toLowerCase(); 275 | } 276 | //调用 277 | var odiv = document.getElementById('odiv'); 278 | delegateEvent(odiv,'a','click',function () { 279 | // body... 280 | alert('1'); 281 | ``` 282 | 283 | ## 自定义事件模型 284 | 285 | ```javascript 286 | function Emitter() { 287 | this._listener = {}; //listener 288 | //注册事件 289 | Emitter.prototype.bind = function (eventName, callback) { 290 | var listener = this._listener[eventName] || []; 291 | listener.push(callback); 292 | this._listener[eventName] = listener; 293 | Emitter.prototype.trigger = function (eventName) { 294 | var args = Array.prototype.slice.apply(arguments).slice;//将arguments转换为数组,并获取参数 295 | var listener = _listener[eventName]; 296 | listener.forEach(function(item) { 297 | try { 298 | item.apply(this,args); //this调用此函数 299 | }catch(e) { 300 | console.error(e); 301 | } 302 | }) 303 | var emmitter = new emmitter(); 304 | emmitter.bind('myevent',function(arg1){ 305 | console.log(arg1,arg2); 306 | emmitter.trigger('myevent','','') 307 | ``` 308 | 309 | ## 模拟事件 310 | 311 | ### 创建事件 312 | 313 | ```js 314 | document.createEvent('HTMLEvents'); 315 | ``` 316 | 317 |   参数是字符串类型,表示要创建的事件类型。 318 | 319 | - uievents; 320 | 321 | - mutationevents; 322 | 323 | - htmlevents; 324 | 325 | ### 初始化事件 326 | 327 | ```js 328 | ev.initEvent('listen', false, false); 329 | ``` 330 | 331 |   参数说明: 332 | 333 | - eventType:事件名称; 334 | 335 | - canBubble:事件是否冒泡; 336 | 337 | - cancelable:是否可以用 preventDefault() 方法取消事件; 338 | 339 | ### 监听事件 340 | 341 | ```js 342 | document.addEventListener(dataavailable, handler, param3); 343 | ``` 344 | 345 |   参数说明: 346 | 347 | - dataavailable:监听的事件名称; 348 | 349 | - handler:处理函数; 350 | 351 | - param3:是否是扑获事件模型; 352 | 353 | ### 触发事件 354 | 355 | ```js 356 | document.dispatchEvent(ev); 357 | ``` 358 | 359 |   参数说明: 360 | 361 |   ev:第一步所创建的事件对象; 362 | 363 | ```html 364 | 365 | 366 | 367 | javascript自定义事件 368 | 380 | 381 | 382 |   
    383 |      384 |   
    385 | 386 | 387 | ``` 388 | 389 | --------------------------------------------------------------------------------