learngitagain
candywxt / candywxt Goto Github PK
View Code? Open in Web Editor NEWlearngitagain
learngitagain
判断一个变量的类型,我们通常用typeof
variable
typeof 12 // "number"
typeof arr // "undefined"
typeof 'arr' // "string"
function fn() {};
typeof fn // "function"
typeof true // "boolean"
typeof [] // "object"
typeof {} // "object"
但是Array属于object,所以并不能用typeof来判断一个数组,这时我们可以用variable instanceof
data type
var arr = [];
arr instanceof Array; // true
还有一个判断任意数据类型的方法: Object.prototype.toString.call(arg);
我们知道在javascript里面,数组是Object的一种,所以我们可以用Object对象原型toString方法,如果对象是数组,则该函数返回[object Array]
,同样如果对象是Object则该函数返回[object Object]
,因为Number,String,Boolean,Array,Function都继承自JavaScript内置的Object对象,而每一个变量都是与其类型相应的对象的一个实例。
Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call(1); // "[object Number]"
Object.prototype.toString.call(fn); // "[object Function]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(null); // "[object Null]"
新项目的技术选型为:redux + react + immutable + pounchdb
技术 | 作用 |
---|---|
redux | 框架,决定应用形态 |
react | 视图 |
immutable | 数据结构 |
pounch | 前端数据库 |
learn redux
Redux 是 JavaScript 状态容器。提供可测试化的状态管理。 可以让你构建一致化的应用。
运行于不同的环境(客户端,服务器,原生应用),并且易于测试。Redux 由 Flux 演变而来。
应用中所有state都以一个对象树的形式存储在一个单一的store中。唯一改变的state的办法是触发action,一个描述发生什么的对象。为了描述action如何改变state树,你需要编写reducers。
一个项目你至少包含这些文件(夹)
project
|
+ -- actions
| |
| \ -- action.js
|
+ -- components
| |
| \ -- conponents.js
|
+ -- containers
| |
| \ --Root.js
|
+ -- reducers
| |
| \ -- index.js
|
+ -- store
| |
| \ -- configurStore.js
|
+ -- index.js
好,那么我们创建一个Store(应用中有且仅有一个store);
createStore(reducer,[initialState])
参数 | 类型 | 作用 |
---|---|---|
reducer | Function | 接收两个参数,分别是当前的state 树和要处理的action ,返回新的state 树 |
[initialState] | 任何值 | 初始时的state。 |
返回 | 类型 | 作用 |
---|---|---|
store | Object | 保存了应用所有的state对象。 |
改变state的唯一方法是 dispatch action
。也可以 subscribe
监听state的变化。然后更新UI
示例
//http://camsong.github.io/redux-in-chinese/docs/api/createStore.html
import { createStore } from 'redux';
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([action.text]);
default:
return state;
}
}
let store = createStore(todos, ['Use Redux']);
store.dispatch({
type: 'ADD_TODO',
text: 'Read the docs'
});
console.log(store.getState());
// ['Use Redux', 'Read the docs']
store存储了应用所有的state tree。
getState()
返回当前state tree。相当于返回最新的store's reducer
dispatch ( action )
参数: action { Object } ; 一个原生对象用来表述应用更新。
返回值: { Object } ; 当你用createStore来创建store的时候,你应该传入plain Object;但当你使用applyMiddleware来createStore的时候,就会有所不同。他会支持异步比如:promises,observables,thunks。
subscribe( listener )
getReducer()
返回当前正在使用的reducer
replaceReducer
已被弃用了
参数:reducers { Object }
返回 :{ function }
//reducers.js
export function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([action.text]);
default:
return state;
}
}
export function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
//app.js
import { createStore, combineReducers } from 'redux';
import * as reducers from './reducers';
console.log(reducers);
// {
// todos: Function,
// counter: Function
// }
let reducer = combineReducers(reducers);
let store = createStore(reducer);
console.log(store.getState());
// {
// counter: 0,
// todos: []
// }
store.dispatch({
type: 'ADD_TODO',
text: 'Use Redux'
});
console.log(store.getState());
// {
// counter: 0,
// todos: ['Use Redux']
// }
这是一个被推荐使用的用来扩展redux的方法。他的主要特点是可以使用异步。
你可以用:thunk , promise 等等。
流程是: ({getState , dispatch }) => next => action
返回: { function } 返回用middleware创建的createStore
//引用applyMiddleware
import { createStore , applyMiddleware } from 'redux'
//你可以引用一个thunk来实现异步
import thunk from 'redux-thunk'
import * as reducers from './reducers'
//创建一个以middleware创建的createStore
let createStoreWithMiddleware = applyMiddleware(thunk)(createStore)
// 创建一个store
let reducer = combineReducers(reducers)
let store = createStoreWithMiddleware(reducer);
function fetchSecretSauce() {
return fetch('http://www.abc.com')
}
//接下来就可以使用thunk了
function makeASandwichWithSecretSauce(forPerson){
//返回一个函数,这样可以异步执行
return function(dispatch) {
return fetchSecretSauce().then(sauce => dispatch(forPerson,sauce) );
} ;
};
参数:actionsCreators { Function or Object } 一个action 生成器。或者一个object的值是action生成器。
dispatch:{ Function } 一个可用的dispatch function
返回:{ Function or Object } 类似于原生object,但是拥有dispatch方法。
//injected by react-redux
let { todos, dispatch } = this.props;
//使用bindActionCreators
let boundActionCreators = bindActionCreators(TodoActionCreators, dispatch);
从左到右来组合多个函数。这是函数式编程中的方法。
参数:需要合成的多个函数,每个函数都接收一个函数作为参数,然后返回一个函数。
返回: 从左到右把接收到的函数合成后的最终函数。
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import * as reducers from '../reducers/index';
let reducer = combineReducers(reducers);
let middleware = [thunk];
let finalCreateStore;
// 生产环境中,我们希望只使用 middleware。
// 而在开发环境中,我们还希望使用一些 redux-devtools 提供的一些 store 增强器。
// UglifyJS 会在构建过程中把一些不会执行的死代码去除掉。
if (process.env.NODE_ENV === 'production') {
finalCreateStore = applyMiddleware(...middleware)(createStore);
} else {
finalCreateStore = compose(
applyMiddleware(...middleware),
require('redux-devtools').devTools(),
require('redux-devtools').persistState(
window.location.href.match(/[?&]debug_session=([^&]+)\b/)
),
createStore
);
// 不使用 compose 来写是这样子:
//
// finalCreateStore =
// applyMiddleware(middleware)(
// devTools()(
// persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))(
// createStore
// )
// )
// );
}
let store = finalCreateStore(reducer);
1、javascript的数据类型
javascript 是弱类型语言,不需要定义数据类型即可对其负值;
var num = 32;
num + num // 64
num + 'num' //32num 变成字符串了
num-'num'//NaN
好了,我们遇到了一个NaN,为什么是NaN呢,通常情况下,NaN出现在以下情况中:
//比如上面的计算,数字和字符串做减法运算
//一般无效的结果都是NaN
1 / 'a' //NaN
parseInt('abc'); // NaN
用全局函数isNaN
可以判断是否为NaN
isNaN(1);//false
isNaN("num");//true
isNaN(NaN);//true
isNaN("1");//false why?
NaN属于number类型,number类型的特殊值除了NaN还有infinity(无限大),NaN于任何值都不相等,包括它自己
NaN == NaN; //flase
NaN === NaN; //flase
typeof NaN; //number
javascript 有六种数据类型:string
number
boolean
null
undefined
object
其中function
array
date
等都属于object
javaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里
javasScript中一切皆是对象,函数也是。
作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。
在Javascript中,变量的作用域有全局作用域和局部作用域两种。
1️⃣ 最外层函数和最外层函数外面定义的变量拥有全局作用域,例如:
var name = '王欣彤';
function doSomething() {
var englishName = 'Candy';
function innerSay(){
console.log(englishName);
}
innerSay();
}
console.log(name);//王欣彤
console.log(englishname);//脚本错误
doSomething();//Candy;
innerSay();//脚本错误
2️⃣ 所有未定义直接负值的变量自动声明为拥有全局作用域,例如:
function doSomething(){
var name = '王欣彤';
englishName = 'Candy'
alert(authorName);
}
doSomething(); //王欣彤
alert(englishName); //Candy
alert(name); //脚本错误
3️⃣ 所有window对象的属性拥有全局作用域
顾名思义,局部作用域一般只在固定的代码片段内可以访问到,最常见的例如函数内部。
function doSomething(){
var blogName="梦想天空";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //脚本错误
innerSay(); //脚本错误
在一个函数被定义的时候,会将它定义时刻的scope chain链接到这个函数对象的[[scope]]属性。
在一个函数对象被调用时,会创建一个活动对象,然后对于每一个函数的形参,都命名为该活动对象的命名属性,然后将这个活动对象作为此时的作用域链(scope chain)的最前端,并将这个函数对象的[[scope]]加入到scope chain中去。
举个例子:
var x = 10;
function foo() {
var y = 20;
function bar() {
var z = 30;
alert(x + y + z);
}
bar();
}
foo(); // 60
globalContext.VO === Global = {x:10 , foo <funtion>};
foo.[[Scope]] = {globalContext.VO};
fooContext.AO = {y:20,bar<function>};
fooContext.Scope = fooContext.AO + foo.[[scope]];
= {
fooContext.AO,
globalContext.VO;
};
bar.[[scope]] = {fooContext.AO,globalContext.VO}
barContext.AO = {z:30};
barContext.Scope = barContext.AO + bar.[[scope]];
= {
barContext.AO,
fooContext.AO,
globalContext.VO;
}
寻找x:barContext.AO,//undefined
fooContext.AO,//undefined
globalContext.VO;//10
寻找y:barContext.AO,//undefined
fooContext.AO,//20
寻找z:barContext.AO,//30
始终记得函数的[[scope]]是在被定义时就确定的,遇到问题像上述例子一样解析一下就知道怎么查找变量了。如果在作用域链仍然找不到变量的话,就会深入到原型链中(下一篇),如果依然找不到就会undefined。
要求如下:
允许使用鼠标点击选中提示栏中的某个选项
允许使用键盘上下键来选中提示栏中的某个选项,回车确认选中
选中后,提示内容变更到输入框中
初级班:
不要求和后端交互,可以自己伪造一份提示数据例如:
var suggestData = ['Simon', 'Erik', 'Kener'];
Ajax的核心技术是XHR(Xml http request)对象,可以通过XHR获取服务器的数据,然后再通过DOM插入页面中呈现,传输的数据格式可以为XML或JSON等
//XHR是javascript的一个对象,所以创建它只要一个new就好了
var xhr = new XMLHttpRequest();
//初始化open有五个参数
void open{
method,//必填
url,//必填
async,//可选 布尔值
user,//可选
password//可选
}
//初始化我们的xhr
xhr.open{
//我们启动一个针对candy.aspx的get请求,在这里url是执行代码的当前页面(使用相对路径),调用open方法并不会真正发送请求,而只是启动一个请求准备发送。
'GET',
'candy.aspx',
'false'
}
//真正要发送请求需要send()方法,send()方法接收一个参数即要请求主体发送的数据,如果不需要请求主体发送数据,则我们需要填入一个null参数,在调用send()方法后,请求就会被分派到服务器。
xhr.send(null);
在发送完请求后我们需要判断请求是否执行成功
if (xhr != null) {
xhr.onreadystatechange = function() {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
//// Do something.
}
else {
alert("Request was unsuccessful: " + xhr.status);
}
};
xhr.open("GET", "www.candy.aspx", true);
xhr.send(null);
}
我们刚刚发送了同步请求,如果我们发送异步请求那么在请求的过程中javascript的代码会继续执行这时可以通过readyState属性来判断请求的状态,当readyState = 4时,表示收到所有响应数据,属性值的定义如下
readyState的值 | 描述 |
---|---|
0 | 未初始化,尚未调用open()方法 |
1 | 启动,但还没有调用send()方法 |
2 | 已发送,但还没收到响应 |
3 | 已接受到部分响应 |
4 | 完成,收到全部响应 |
挖坑~
任务描述:
第一阶段
在页面中,有一个单行输入框,一个按钮,输入框中用来输入用户的兴趣爱好,允许用户用半角逗号来作为不同爱好的分隔。
当点击按钮时,把用户输入的兴趣爱好,按照上面所说的分隔符分开后保存到一个数组,过滤掉空的重复的爱好,在按钮下方创建一个段落显示处理后的爱好。
先写html结构
<body>
<input id="hobby" placeholder="请输入你的爱好">
<button id="submit" type="submit">提交</button>
<p id="result"></p>
</body>
看到题干,首先知道我们需要有一个文本框用来让用户输入爱好,我们需要在点击了按钮之后将爱好显示在一个<p>
内,那么我们就需要取出文本框<input>
的内容放在<p>
里,在点击<button>
之后,首先先把要取出来的元素都取出来
var hobby = document.getElementById("hobby").value,
result = document.getElementById("result"),
sub = document.getElementById("submit");
东西取出来之后先分析下会发生什么事情,<sub>
按钮在点击后会将文本“传递”到<p>
里,那么给<sub>
添加一个<onclick>
事件,当触发<onclick>
将会发生“传递”,这个“传递”我先叫他<fn>
EventUtil.addHandler(sub,"click",fn);
说道监听事件,我在之前写了一个EvenUtil对象,这样就可以方便的为元素添加
var EventUtil = {
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attatchEvent("on"+type,handler);
}else{
element["on"+type] = handler;
}
},
removeHandler:function(elment,type,handler){
if(element.removeEventListener){
element.removeEventListener(type,handler,false);
}else if(element.detachEvent){
element.detachEvent("on"+type,handler);
}else{
element["on"+type]=null;
}
}
}
接下来就是我们在点击之后要做什么事情了,封装<fn>
函数
我们先简单点,先把<hobby>
里面的内容添加在<result>
里面
var fn(){
var hobby = document.getElementById("hobby").value;
result.innerHTML = hobby;
}
接下来,我们需要把<hobby>
得到的字符串变成数组,在第一个阶段,我们可以使用<split>
来分割数组
//定义一个变量来存放数组
var str = hobby.split(",");
//输出str~
result.innerHTML = str;
现在我们将得到的字符串按照分隔符分割成了数组,接下来我们要将这个数组进行去重,去空操作。
我们定义这样一个去重函数function remoSpace(arr)
和function uniqArray(arr)
function remoSpace(arr){
//获取数组长度
var len=arr.length;
//获取数组最后一个元素的下标--i,从后往前,遇到空格就删除,删除的位置刚好就为i所在的位置
while( --len > 0) {
if(!str[len]||str[len]== ''){
str.splice(len,1);
}
}
return str;
}
//去重的方法也差不多
function uniqArray(arr){
var len = arr.length;
while(--len){
for(var i=0;i<len;i++){
if(arr[len] == arr[i]){
arr.splice(len,i);
break;
}
}
}
return arr;
}
数组去重去空完毕之后我们第一阶段就完成了!
接下来第二阶段
第二阶段
单行变成多行输入框,一个按钮,输入框中用来输入用户的兴趣爱好,允许用户用换行、空格(全角/半角)、逗号(全角/半角)、顿号、分号来作为不同爱好的分隔。
当点击按钮时的行为同上
单行变成多行
<textarea id="hobby" placeholder="请输入你的爱好"></textarea>
在阶段一中我们使用的是简单的split(",")
来分割字符串使其变成数组,阶段二中我们需要更多的方法,这就需要用到正则表达式
\s 匹配一个空白字符,包括空格、制表符、换页符和换行符。
那么我们也就是需要加上逗号,顿号,分号等字符。
if(hobby){
var str = hobby.split(/\s|,|、|;/i);
}
//顺便用上我们之前的去重去空函数
str = remoSpace(str);
str = uniqArray(str);
这样阶段二也完成了
第三阶段
用户输入的爱好数量不能超过10个,也不能什么都不输入。当发生异常时,在按钮上方显示一段红色的错误提示文字,并且不继续执行后面的行为;当输入正确时,提示文字消失。
同时,当点击按钮时,不再是输出到一个段落,而是每一个爱好输出成为一个checkbox,爱好内容作为checkbox的label。
先做第一步判断数组长度是否在1-10之间。
if(str.length > 0 && str.length <=10){
//输出爱好!
}else if(str.length === 0){
//爱好不能为空!
}else if(str.length > 10){
//个数不能超过10个!
}
再来将错误显示出来,在显示错误之前,我们需要新创建一个文本节点
//我们不妨将错误情况变成一个函数error()
function error(){
var error = document.createElement("p"),
node = document.createTextNode("错了!");
error.style.color="red";
error.appendChild(node);
sub.parentNode.insertBefore(error,sub);
}
//但是这样每次出错都会新加一个节点,并且节点并不会删除,要怎么动态删除节点呢……
任务描述
界面首先有一个文本输入框,允许按照特定的格式YYYY-MM-DD输入年月日;
先写界面
<label for="time">输入日期:<input id="time" type="text" placeholder=" YYYY-MM-DD"></label>
然后将得到的字符串按照-
分组,设置Date
,用来倒计时~
var arr = time.value.split("-");
var setDate = new Date(arr[0],arr[1]-1,arr[2]);
输入框旁有一个按钮,点击按钮后,计算当前距离输入的日期的00:00:00有多少时间差
<button type="submit" id="btn">开始计时!</button>
btn.onclick = function(){
//开始计时
//获得时间差
difTime = setDate.getTime() - new Date().getTime();
//判断时间是否可以倒计时
if(difTime>0){
//可以
}else{
//过去的时间不能倒计时
console.log("wrong!");
}
}
在页面中显示,距离YYYY年MM月DD日还有XX天XX小时XX分XX秒
每一秒钟更新倒计时上显示的数
如果时差为0,则倒计时停止
判断完之后我们需要显示时间差并且每秒刷新一次,需要用到setInterval()
和clearInterval()
interval = setInterval(function(){
//显示倒计时
//myCode
update();
},1000)
怎么显示呢。。我们的html结构需要给一个显示的位置,所以在html页面里面添加一个p
<p id="result"></p>
那么继续编写我们的myCodeupdate()
function update(){
self.setInterval(result.innerHTML = difTime--,1000)
}
好了他可以倒计时了,但是这肯定不是我们想要的效果,这样的毫秒数太不好读了,我们需要将difTime
改变一个好看的样式
var oD = parseInt(difTime/3600/24/1000);
var oH = parseInt((difTime/1000-oD*24*3600)/3600);
var oM = parseInt((difTime/1000-oD*24*3600-oH*3600)/60);
var oS = difTime%60;
离成功更近了一步,接下来输出所得,我发现直接将reault.innerHTML = oD+"天"
会报出Uncaught SyntaxError: Unexpected token ILLEGAL
错误
任务描述
图片数量及URL均在HTML中写好
可以配置轮播的顺序(正序、逆序)、是否循环、间隔时长
图片切换的动画要流畅
在轮播图下方自动生成对应图片的小点,点击小点,轮播图自动动画切换到对应的图片
这是第一次写轮播图,网上找了几个demo,看了一些教程,研究了一下代码,发现轮播图的关键就是能够正确的判断出如何修改图片的位置以让它正确的显示。
在写HTML的时候就应该要想到修改哪些值会使得图片正确显示。
<ul>
,更多的是用<div>
和<a>
,重构时将这些标签根据情景更换成了<ul>
或<dl>
;<div>
。重构时使用border
做线条。float
。个人不喜欢使用float
。重构时,如果需要并排显示,则多用:diplay:inline-block;
float
诞生的原意:使文字包裹在图片周围。则说明我们不应该过多的使用float
来做布局排版。并且display
,就是用来排版的。clear:both
(添加多余标签,不推荐)clear:both
clearfix
类。float
的使用。所以并没有很多的clear方法。所以最终还是要减少使用float
啊。个人不足
hack技巧不够。对IE并不友好。然后就对饿了么产生了崇高的敬意!!好吧 ,未来我会花时间在学习hack技巧上的。
实现了鼠标切换,实现了无限滚动。
要求:至少 3 个,技术不限,也可以是交互方面的内容,并说明改进原因;
<a>
链接就弹出一个新窗口。so,点一会菜就会开很多个窗口。这真是百问不厌的问题啊。最初做前端是因为它很美(那些H5动画,SVG,WebGL做出来的东西多酷炫)。学了一段之后发现它很有用。(比如我可以自定义一些chrome插件来使生活更有趣和便捷)更多的学习之后我发现,学前端的都是活泼可爱的程序员,这些小伙伴真的太有趣了。然而,当我技术达到,我还是希望我可以回报社会,能写出有利于残障人士浏览的网页~
做这套题是意料之外的。本以为发个简历就好了。没想到小鱼给了一个链接说做完发给他。奈何!!我周六周日时间已经安排好了。周一又要实习。(目前在一家小公司实习,更加坚定了我需要一个有活力,团队氛围超级棒的平台。所以开始寻找下一个实习。刚好看到饿了么,那么这就是缘分,希望可以一切顺利~)于是加了两天夜车,做了下题。
根据自己的理解,第一题应该是考察语义化,和一些常见的布局技巧,hack技巧。第二题应该考察的是对JS面向对象编程的理解,以及相关的dom操作,事件操作。第三题考察的是对自己未来所在的公司是否有足够的了解。第四题应该是看你这个人是不是公司合适的人~
最后,非常感谢小鱼每次都很及时的回复信息。
And,最后的最后,希望给个面试机会~~
(function(window,undefined){
var jQuery = (function(){
})();
window.jQuery = window.$ = jQuery
})(window)
1、为什么要用自调用匿名函数?
因为这样就可以在加载完jQuery文件时可以立即执行了啊~
2、为什么传入window?
因为这样就将window对象变成参数传进来变成私有对象了,方便回溯引用。同时还利于压缩代码~
3、为什么传入undefined?
因为这样undefined就真的是undefined了
(function(window,undefined){
var jQuery = (function(){
var jQuery = function(selector, context){
return new jQuery.fn.init (selector, context, rootjQuery );
},
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ){...},
//一堆原型属性和方法
};
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function(){...};
jQuery.extend({
//一堆静态属性和方法
});
return jQuery;
})();
window.jQuery = window.$ = jQuery
})(window)
1、为什么我们可以不用new构造jQuery对象呢?
因为我们return 了一个new jQuery.fn.init()啊
2、为什么把jQuery.prototype赋给jQuery.fn呢?
因为这样可以少写挺多字的…同时在重写jQuery时我们把constructor重新指回了jQuery;原型链就完整了!
3、为什么又把jQuery.fn赋值给了jQuery.fn.init.prototype呢…
因为你return 的是jQuery,而jQuery return 的是new jQuery.fn.init() 所以为了让jQuery.fn上的方法都成为jQuery.fn.init原型上的方法,这样你得到的jQuery才完整。
4、喂,我发现里面还有一个自调用匿名函数,这么多匿名函数不是多余的吗?
其实去掉也无妨,只是去掉之后潜在增加构造函数jQuery对象模块与其他模块的耦合度。通过把这些局部变量包裹在一个自调用匿名函数中,实现的其实是高内聚低耦合的设计**!所以jQuery很ncie啊!
5、为什么有一个jQuery.extend 和一个jQuery.fn.extend ?
问题挖坑……我等下告诉你!
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.