- 👋 Hi, I’m @zi.li
- 👀 I’m interested in Front-end development
- 目前正在找工作,有看上我的,上海、杭州、合肥地区请联系我。
- 邮箱:[email protected]
blog's Introduction
blog's People
blog's Issues
js继承
js继承
-
原型继承
function Parent (name) { this.name = name; } Parent.prototype.getName = function () { return this.name; } function Child (name, age) { this.name = name; this.age = age; } Child.prototype = new Parent();
缺点:
- 实例无法向父类构造函数传参
- 所有实例都会共享父类实例的属性
-
构造函数式继承
function Parent (name) { this.name = name; } Parent.prototype.getName = function () { return this.name; } function Child (name, age) { Parent.call(this, name); this.age = age; }
缺点:
- 没有继承父类原型上的方法
-
组合继承
function Parent (name) { this.name = name; } Parent.prototype.getName = function () { return this.name; } function Child (name, age) { Parent.call(this, name); } Child.prototype = new Parent(); Child.prototype.constructor = Child;
缺点:
- 父类的构造函数被调用两次
-
寄生组合继承
function _inherits (subClass, superClass) { subClass.prototype = Object.create(superClass && superClass.prototype); subClass.prototype.constructor = subClass; } function Parent (name) { this.name = name; } Parent.prototype.getName = function () { return this.name; } function Child (name, age) { Parent.call(this, name); this.age = age; } _inherits(Child, Parent); Child.prototype.getAge = function () { return this.age; }
-
class继承
class Parent { constructor(name) { this.name = name; } getName() { return this.name; } } class Child extends Parent { constructor(name, age) { super(name); // Parent.call(this) this.age = age; } }
// class继承用babel转为es5 "use strict"; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } } function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var Parent = /*#__PURE__*/function () { function Parent(name) { _classCallCheck(this, Parent); this.name = name; } _createClass(Parent, [{ key: "getName", value: function getName() { return this.name; } }]); return Parent; }(); var Child = /*#__PURE__*/function (_Parent) { _inherits(Child, _Parent); var _super = _createSuper(Child); function Child(name, age) { var _this; _classCallCheck(this, Child); _this = _super.call(this, name); // Parent.call(this) _this.age = age; return _this; } return Child; }(Parent);
所以,ES5的继承实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.call(this));ES6的继承机制完全不同,实质是先将父类实例对象的属性和方法加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this
Node节点
Node.nodeType
nodeType属性用来区分不同类型的节点。
语法:var type = node.nodeType
例:var bodyType = document.body.nodeType
节点类型常量
- Node.ELEMENT_NODE 值:1 元素节点,例如div、p
- Node.TEXT_NODE 值:3 Element或Attr中实际的文字
- Node.CDATA_SECTION_NODE 值:4 CDAASection,例如<!CDATA[[...]]>
- Node.PROCESSING_INSTRUCTION_NODE 值: **7 ** 用于XML文档的processingIntruction,例如声明
- Node.COMMENT_NODE 值:8 Comment节点
- Node.DOCUMENT_NODE 值: 9 Document节点
- Node.DOCUMENT_TYPE_NODE 值: 10 描述文档类型的DocumentType节点,例如
- Node.DOCUMENT_FRGMENT_NODE 值: 11 DocumentFragment节点
Node.nodeValue
返回或设置当前节点的值
Node.parentNode
返回当前节点的父节点,若没有,则返回null
Node.parentElement
返回当前节点的父节点Element,若没有,则返回null
Node.previousSibling(只读)
返回当前节点同辈的前一个节点,若没有,则返回null
Node.textContent
返回或设置一个元素内所有子节点及其后代的文本
Node.childNodes(只读)
返回一个包含了该节点所有子节点的实时的NodeList
Node.firstChild(只读)
返回该节点的第一个子节点,若没有,则返回null
Node.lastChild(只读)
返回该节点的最后一个子节点,若没有,则返回null
Node.nextSibling(只读)
返回与该节点同级的下一个节点,若没有,则返回null
Node.nodeName(只读)
返回一个包含该节点名字的DOMString
Node.isConnected(只读)
返回一个布尔值用来检测该节点是否已连接(直接或者间接)到一个上下文对象上,比如通常DOM情况下的Document
对象,或者在shadow DOM情况下的ShadowRoot
对象。
Node.baseURI(只读)
返回一个表示base URL的DOMString
下面是一个爬取页面信息的例子:
(function(document_root) {
let __html = '', node = document_root.firstChild;
while(node) {
switch(node.nodeType) {
case Node.ELEMENT_NODE:
__html += node.outerHTML;
break;
case Node.TEXT_NODE:
__html += node.nodeValue;
break;
case Node.CDATA_SETION_NODE:
__html += '<![CDATA[' + node.nodeValue + ']]>';
break;
case Node.COMMENT_NODE:
__html += '<!--' + node.nodeValue + '-->';
break;
case Node.DOCUMENT_TYPE_NODE:
__html += "<!DOCTYPE " + node.name + (node.publicId ? ' PUBLIC "' + node.publicId + '"' : '') + (!node.publicId && node.systemId ? ' SYSTEM' : '') + (node.systemId ? ' "' + node.systemId + '"' : '') + '>\n';
break;
}
node = node.nextSibling;
}
return __html;
})(document)
参考文章:MDN
React组件复用
React组件复用在版本16.8以前一般是通过高阶组件和render props实现,16.8以后则可以通过hooks实现。下面我们以一个计时器为例看看这三种方式是如何实现的。
高阶组件
const WrapTimer = (WrapComponent: React.ComponentType<any>) => {
return class extends React.Component<WrapTimerPropsType, TimeType> {
timer: NodeJS.Timer | null = null;
constructor(props: any) {
super(props);
this.state = {
hour: '00',
minute: '00',
second: '00',
}
this.timer = null
}
componentDidMount() {
this.timer && clearInterval(this.timer);
if (this.props.time) {
this.setState({
...this.props.time
}, () => {
this.countDown();
})
} else {
this.countDown();
}
}
countDown = () => {
this.timer = setInterval(() => {
this.setState((state: TimeType) => {
let { hour, minute, second } = state;
if (second >= '59') {
second = '00';
const newMinute = Number(minute) + 1;
minute = newMinute > 9 ? newMinute.toString() : addZero(newMinute);
} else if (minute >= '59') {
minute = '00';
const newHour = Number(hour) + 1;
hour = newHour > 9 ? newHour.toString() : addZero(newHour);
} else {
const newSecond = Number(second) + 1;
second = newSecond > 9 ? newSecond.toString() : addZero(newSecond);
}
return {
hour,
minute,
second,
}
})
}, 1000)
};
componentWillUnmount() {
this.timer && clearInterval(this.timer);
}
render() {
return (
<WrapComponent {...this.state} />
)
}
}
}
render props
export default class RenderTimer extends React.Component<{ render: (state: TimeType) => React.ReactNode; time?: TimeType; }, TimeType> {
timer: NodeJS.Timer | null = null;
constructor(props: any) {
super(props);
this.state = {
hour: '00',
minute: '00',
second: '00',
}
this.timer = null
}
componentDidMount() {
this.timer && clearInterval(this.timer);
if (this.props.time) {
this.setState({
...this.props.time
}, () => {
this.countDown();
})
} else {
this.countDown();
}
}
countDown = () => {
this.timer = setInterval(() => {
this.setState((state: TimeType) => {
let { hour, minute, second } = state;
if (second >= '59') {
second = '00';
const newMinute = Number(minute) + 1;
minute = newMinute > 9 ? newMinute.toString() : addZero(newMinute);
} else if (minute >= '59') {
minute = '00';
const newHour = Number(hour) + 1;
hour = newHour > 9 ? newHour.toString() : addZero(newHour);
} else {
const newSecond = Number(second) + 1;
second = newSecond > 9 ? newSecond.toString() : addZero(newSecond);
}
return {
hour,
minute,
second,
}
})
}, 1000)
};
componentWillUnmount() {
this.timer && clearInterval(this.timer);
}
render() {
return (
<div>{this.props.render(this.state)}</div>
)
}
}
hooks
export default function useTimer(props: { time?: TimeType }) {
const time = props.time || {
hour: '00',
minute: '00',
second: '00',
};
const [date, setDate] = useState(time)
useEffect(() => {
timer && clearInterval(timer);
countDown();
return () => {
timer && clearInterval(timer);
}
}, [props.time]);
// 倒计时
const countDown = () => {
timer = setInterval(() => {
setDate((date: TimeType) => {
let { hour, minute, second } = date;
if (second >= '59') {
second = '00';
const newMinute = Number(minute) + 1;
minute = newMinute > 9 ? newMinute.toString() : addZero(newMinute);
} else if (minute >= '59') {
minute = '00';
const newHour = Number(hour) + 1;
hour = newHour > 9 ? newHour.toString() : addZero(newHour);
} else {
const newSecond = Number(second) + 1;
second = newSecond > 9 ? newSecond.toString() : addZero(newSecond);
}
return {
hour,
minute,
second,
}
})
}, 1000)
};
return date;
}
通过上面三种方式,我们可以单独把计时器的逻辑部分抽离出来,实现组件的复用。在React16.8版本以前,通过高阶组件和render props可以实现,但是这类方案需要重新组织你的组件结构,这可能会很麻烦,使你的代码难以理解,而使用 Hook 从组件中提取状态逻辑,使得这些逻辑可以单独测试并复用,Hook 使你在无需修改组件结构的情况下复用状态逻辑。 这使得在组件间或社区内共享 Hook 变得更便捷。
npm包发布流程
npm发包流程
-
注册npm账号(https://www.npmjs.com/)
-
登录账号
-
第一次发包
npm添加用户账号
命令:npm adduser
-
已添加用户账号
命令:npm login
查看当前用户:npm whoami
-
-
发布
命令:npm publish
-
更新发布
npm version <update_type>
npm publish
问题:
-
code 403
检查下当前的登录源是否是https://registry.npmjs.org/,命令:**npm config get registry**
若不是则设为npmjs源,命令:npm config set registry=npm config get registry
-
code 401
未登录
-
如果发的包是某个packages下的包,发布是不成功的
命令:npm publish --access public
Linux命令
Linux命令
yum install nginx 安装插件
netstat -lntup 查看运行的端口
locate nginx.conf 查找nginx.conf文件
systemctl restart nginx 重启nginx
nginx -c /path/to/nginx.conf 以特定目录下的配置文件启动nginx
nginx -s stop 快速停止nginx
nginx -s quit 完整有序的停止nginx
nginx -s reload 修改配置后重新加载生效
nginx -s reopen 重新打开日志文件
rm -rf 删除文件夹
rm -f 删除文件
cp index.js demo.js 复制一个文件
cp -a dir1 dir2 复制一个目录
cp -r dir1 dir2 复制一个目录及子目录
find / -name file 从'/'开始进入根文件系统搜索文件和目录
find / -user user 搜索属于用户‘user’的文件和目录
find /home/user -name *.bin 在目录'/home/user'中搜索带有'.bin'结尾的文件
gzip file 压缩文件
编辑文件
vi nginx.conf 查看nginx.conf文件
接着恩i键
接着编辑文件
编辑完成后 esc->: ->wq! enter
pwd 查看当前所在路径
BFC
一、简介
BFC(Block Formatting Context)块级格式化上下文。它是一个独立的渲染区域,只有Block-level box参与,它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。通俗地讲,BFC是一个容器,用于管理块级元素。
二、触发方式
- 根元素
- 浮动元素:float为left、right
- overflow:auto、scroll、hidden
- display:inline-block、table-cell、table-cation、table、inline-table、flex、inline-flex、grid、inline-grid
- position:absolute、fixed
三、布局规则
- 内部的Box会在垂直方向一个接一个地放置(即块级元素独占一行)
- BFC的区域不会与float box重叠(实现自适应两栏布局)
- 内部的Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠(margin重叠三个条件:同属一个BFC、相邻、块级元素)
- 计算BFC的高度时,浮动元素也参与计算(清除浮动haslayout)
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之亦如此
四、特性
-
BFC会阻止垂直外边距重叠
按照BFC的定义,只有同属于一个BFC时,两个元素才有可能发生垂直margin的重叠,这个包括相邻元素或者嵌套元素,只要他们之间没有阻挡(比如边框、非空内容、padding等)就会发生margin重叠。
-
相邻兄弟元素margin重叠问题
<style> .child { color: #fff; background-color: #888; width: 200px; line-height: 100px; text-align: center; margin: 100px; } </style> <body> <div class='child'>Child1</div> <div class='child'>Child2</div> </body>
上面两个div上下之间的距离本该为200px,然而实际上只有100px,发生了重叠。解决办法是在div外面包裹一层容器,并触发该容器生成一个BFC,那么两个div便不属于同一个BFC,就不会发生margin重叠了。
<style> .parent { overflow: hidden; } .child { color: #fff; background-color: #888; width: 200px; line-height: 100px; text-align: center; margin: 100px; } </style> <body> <div class='child'>Child1</div> <div class='parent'> <div class='child'>Child2</div> </div> </body>
-
父子元素margin重叠问题
<style> .child1 { width: 100px; height: 100px; } .parent { background-color: turquoise; } .child2 { background-color: yellowgreen; margin: 40px; } </style> <body> <div class='child1'>Child1</div> <div class='parent'> <div class='child2'>Child2</div> </div> </body>
上图parent元素与child2元素之间理论上本该有个40px的上下margin值,然而实际上父子元素并没有存在margin值,与此同时,parent与child1之间的间距为40px。解决方法:给parent元素添加overflow: hidden;或者overflow:auto;使其形成一个BFC,也可以在parent元素中添加border: 1px solid ; 或是padding: 1px;
-
-
BFC不会重叠浮动元素
<style> .box1 { width: 100px; height: 100px; float: left; background-color: lightblue; } .box2 { width: 200px; height: 200px; background-color: #eee; } </style> <body> <div class='box1'> 我是一个左浮动的元素 </div> <div class='box2'> 喂喂喂!大家不要生气嘛,生气会犯嗔戒的。悟空你也太调皮了, 我跟你说过叫你不要乱扔东西,你怎么又……你看,我还没说完你就把棍子给扔掉了! 月光宝盒是宝物,你把它扔掉会污染环境,要是砸到小朋友怎么办,就算砸不到小朋友, 砸到花花草草也是不对的。 </div> </body>
上图中,文字围绕着浮动元素排列,不过在这里,这显然不是我们想要的。解决办法:给box2元素添加overflow: auto; 使其形成一个BFC。
-
BFC可以包含浮动(清除浮动)
<style> .parent { background-color: turquoise; } .child { width: 100px; height: 100px; float: left; border: 1px solid #000; } </style> <body> <div class='parent'> <div class='child'></div> <div class='child'></div> </div> </body>
由于父div内的两个div元素浮动,脱离了文档流,父div内容宽度为0(高度塌陷),未能将子元素包裹住。解决办法:把父div变成一个BFC。
深入探讨React Hooks是如何实现的?
Hooks是在用户界面中封装有状态行为和副作用的最简单的方法。它的设计需要对JavaScript中的闭包有一定得了解。
什么是闭包?
You Don’t Know JavaScript一书中是这样定义的:
“闭包是指一个函数能够记住并访问其词法作用域,即使该函数在其词法作用域之外执行”
function useState(initialValue) {
var _val = initialValue;
function state() {
return _val;
}
function setState(newVal) {
_val = newVal;
}
return [state, setState];
}
var [count, setCount] = useState(0);
console.log(count());
setCount(1);
console.log(count());
在这里,我们模仿React useState创建了一个函数。在我们的useState函数中,有2个内部函数,state和setState。state返回_val上面定义的局部变量,并将setState局部变量设置为传递给它的参数(即newVal)。
在函数组件中使用
function Counter() {
const [count, setCount] = useState(0);
return {
click: () => setCount(count() + 1),
render: () => console.log('render: ', { count: count() })
}
}
const c = Counter();
c.render();
c.click();
c.render();
这里我们没有DOM渲染,用console.log打印出来。上面函数是模拟函数组件的渲染和用户的操作。
上面的函数中我们返回的state都是函数,如果我们想和React useState一样,返回的是一个变量,则有一个错误:
function useState(initialValue) {
var _val = initialValue;
function setState(newVal) {
_val = newVal;
}
return [_val, setState]
}
var [count, setCount] = useState(0);
console.log(count); // 0
setCount(1);
console.log(count); // 0
这里我们可以看到,当我们从useState拿到count后,count始终是初始化时的值。
变量state
const MyReact = (function() {
let _val;
return {
render(Component) {
const Comp = Component()
Comp.render()
return Comp
},
useState(initialValue) {
_val = _val || initialValue
function setState(newVal) {
_val = newVal
}
return [_val, setState]
}
}
})();
function Counter() {
const [count, setCount] = MyReact.useState(0)
return {
click: () => setCount(count + 1),
render: () => console.log('render:', { count })
}
}
let App;
App = MyReact.render(Counter); // render: { count: 0 }
App.click();
App = MyReact.render(Counter); // render: { count: 1 }
JavaScript获取音视频
JavaScript获取音视频
MediaDevidces.getUserMedia()
MediaDevices.getUserMedia()方法提示用户允许使用一个视频和/或一个音频输入设备,例如相机或屏幕共享和/或麦克风。它返回一个Promise对象,成功后会resolve回调一个MediaStream对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promise
会reject
回调一个 PermissionDeniedError
或者 NotFoundError
。
function getNavigatorUserMedia() {
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
if (navigator.mediaDevices.getUserMedia === undefined) { // 兼容低版本浏览器
navigator.mediaDevices.getUserMedia = function (constraints) {
const getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
return new Promise((resolve, reject) => {
getUserMedia.call(navigator, constraints, resolve, reject);
});
}
}
return navigator;
}
getNavigatorUserMedia().mediaDevices.getUserMedia({ video: { width, height }, audio: true })
.then((stream) => {
setStatus('success');
const video = document.querySelector('video');
if ('srcObject' in video) {
video.srcObject = stream;
} else {
video.src = window.URL.createObjectURL(stream);
}
video.onloadedmetadata = function () {
video.play();
};
})
.catch((error) => {
console.log(error);
});
在TypeScript兼容低版本浏览器写法
function getNavigatorUserMedia() {
let navigatorCopy = navigator as any;
if (navigatorCopy.mediaDevices === undefined) {
navigatorCopy.mediaDevices = {};
}
if (navigatorCopy.mediaDevices.getUserMedia === undefined) { // 兼容低版本浏览器
navigatorCopy.mediaDevices.getUserMedia = function (constraints: MediaStreamConstraints | undefined) {
const getUserMedia = navigatorCopy.webkitGetUserMedia || navigatorCopy.mozGetUserMedia;
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
return new Promise((resolve, reject) => {
getUserMedia.call(navigatorCopy, constraints, resolve, reject);
});
}
}
}
getNavigatorUserMedia().mediaDevices.getUserMedia({ video: { width, height }, audio: true })
.then((stream: MediaStream) => {
setStatus('success');
const video = document.querySelector('video') as HTMLMediaElement & { src: string };
if ('srcObject' in video) {
video.srcObject = stream;
} else {
video.src = window.URL.createObjectURL(stream);
}
video.onloadedmetadata = function () {
video.play();
};
})
.catch((error: any) => {
console.log(error);
});
性能优化
性能优化
浏览器渲染
构建DOM树、CSSOM树、渲染树
DOM、style加载解析是一起的不会阻塞,script会阻塞DOM渲染
选择器是从右到左的
浏览器遇到link、@import会开启一个新的线程,发送http请求,link是异步的,不会阻塞DOM渲染,@import是同步的,会阻塞DOM渲染,在真实的项目中应该减少@import的使用
优化方案:
- 标签语义化和避免深层次嵌套
- css选择器渲染是从右到左的,避免嵌套太深
- 尽早尽快地把css下载到客户端(充分利用http多请求并发机制)
- style
- link
- @import
- 放到顶部
- 避免阻塞的js加载(放到底部)
- 减少DOM的回流和重绘
网络交互层面上的优化
-
DNS解析优化
每一次的DNS解析时间预计在20~120秒
-
减少DNS请求次数
-
DNS预获取(DNS Prefetch)
<link rel='dns-prefetch' href='' />
-
-
减少http请求次数和请求资源大小
- 资源合并压缩
- 字体图标
- Base64
- gzip
- 图片懒加载
- 数据延迟分批加载
- cdn资源
应用缓存
缓存位置
- Service Worker: 浏览器独立线程进行缓存
- Memeory Cache: 内存缓存
- Disk Cache:硬盘缓存
- Push Cache: 推送缓存(http2中的)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.