wksmile / blog Goto Github PK
View Code? Open in Web Editor NEW吴凯的个人博客
吴凯的个人博客
Value | function | typeOf |
"foo" | String | string |
new String("foo") | String | object |
1.2 | Number | number |
new Number(1.2) | Number | object |
true | Boolean | boolean |
new Boolean(true) | Boolean | object |
new Date() | Date | object |
new Error() | Error | object |
[1,2,3] | Array | object |
new Array(1, 2, 3) | Array | object |
new Function("") | Function | function |
/abc/g | RegExp | object |
new RegExp("meow") | RegExp | object |
{} | Object | object |
new Object() | Object | object |
null | Object | object |
undefined | undefined |
所有可以通过构造函数创建的对象都可以用 instanceof 检查类型
Object.prototype.toString.call(x) 来检查x的类型,可以区分Boolean, Number, String, Function, Array, Date, RegExp, Object, Error,null,undefined等等。
Javascript中有5种基本类型(除了symbol,es6中增加了symbol类型),以及对象类型,相信很多朋友像我一样,用了很久的js还是有点分不清怎么判断一个数据的类型。
// Numbers
console.log(typeof 37 === 'number');
console.log(typeof 3.14 === 'number');
console.log(typeof Math.LN2 === 'number');
console.log(typeof Infinity === 'number');
console.log(typeof NaN === 'number'); // 尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字"
console.log(typeof Number(1) === 'number'); // 不要这样使用!
// Strings
console.log(typeof "" === 'string');
console.log(typeof "bla" === 'string');
console.log(typeof (typeof 1) === 'string'); // console.log(typeof返回的肯定是一个字符串
console.log(typeof String("abc") === 'string'); //不要这样使用!
// Booleans
console.log(typeof true === 'boolean');
console.log(typeof false === 'boolean');
console.log(typeof Boolean(true) === 'boolean'); // 不要这样使用!
// Symbols
console.log(typeof Symbol() === 'symbol');
console.log(typeof Symbol('foo') === 'symbol');
console.log(typeof Symbol.iterator === 'symbol');
// Undefined
console.log(typeof undefined === 'undefined');
console.log(typeof blabla === 'undefined'); // 一个未定义的变量,或者一个定义了却未赋初值的变量
// Objects 使用Array.isArray或者Object.prototype.toString.call方法可以从基本的对象中区分出数组类型
console.log(typeof {a:1} === 'object');
console.log(typeof [1, 2, 4] === 'object');
console.log(typeof /^[a-zA-Z]{5,20}$/ === 'object');
console.log(typeof {name:'wenzi', age:25} === 'object');
console.log(typeof null === 'object');//true
// 下面的容易令人迷惑,不要这样使用!
console.log(typeof new Boolean(true) === 'object');
console.log(typeof new Number(1) === 'object');
console.log(typeof new Date() === 'object');
console.log(typeof new String("abc") === 'object');
console.log(typeof new Error() === 'object');
// 函数
console.log(typeof function(){} === 'function');
console.log(typeof Math.sin === 'function');
通过上面例子我们可以很明显的看到,除了基本类型以外的类型,都是对象,但是有例外:null 的 typeof 值是 'object' 【坑1】, 函数的 typeof 值是 'function' ! (函数对象的构造函数是 Function,也就继承了 Function 的原型)【坑2】,NaN 的类型也是 'number'【坑3】
注意:本文的测试在现在最新浏览器上进行,老版本浏览器可能有所不同。比如Safari 3.X中typeof /^\d*$/;为'function'【坑4:兼容性复杂】。
不是所有对象都是返回 object,而且还有 null 捣乱,那我们如何判断一个值的类型呢
var str = new String("hello world");
console.log(str instanceof String);//true
console.log(String instanceof Function);//true
console.log(str instanceof Function);//false
function Person(){
}
var Tom = new Person();
console.log(Tom.constructor === Person);//true
使用toString()方法来检测对象类型
function Type() { };
var toString = Object.prototype.toString;
console.log(toString.call(new Date) === '[object Date]');//true
console.log(toString.call(new String) ==='[object String]');//true
console.log(toString.call(new Function) ==='[object Function]');//true
console.log(toString.call(Type) ==='[object Function]');//true
console.log(toString.call('str') ==='[object String]');//true
console.log(toString.call(Math) === '[object Math]');//true
console.log(toString.call(true) ==='[object Boolean]');//true
console.log(toString.call(/^[a-zA-Z]{5,20}$/) ==='[object RegExp]');//true
console.log(toString.call({name:'wenzi', age:25}) ==='[object Object]');//true
console.log(toString.call([1, 2, 3, 4]) ==='[object Array]');//true
//Since JavaScript 1.8.5
console.log(toString.call(undefined) === '[object Undefined]');//true
console.log(toString.call(null) === '[object Null]');//true
// 下面的函数调用都返回 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
// 鲜为人知的事实:其实 Array.prototype 也是一个数组。
Array.isArray(Array.prototype);
// 下面的函数调用都返回 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray({ __proto__: Array.prototype });
instanceof 和 isArray
当检测Array实例时, Array.isArray 优于 instanceof,因为Array.isArray能检测iframes.
通过如下代码可以创建该方法
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
**什么是盒模型:**盒模型又称框模型(Box Model),包含了元素内容(content)、内边距(padding)、边框(border)、外边距(margin)几个要素。如图:
由于IE盒模型的怪异模式,IE模型和标准模型的内容计算方式不同。
IE模型和标准模型唯一的区别是内容计算方式的不同,如下图所示:
IE模型元素宽度width=content+padding,高度计算相同
标准模型元素宽度width=content,高度计算相同
通过css3新增的属性 box-sizing: content-box | border-box
分别设置盒模型为标准模型(content-box
)和IE模型(border-box
)。
.content-box {
box-sizing:content-box;
width: 100px;
height: 50px;
padding: 10px;
border: 5px solid red;
margin: 15px;
}
.content-box
设置为标准模型,它的元素宽度width=100px。
.border-box {
box-sizing: border-box;
width: 100px;
height: 50px;
padding: 10px;
border: 5px solid red;
margin: 15px;
}
.border-box
设置为IE模型,它的元素宽度width=content + 2 * padding + 2 * border = 70px + 2 * 10px + 2 * 5px = 100px。
dom.style.width/height
只能取到行内样式的宽和高,style标签中和link外链的样式取不到。dom.currentStyle.width/height
取到的是最终渲染后的宽和高,只有IE支持此属性。window.getComputedStyle(dom).width/height
同(2)但是多浏览器支持,IE9以上支持。dom.getBoundingClientRect().width/height
也是得到渲染后的宽和高,大多浏览器支持。IE9以上支持,除此外还可以取到相对于视窗的上下左右的距离以上API在浏览器中测试过,有兴趣可以都试一下
当两个垂直外边距相遇时,他们将形成一个外边距,合并后的外边距高度等于两个发生合并的外边距的高度中的较大者。注意:只有普通文档流中块框的垂直外边距才会发生外边距合并,行内框、浮动框或绝对定位之间的外边距不会合并。
且看下面例子:
<section id="sec">
<style media="screen">
* {
margin: 0;
padding: 0;
}
#sec {
background: #f00;
}
.child {
height: 100px;
margin-top: 10px;
background: yellow;
}
</style>
<article class="child"></article>
</section>
这里父元素section的高度是多少呢,100px,但是我们给section设置overflow:hidden后高度就变成110px,这是为什么呢,其实这里我们给父元素创建了BFC。,什么是BFC,请看下面的介绍。
BFC(Block Formatting Context):块级格式化上下文。
BFC决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。当设计到可视化布局的时候,BFC提供了一个环境,HTML元素在这个环境中按照一定的规则进行布局。一个环境中的元素不会影响到其他环境中的布局。
BFC的原理(渲染规则)
如何创建BFC
说了这么多规则,放几个实类出来看看。
<section id="margin">
<style>
* {
padding: 0;
margin: 0;
}
#margin {
background: pink;
overflow: hidden;
}
p {
margin: 15px auto 25px;
background: red;
}
</style>
<p>1</p>
<div style="overflow: hidden">
<p>2</p>
</div>
<p>3</p>
<p>4</p>
</section>
请看这里的第二个p元素
2
他被一个父元素包裹,并且父元素有overflow:hidden
样式,前面的如何创建BFC的第一条就说了 overflow:hidden
可以创建一个BFC。结果如下图所示。
我们看这里的2,它的上下外边距都没有与1和3发生重叠,但3与4外边距发生了重叠。这就解释了BFC创建了一个独立的环境,这个环境中的元素不会影响到其他环境中的布局,所以BFC内的外边距不与外部的外边距发生重叠。
再看看下面的列子:
<section id="layout">
<style media="screen">
#layout {
background: red;
}
#layout .left {
float: left;
width: 100px;
height: 100px;
background: pink;
}
#layout .right {
height: 110px;
background: #ccc;
}
</style>
<div class="left"></div>
<div class="right"></div>
</section>
写过前端页面的我们肯定遇到过这种情况,这里其实是浮动元素叠在 .right
元素的上面,如果我们想让.right元素不会延伸到 float元素怎么办,其实我们在.right元素上加 overflow:hidden
(用其他的方式创建BFC也可以)创建BFC就可以解决。因为BFC不会与浮动元素发生重叠。
还有一种情况很常见,就是由于子元素浮动,导致父元素的高度不会把浮动元素算在内,那么我们在父元素创建BFC就可以让可以让浮动元素也参与高度计算。
IFC这里就不介绍,大家可以自行搜索。
December 20,2017 >> 7、RSA加密通信—基于socket.io的实现
December 6,2017 >> 6、四类Javascript内存泄漏及如何避免
December 4,2017 >> 5、深入理解new操作符
December 4,2017 >> 4、jQuery-v1.10.2源码解读
December 4,2017 >> 3、stream-handbook,nodejs stream手册
December 3,2017 >> 2、gulp vs grunt
November 27,2017 >> 1、display:table-cell的应用
图片地图
介绍
图片地图允许你在一个图片上关联多个URL,目标URL的选择取决于用户点击了图片上的哪个位置。图片地图有两种类型,服务器端图片地图将所有点击提交到同一个目标URL,向其传递x,y坐标,web应用程序将该x,y坐标映射为适当的操作。客户端图片地图通过HTML的MAP标签将用户的点击映射到操作。
缺点
CSS Sprites
介绍
和图片地图一样,css Sprites也可以合并图片,减少HTTP请求,但更灵活。使用css的background-position属性,可以将HTML元素放置到背景图片中期望的位置上。
内联图片
介绍
通过使用data:URL模式可以在web页面中包含图片但无需任何额外的HTTP请求。格式如下
data:[<mediatype>][;base64],<data>
缺点
合并脚本和样式
介绍
在生产环境将多个脚本和样式表合并
介绍
如果应用程序web服务器离用户更近,则一个HTTP请求的响应时间将缩短。另一方面,如果组件web服务器离用户更近,则多个HTTP请求的响应时间将缩短。
内容发布网络(CDN)是一组分布在多个不同地理位置的web服务器,用于更加有效地向用户发布内容。
CDN用于发布静态内容,如图片、脚本、样式表和Flash。
Expires头
Web服务器使用Expires头来告诉Web客户端它可以使用一个组件的当前副本,直到指定的时间为止。可以将页面中图片样式等设置缓存,浏览器在后续的页面中会使用缓存的图片,将HTTP请求的数量减少。如下:
Expires: Mon, 15 Apr 2024 20:00:00 GMT
Max-Age和mod_expires
因为Expires头使用一个特定的时间,它要求服务器和客户端的时钟严格同步。另外,过期日期需要经常检查并且一旦未来这一天到来了,还需要在服务器配置中提供一个新的日期。
HTTP1.1中Cache-Control使用max-age指令指定组件被缓存多久,它以秒为单位定义一个更新窗。如果从组件被请求开始过去的秒数少于max-age,浏览器就使用缓存的版本,这就避免了额外的HTTP请求。对于不支持HTTP1.1的浏览器你可以同时写两个响应头Expires和max-age,并且Max-age指令会重写Expires头。
如果一个组件没有长久的Expires头,它仍然会存储在浏览器的缓存中。在后续请求浏览器会检查缓存并发现组件已经过期,浏览器为了提高效率会发送一个条件GET请求,如果组件没有改变,只会发送一个很小的头告诉浏览器可以使用其缓存的组件。
Web客户端可以通过HTTP请求中的Accept-Encoding头来表示对压缩的支持:
Accept-Encoding:gzip, deflate
如果web服务器看到请求头中有这个头,就会使用客户端列出来的方法中的一种来压缩响应。web服务器通过响应中的Content-Encoding头来通知客户端
Content-Encoding: gzip
压缩内容
通常压缩HTML文档,脚本和样式表,其实包括XML和JSON在内的任何文本响应都可以被压缩。但图片和PDF不应该压缩,因为他们本来就已经被压缩了,试图对它们进行压缩只会浪费CPU资源,还有可能会增加文件大小。
网页渲染机制
解析HTML标签,构建DOM树 >> 解析CSS标签,构建CSSOM树 >> 把DOM和CSSOM组合成渲染树(render tree) >> 在渲染树的基础上进行布局, 计算每个节点的几何结构 >> 把每个节点绘制到屏幕上 (painting)
浏览器出现白屏的原因
白屏问题
在使用样式表时,页面逐步呈现会被阻止,直到所有的样式表下载完成。所以需要将样式表放在页面顶部HEAD中。
如果把样式放在底部,对于IE浏览器,chrome等(css全部加载后再呈现,有可能等待长),在某些场景下(新窗口打开,刷新等)页面会出现白屏,而不是内容逐步展现。使用 @import 标签,即使 CSS 放入 link, 并且放在头部,也可能出现白屏。
对于图片和CSS, 在加载时会并发加载(如一个域名下同时加载两个文件)。 但在加载 JavaScript 时,会禁用并发,并且阻止其他内容的下载. 所以把 JavaScript 放入页面顶部也会导致白屏现象.
FOUC
Flash of Unstyled Content "无样式内容闪烁“:有些浏览器是边渲染边呈现,CSS放置body标签底部,会出现加载html结束后才一次性加载css样式,从而导致页面闪烁。
怎么避免出现白屏
引入位置
加入异步
没有defer或async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该script标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。
将脚本放在顶部的影响
对css表达式的频繁求值使其得以工作,但也导致css表达式的低下性能。
避开该问题
在第一次加载中内联样式脚本比外部的快,因为外部多了HTTP请求。但是外部javascript和css文件有机会被浏览器缓存起来。而HTML文档通常不会被缓存,这样每次文档下载都会下载内联的样式文档和脚本。
两全其美
下面的方式既可以获得内联的优势,同时也能缓存外部文件。
加载后执行
通过创建对应的DOM元素(script和link)并赋予URL来实现
动态内联
通过cookies做指示器,让主页服务器知道一个组件是否在浏览器的缓存中。如果cookie不存在就内联JS和css,如果cookie出现了,则有可能外部组件位于浏览器缓存中。
介绍
Internet是通过IP地址来查找服务器的,DNS将主机名映射到IP地址上。如果一个服务器被另外一个具有不同IP地址的服务器替代了,DNS允许用户使用同样的主机名来连接到新的服务器。
DNS缓存和TTL
DNS信息会留在操作系统的DNS缓存中,很多浏览器拥有其自己的缓存,和操作系统的缓存相分离。只要浏览器在其缓存中保留了DNS记录,它就不会麻烦操作系统来请求这个记录,否则会向操作系统询问地址。
由于IP地址会变化以及缓存会消耗内存,因此应该周期性地消除缓存中的DNS记录,并通过大量不同的配置检测清除的频率有多高。
影响DNS缓存的因素
服务器可以表明记录可以被缓存多久,查找返回的DNS记录包含了一个存活时间(Time-to-live,TTL)值。尽管操作系统缓存会考虑TTL值,但浏览器通常忽略该值,并设置它自己的时间限制。只要浏览器和web服务器通信着,并保持TCP连接打开的状态,就没理由进行DNS查找。
精简
精简是从代码中移除不必要的字符以减小其大小,进而改善加载时间的实践。精简后所有的注释以及不必要的空白字符都将被移除。
混淆
混淆是可以应用在源代码上法的另外一种优化方式,和精简一样它也会移除注释和空白,同时它还会改写代码,函数和变量的名字将被转换为更短的字符串。通常这样做是为了增加对代码进行反向工程的难度。
缺陷
由于混淆更加复杂,混淆过程本身很有可能引入错误。
维护
混淆会改变javascript符号,因此需要对任何不能改变的符号进行标记,防止混淆其修改它们。
调试
经过混淆的代码很难阅读,这使得在产品环境中调试问题更加困难。
锦上添花
介绍
重定向用于将用户从一个URL重新路由到另一个URL。重定向会使页面变慢。
重定向的类型如下,应该使用301,302,这样可以确保后退按钮能够正确工作。
301,302,在实际中都不会被缓存,除非有附加的头。
html文档的头中包含的meta refresh标签可以在其content属性所指的秒数之后重定向用户。
<meta http-equic="refresh" content="0; url=http://baidu.com" >
javascript也可以重定向,将document.location设置为期望的URL即可。
重定向之外的其他选择
缺少结尾的斜线:缺少结尾的/会301重定向。
连接网站:重定向可以将旧网站连接到新的网站,但还可以其他形式将一个网站的不同部分连接起来,以及基于一些条件来引导用户。
跟踪内部流量:重定向经常用于跟踪用户流量的流向。通过分析来自www.yahoo.com的web服务器日志可以得到人们离开的首页后的流量去向。
也可以使用referer日志来跟踪流量去向,每个http请求都包含一个url,表明从哪个页面发起的请求,也就是引用方。使用referer日志避免了向用户发送重定向,也就改善了响应时间。
美化url:使用重定向的另一种动机是使url更加美观并且易于记忆,在前面的“缺少结尾的斜线”一节后,知道了结尾多了个“/”,不利于美观。关键是要找出一种方式,无需重定向就能拥有如此简洁的url,与其让用户忍受额外的http请求,最好还是使用“连接网站”一节中介绍的aLIas,mod_rewrite DIrectorySlash和直接连接代码来避免重定向。
避免重复脚本
介绍
实体标签(Entity Tag,ETag,HTTP1.1)是web服务器和浏览器用于确认缓存组件有效性的一种机制。
浏览器在条件GET请求检测缓存的组件是否和原始服务器上的组件匹配时有两种方式:
最新修改时间
原始服务器通过Last-Modified响应头来返回组件的最新修改日期。
实体标签
ETag是唯一标识了一个组件的一个特定版本的字符串,该字符串必须用引号引起来。
服务器返回ETag字段到浏览器,此后浏览器访问服务器会使用If-None_Match头将ETag传回原始服务器进行比较,如果匹配返回304状态码。
ETag带来的问题
当浏览器从一台服务器上获取了原始组件,之后又向另外一台不同的服务器发起条件GET请求时,ETag不会匹配,这对于使用服务器集群来处理请求的网站来说很常见。
ETag还降低了代理缓存的效率。代理后面用户缓存的ETag经常和代理缓存的ETag不匹配,这导致不必要的请求被发送到原始服务器。
If-None-Match比If-Modified-Since具有更高的优先级,只要使用了ETag,即使ETag不匹配也不会看Expires而返回304.
ETag是否该用
如果你的组件必须通过最新修改日期之外的一些东西来进行验证,则ETag是一种强大的方法。如果你无须自定义ETag的内容,最好简单地将其移除。
改善Ajax请求
改善Ajax请求最重要的方式就是使响应可缓存,其他的规则也有一些适用于Ajax请求:
网格容器
通过在元素上声明 display:grid 或 display:inline-grid 来创建一个网格容器。一旦我们这样做,这个元素的所有直系子元素将成为网格项目。
网格容器
通过 grid-template-columns 和 grid-template-rows 属性来定义网格中的行和列。这些属性定义了网格的轨道。一个网格轨道就是网格中任意两条线之间的空间。若只定义了列,则会让网格按所需的内容创建行。
fr单位
轨道可以使用任何长度单位进行定义。 网格还引入了一个额外的长度单位来帮助我们创建灵活的网格轨道。新的fr单位代表网格容器中可用空间的一等份,如
grid-template-columns: 1fr 2fr 1fr;
表示把网格容器可用宽空间分成4等分,第一第三轨道为一等分,第二轨道为二等分。如下
grid-template-columns: 500px 1fr 2fr;
表示第一个轨道是500像素,这个固定宽度被从可用空间中取走。剩下的空间被分为三份,按比例分配给了两个弹性尺寸轨道。
在轨道清单中使用repeat()
Repeat 语句可以用于重复轨道列表中的一部分。
grid-template-columns: 1fr 1fr 1fr;
grid-template-columns: repeat(3, 1fr); // 与上面相同,表示重复1fr 3次
grid-template-columns: 20px repeat(6, 1fr) 20px; // repeat也可以只用一部分,表示20像素,接着重复了6个1fr的轨道,最后一个20像素的轨道
隐式或显示网格
显示就是你用grid-template-columns 和 grid-template-rows定义的网格,而当增加内容网格自动创建行和列的表示隐式网格。grid-auto-rows 属性用来设置在隐式网格中的轨道高度。
轨道大小minmax()
设置最大最小值,比如设置 grid-auto-rows: minmax(100px, auto); 表示最小轨道的高度为100px,最大自动根据内容设置。
网格线
前面我们用的grid-template-columns和grid-template-rows都是轨道布局,我们也可以用网格线布局。grid-column-start和grid-column-end属性可以合并为 grid-column,grid-row-start和grid-row-end则合并为grid-row。如下为网格线编号,这个编号顺序取决于书写模式。grid-area为上面的四个属性的合写,顺序与margin的顺序相反。
如下,box1从列线1开始,延伸至列线4,也就是我们这个例子中最右边的列线。并从行线1延伸到行线3,占据了两个行轨道。第二个元素从列线1开始,延伸了一个轨道。因为这是默认行为,所以我不用指定结束线。并且它从行线3到行线5,跨越了两个行轨道。剩下的元素会把自己安放到网格空余的空间中。
<div class="wrapper">
<div class="box1">One</div>
<div class="box2">Two</div>
<div class="box3">Three</div>
<div class="box4">Four</div>
<div class="box5">Five</div>
</div>
/************************************/
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px;
}
.box1 {
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 3;
}
.box2 {
grid-column-start: 1;
grid-row-start: 3;
grid-row-end: 5;
}
网格间距
在两个网格单元之间的网格横向间距或网格纵向间距可使用grid-column-gap和grid-row-gap属性来创建,或者直接使用两个合并的缩写形式grid-gap设置大小。
命名网格区域
grid-area除了可以用网格线编号定义区域,还可以用于给区域命名。为了创建如下的布局,我们先命名区域然后用grid-template-areas定义区域;
.header {
grid-area: hd;
}
.footer {
grid-area: ft;
}
.content {
grid-area: main;
}
.sidebar {
grid-area: sd;
}
.wrapper {
display: grid;
grid-template-columns: repeat(9, 1fr);
grid-auto-rows: minmax(100px, auto);
grid-template-areas:
"hd hd hd hd hd hd hd hd hd"
"sd sd sd main main main main main main"
"ft ft ft ft ft ft ft ft ft";
}
/******************************************/
<div class="wrapper">
<div class="header">Header</div>
<div class="sidebar">Sidebar</div>
<div class="content">Content</div>
<div class="footer">Footer</div>
</div>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.