Giter VIP home page Giter VIP logo

learn-js's Introduction

learn-js's People

Contributors

sofish avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

learn-js's Issues

第十六天:写一个 route

觉得 angular 2 的文档太难懂,想自己写,写到 template 渲染基本就挂,工作量太大,得出一个结果就是该作死一定会死,不想做死其实就写写 demo 或者有空就给人打打 patch 好了,自己写真的有点麻烦。不过在开始的时候写了一个简单的路由。实现一个基本功能,基本走向是:

- constructor(): 
  --> this.base = HTML_BASE || '/'
  --> this.routes = [],  this.routes.notfound = <rotue>
  --> this.current = <route> || null 
  --> event: <history> `popstate`, <link> `click || touchstart`
  --> CALL_AFTER_REFRESH: this.go(url)
- go(url): redirect to some path
- when(/url/with/:dynamic/params, createdCallback, destroyedCallback): listen to some path

所以如果功能这样,最终 api 看起来就是:

1. js api

// notfound | 404
router.when(created, destroyed);

// route with dynamic param
router.when('/some/:id/path', created, destroyed);

// navigate to a specific url
// when pathname is /base/some/path and base is /base, url equal to /some/path
route.go(url);

2. template markup

<!-- if not listened, route to `HTML_BASE/404` -->
<a href="/some/internal/path">internal</a>

<!-- open in new window, then follow the rules like above -->
<p><a href="/some/internal/path" target="_blank">target="_blank"</a></p>

<!-- trigger default behavor -->
<p><a href="http://sofi.sh">external</a></p>

实现实现代码如下:

实在是太懒了,也懒得看流行框架代码如何撸,先现撸一个可用版本:

class Router {
  constructor() {
    try {
      this.base = document.querySelector('base').getAttribute('href').replace(/(?:\/+)?$/, '');
    } catch (e) {
      this.base = '';
    }

    this.routes = [];
    this.current = null;

    // back
    window.addEventListener('popstate', function() {
      this.go(this._url());
    }.bind(this));

    // listen to links
    this._navigate();

    // wait for routes
    setTimeout(function() {
      this.go(this._url());
    }.bind(this));
  }

  when(url, created, destroyed) {
    var params = [];

    // by default, route to /404
    if(typeof url === 'function') {
      return this.routes.notfound = {
        url: '/404', created: url,
        destroyed: created,
        params
      };
    }

    url = url.replace(/:([^\/]*)/g, function(match, param) {
      params.push(param);
      return '([^\\/]+)';
    });
    url = new RegExp(`${url}$`);

    if(typeof created === 'function') {
      this.routes.push({url, created, destroyed, params});
    }
  }

  go(url, isExternalLink) {
    if(typeof path === 'number') return history.go(url);    // back or forward
    if(isExternalLink) return location = url;               // external links

    if(url[0] !== '/') url = '/' + url;
    if(url !== this.url) {
      var isFound = this.exec(url);
      // it's safe to set STATE and TITLE to null
      this.url = isFound ? url : '/404';
      history.pushState(null, null,  this.base + this.url);
    }
  }

  _url() {
    return (location.pathname + location.search + location.hash).slice(this.base.length);
  }

  _navigate() {
    let event = typeof window.ontouchstart === 'undefined' ? 'click' : 'touchstart';
    document.addEventListener(event, function(e) {
      var target = e.target;
      if(                                                   // Exclude:
        target.tagName !== 'A' || !target.href ||           //  - non links
        target.getAttribute('target') === '_blank'          //  - link open in new tab or window
      ) return;

      var url = target.href.split(/\/+/);
      var host = url[1];
      url = '/' + url.slice(2).join('/');
      if(host !== window.location.hostname) return;         //  - external link

      e.preventDefault();
      this.go(url);
    }.bind(this), false);
  }

  // exec callback
  exec(url) {
    var count = 0;
    url = this.parse(url);

    if(this.current && this.current.destroyed) this.current.destroyed();

    this.routes.forEach(function(route) {
      if(!url.pathname.match(route.url)) return;
      this.current = route;

      var data = route.url.exec(url.pathname).slice(1);
      var params = {};

      route.params.forEach((key, i) => params[key] = data[i]);
      route.created({params, search: url.search});

      count++;
    }.bind(this));

    // 404
    if(!count && this.routes.notfound && this.url !== '/404') {
      this.current = this.routes.notfound;
      this.routes.notfound.created({params: {}, search: url.search});
    }

    return count;
  }

  // parse url
  parse(url) {
    url = url.split('?');
    var search = {};
    var pathname = url[0];

    url = url[1] ? url[1].split('&') : [];
    url.forEach(function(pair) {
      pair = pair.split('=');

      let key = pair[0];
      let value = pair[1];

      if(!/\[\]$/.test(key)) return search[key] = value;

      search[key] = search[key] || [];
      search[key].push(value);
    });

    return {pathname, search};
  }
}

第四天:`call` vs `apply`

对于函数体内,this 总是指向调用它的上下文,有时候我们希望调用的上下文是某个指定的对象,这里最简单的方法是使用用 callapply。每次面试,问到它俩有什么区别,这个非常简单的一个点,面试的时候屡试不爽,大部分人都不知道。

在此之前,我们先来看一段代码。

class Cat {
  constructor(name) {
    this.name = name;
  }
  meow() {
    console.log(`meow, i'm ${this.name}`);
  }
}

var fakeCat = { name: 'sofish' };

var ciao = new Cat('ciao');
ciao.meow();  // meow, i'm ciao
ciao.meow.call(fakeCat); // meow, i'm sofish
ciao.meow.apply(fakeCat); // meow, i'm sofish

同样是 Cat 的实例 —— ciao 在叫(meow),为什么结果不一样?因为第二和三个调用使用 callciao.meow 的执行上下文改变成 fakeCat,所以 this.name 相当于 fakeCat.name,结果很明显。

上面简单演示了它俩的作用,它俩的使用一样,只是参数不同。

  • call(context, arg1, arg2...) 第一个参数是上下文,之后所有参数为调用函数的参数列表
  • apply(context, [arg1, arg2...]) 第一个参数与 call 一样,之后传入一个数组作为函数的参数列表
  • 记忆方法:applyarray 第一个字母都是 a(如果这样就不会搞混参数了)

来个代码片段看看:

function sum(a, b, c) {
  console.log(a + b + c);
} 

sum.call(null, 1, 2, 3); // 6
sum.apply(null, [1, 2, 3]); // 6

好困,看会电视就睡觉去~

第六天:分组

几乎每次面试都问一个题:一群人出去玩,写一个程序随机分组可以如何分。最后简化成 10 个人出去玩,如何将人随机分配到 4 个组里,并保证每个组的人比较均匀。

var arr = [1,2,3,4,5,6,7,8,9,0];
var group = [[],[],[],[]];

(function split(arr, group) {
  // you code here


  console.log(group);
})(arr, group);

不想直接给答案,有订阅的大家思考一下,有兴趣的可以评论发自己的答案。也是留给老婆的一道题。考点包括随机、数组操作、基本的流程控制。

补:昨天又忘记了 ( 👎 )

第七天:Fisher–Yates Shuffle

最近有时差,昨天的任务今天来写 👎 。

昨天写了前天的任务「如何分组」。大家都会需要用到「洗牌」,而关于如何洗有多种算法,其中有一个简洁高效的算法就是 Fisher-Yates Shuffle https://bost.ocks.org/mike/shuffle/ ( 文章和演示都非常棒 )。

在「如何分组」里我写了一个思路,里面有一种重要的点是不断从原来的数组踢除数值,这会导致数组本身重排,而这是 Fisher-Yates 要避免的问题,他采用的是交换的方法来避免重排,如下中文注释。

function shuffle(array) {
  var m = array.length, t, i;

  // While there remain elements to shuffle…
  while (m) {

    // Pick a remaining element…
    i = Math.floor(Math.random() * m--);

    // And swap it with the current element.
    t = array[m];  // 缓存当前的第 m 位
    array[m] = array[i]; // 随机 m 之前某位放进 m
    array[i] = t; // 第随机位换成 m 位的值(后续还会被取到)
  }

  return array;
}

感慨,算法总是逼死我们这些文科生。

第十五天:正则表达式

在处理字符串的时候,正则就非常有用。今天老婆又开始看文章了,所以我也开始更新了。举个例子,处理模板,在没有多行模板的时候,我通常会选择这样做:

var person = { name: 'sofish', bio: 'a programmer'};
var tmpl = 'This is {name} and he is {bio}.';
var output = tmpl.replace(/\{(\w+)\}/g, function(match, group1) { 
  return person[group1] || '';
});
console.log(output);

关于正式的基础,字面量、ExpReg 对象,exec test search match replace 等方面的使用,可以看这篇文章:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions

第十一天:写一个 jQuery 插件

现在,用 jQuery 的公司还很多,但是拿出来说的已经很少了。还有 15 分钟就要去跑步,加上老婆还在整天跟 jQuery 打交道,写两句说明一下。拿官方的例子说明一下:

// 避免冲突,创建一个函数自执行函数,并把 `jQuery` 传入
(function( $ ) {

    // 用 `$.fn.插件名` 来定义一个新的插件
    // 关于插件为什么不用 `new`,`$.fn` 是什么意思,可以看:
    // http://stackoverflow.com/questions/4083351/what-does-jquery-fn-mean
  $.fn.showLinkLocation = function() {

    // `this` 即 `$()` 选中的集合
    // `filter` 筛选这个选中集合中的 `<a>`
    // 通常插件都会用 `each` 来循环整个集合,因为每个 `$()` 都会返回一个 jQuery 集合
    this.filter( 'a' ).each(function() {
      var link = $( this );
      link.append( ' (' + link.attr( 'href' ) + ')' );
    });

    // jQuery 其中一个最大的特点是链式调用,而 `return this` 返回一个 jQuery 对象让链式调用成为现实
    return this;

  };
}( jQuery ));

// 执行插件
$( 'a' ).showLinkLocation();

第十四天:2 进制与 10 进制转换

呃,这其实是一个很大的话题,虽然说起来只有几句话。拿简单的十进制数字 3,如果转换成二进制:

3..toString(2) // '11'

呃,浏览器里如何显示二进制呢?我们这里忽略,跳出来说一下为什么是 3..toString() 而不是 3.toString(),是不是也曾误了 Number 并没有 toString 方法?用 .. 只是一个 hack 避开了小数点。另外可以写成 (3).toString() 这样就明白多了。转回来。关于如何把二进制转成 10 进制,就更简单了:

parseInt('11', 2) // 3

同样的,可以用带上像 2 8 10 16 这几个参数,来进行 2、8、10、16 进制的转换。不过负数呢?考虑一下这个执行返回什么:

(-3).toString(2) // '-11'

看!起!来!好!像!是!对!的!不过负数通常是以补码来表示的,而什么叫补码?( # )补码形式是指一个数的负对应值( negative counterpart )( 如 5 和 -5 )为数值的所有比特位反转后,再加 1。那么,-3 的值应该是:

(-3 >>> 0).toString(2) // 11111111111111111111111111111101

而关于为什么要用无符号右移 >>> 呢?其实右移了 0 位,( # ) (right logical shift) coerces its arguments to unsigned integers`,然后再转成 2 进制。

再次逼死文科生。我睡觉去了。

第十天:递归

通常来说,提起递归,就会想到阶乘;想起阶乘就会想到自己既不喜欢数学也不喜欢历史;所以也就是说无论从客观层面(数学)上来说,还是从非客观(历史,通常更像故事而不是真实)都不喜欢,那就是任性;任性的结果是这些科目成绩不好,成绩不好就只能考法学院;考法学院还不好好学习,就只能写代码,写代码又要搞递归;递归又要回到阶乘。所以,还是贴个图片并从维基百科拿来一句定义吧:一个正整数的阶乘/层(英语:factorial)是所有小于及等于该数的正整数的积,并且有0的阶乘为1。

又要来逼死文科生了:递归,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。那我们用递归实现一个阶乘吧:

function factorial(n) {
  return n ? (n * factorial(n - 1)) : 1;
}

好了,完美,不过《 JS 高级程序设计》里提及过一个问题,函数作为一个引用类型,在递归里,如果我们使用函数名来调用自身,可能会存在一个指向的问题(引用类型在有引用时,指向的对象是不会被回收(GC)的,对吧?!),看下面的代码:

var f = factorial;
factorial = null;
f(4); // TypeError: factorial is not a function

我们可以简单地使用一个 hack 来解决 —— 使用 arguments.callee,它永远指向函数本身:

function factorial(n) {
  return n ? (n * arguments.callee(n - 1)) : 1;
}

var f = factorial;
factorial = null;
f(4);

然后... 又要一脸懵逼了,因为有了 strict 模式,如下:

'use strict'

~function func() {
  arguments.callee;
  // TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
}();

所以有什么办法比较好呢?

让我们回到递归本身来。在面试的时候,我们经常问起一个问题 —— 如何拍平一个数组。如:

var arr = [1, [2, [3, [4], 5], 6], 7];
(function flatten(arr) {
  var newArray = [];
  // your code here

  return newArray;
})(arr);

那么,如果使用递归的话,可以如何实现呢?

第五天:ES2015 Generator

4 篇关于 Generator 的文章,从入门到放弃(CSP),里面有几个重要的点:

1. 使用 yieldreturn 导致 for...of 结果的不同

  function *foo() {
      yield 1;
      return 2;
  }

  var it = foo();

  console.log( it.next() ); // { value:1, done:false }
  console.log( it.next() ); // { value:2, done:true }

  for(let value of foo()) { 
    console.log(value)
  }

2. next() 可以传值

function *foo() {
    var x = 1 + (yield "foo");
    return x;
}

var it = foo();

console.log(it.next()); // 'foo'
console.log(it.next(1)); // 2

3. 在 Generator 嵌套 Generator 的顺序是怎样的?

当前迭代器会代理嵌套 Generator 的迭代器,流程如下:*bar() 的迭代器走到 yield *foo() 的点,进入 *foo() 完成迭代,再跳出来往下执行。

function *foo() {
    var z = yield 3;
    var w = yield 4;
    console.log( "z: " + z + ", w: " + w );
}

function *bar() {
    var x = yield 1;
    var y = yield 2;
    yield *foo(); // `yield*` delegates iteration control to `foo()`
    var v = yield 5;
    console.log( "x: " + x + ", y: " + y + ", v: " + v );
}

var it = bar();

it.next();      // { value:1, done:false }
it.next( "X" ); // { value:2, done:false }
it.next( "Y" ); // { value:3, done:false }
it.next( "Z" ); // { value:4, done:false }
it.next( "W" ); // { value:5, done:false }
// z: Z, w: W

it.next( "V" ); // { value:undefined, done:true }
// x: X, y: Y, v: V

4. 知名 Node.js 库 tj/co 的实现原理

基本上就是自执行 Generator 和 Promise 结合的结果。

// run (async) a generator to completion
// Note: simplified approach: no error handling here
function runGenerator(g) {
    var it = g(), ret;

    // asynchronously iterate over generator
    (function iterate(val){
        ret = it.next( val );

        if (!ret.done) {
            // poor man's "is it a promise?" test
            if (typeof ret.value.then === 'function') {
                // wait on the promise
                ret.value.then( iterate );
            }
            // immediate value: just send right back in
            else {
                // avoid synchronous recursion
                setTimeout( function(){
                    iterate( ret.value );
                }, 0 );
            }
        }
    })();
}

function *foo() {
    var z = yield 3;
    console.log(z);
    var w = yield 4;
    console.log(w);
}

function *bar() {
    var x = yield 1;
    console.log(x);
    var y = yield 2;
    console.log(y);
    yield *foo();
    var v = yield 5;
    console.log(v);
}

runGenerator(bar);

结:昨晚忘记更新了,这四篇写的非常好,我猜老婆也看不懂。在 async / await 出来之前,乖乖用 tj/co 就可以了。

第八天:微信 js sdk 签名

今天终于正常了,当日事当日毕。

以前写宣传页面的时候,微信作为一个最大的流量平台,分享的「卡片」当然要做的好看一点,所以写了 sofish/wechat.js 来省时间。后来微信就变得很屎,分享竟然需要签名,而且对每个页面都要。

最近老婆的项目遇到一个情况需要自定义分享到朋友图/朋友的卡片 URL 和图片,所以找了一个实现 https://github.com/leecade/weixin-node ,简单好用(记得建一个 /tmp/ 文件夹,别问我为什么)。

因为微信规定 ticket 时间是 7200,并且有次数限制,所以需要自己缓存 ticket,而这个库用了一个简单粗暴且有效的方法 —— 存文件。每次需要之后去读文件,判断是否过期,如果过期重新请求,没过期就用缓存。https://github.com/leecade/weixin-node/blob/master/index.js#L79

签名和用法参考:微信JS-SDK说明文档

第十二天:不用 new

一、避免无须有的实例化

一直很喜欢 Bootstrap 里用不 new 执行 js 的方式,写一个例子,阻止页面上任何 a[preventdefault] 标签的默认行为,并弹出它的链接:

(function($) {
  $(document).on('click', 'a[preventdefault]', function(e) {
    e.preventDefault();
    alert(this.href)
  });
})(jQuery);

这种方式不需要像 new PreventDefault('a[preventdefault]'),在 html 中直接声明,比如 Tab 插件,只需要写 data-toggle="Tab" data-target="#someId" 即可(新版好像已经不需要这样),而不像大家习惯的 new Tab('#id'),在不需要任何 options 的情况也能省就省,直接把 html 的标记当声明。当然,见仁见智,这种方式只是我自己比较喜欢。

二、类似于 jQuery 的 $.fn.pluginName 自助实例化

#13 中的注释也写了,$.fn === $.prototype ,为什么 $(selector).pluginName() 就可以直接用呢?有没有办法去掉 new 关键词呢?

function C(name) {
  // node 里可以用 !new.target 来检测
  if(!(this instanceof C)) return new C(name);
  this.name = name || 'noname';
}

C.prototype.test = function() {
  return 'i\'m ' + this.name;
}

var c = C();

console.log(c.name, c.test());

再一次,这也是见仁见智的事,我就不是很喜欢不 new 的情况,但实现 jQuery 的 $.fn 却又很喜欢。

第九天:无依赖小库

对于球迷来说 NBA 是一种精神,对于 Benz 粉丝来说 AMG 是一种精神,对于黑客来说无依赖也是一种精神。前段时间因为 leftPad 在 npm unpublish 之后引发了一堆对 leftPad 的讨论,就如坐我旁边的同事,就叫我当场写个 leftPad,然后在内部分享会嘲笑我写的太差。

刚半夜看 GitHub Trending 发现了一个无依赖的对字符串操作的小库 dleitee/strman。喜欢看薄的书,看简单的代码。所以看了一波:

export const _isArray = value => {
    return (value !== null &&
           value.length >= 0 &&
           Object.prototype.toString.call(value) === '[object Array]');
};

export const _pop = array => {
    let newarray = [];
    for(let i = 0; i < array.length-1; i++){
        newarray[i] = array[i];
    }
    return newarray;
};

如果是我写的话,可能会是这样的:

export const _isArray = value =>  Object.prototype.toString.call(value) === '[object Array]';
export const _pop = array => array.slice();

所以我觉得这个库还是把东西写复杂了,随后发了一条微博轻吐槽(其实是反问),经提示,发现了一个坑(像 sort 要返回 true/false 一样的坑,以前注意过后来全忘记了):

let str = new String();
typeof str; // object
'' instanceof String; // false

真是一脸懵逼 😿 ,当然,像上面的 _isArray 还可以这样写:

export const _isArray = value =>  Array.isArray(value);

但这样写有一个不好的点 —— 不兼容老浏览器。似乎 Symbal 没这个问题?(这个留给大家)。所以总的来说 Object.prototype.toString.call 还是比较安全的办法。

var frame = document.createElement('iframe');
frame.src = window.location.href;
document.body.appendChild(frame);

var arr = new frame.contentWindow.Array();

console.log(arr instanceof Array); // false
console.log(Array.isArray(arr)); // true

这里我记错了,写一个例子来看看,多谢微博提醒的同学

要总结的话只有一句:我不喜欢看源代码,不过无依赖的看看也挺舒服;要啰嗦的是,突然想起百度 5、6 年前开源过一个叫 Tangram 的库,我就几乎全读了,后来发现当时了解的 js 技巧似乎比现在还多;要自黑的是,当隔三个月看自己的代码觉得是垃圾的时候说明一切都还好,当隔了一年了看自己的代码觉得当时自己很牛逼的话,那说明水平已经比较水 —— 说的就是我。

第十三天:数据结构的锅

突然想起 LeetCode,这是一个我不喜欢的地方,不过既然想去就去刷一刷。刷了几题觉得有时候就是很偏见的的玩意,比如奖字符串中的元音反转,也就是 hello 会变成 holle,也就玩玩。

准备结束刷新到 https://leetcode.com/problems/flatten-nested-list-iterator/ ,然后默默在编辑器写后运行,跑过自己本地的 Testcase,但是贴上去竟然出错。代码如下:

var NestedIterator = function(nestedList) {
  this.nestedList = nestedList;
};

NestedIterator.prototype.flatten = function(arr, ret) {
  if(!ret) ret = [];
  for(var i = 0, j = arr.length; i < j; i++) {
    Array.isArray(arr[i]) ? this.flatten(arr[i], ret) : ret.push(arr[i]);
  }
  return ret;
};

NestedIterator.prototype.hasNext = function() {
  var tmp = this.nestedList[0];
  while(tmp && tmp.toString() === '') {
    this.nestedList.shift();
    tmp = this.nestedList[0];
  }
  return this.nestedList.length;
};

NestedIterator.prototype.next = function() {
  var ret = this.nestedList.shift();
    if(Array.isArray(ret)) {
    [].unshift.apply(this.nestedList, this.flatten(ret));
    ret = this.nestedList.shift();
  }
  return ret;
};

var i = new NestedIterator([[1,1],2,[1,1]])
var a = [];

while (i.hasNext()) a.push(i.next());
console.log(a);

运行起来是没问题的,但是要求并!不!是!一!个!纯!数!组!所以呵呵哒,总的来说,就是一个奇怪的古老程序员喜欢的复杂的数据结构,所以实现起来也真是:垃圾结果导致垃圾代码。

重要的话已经吐了,再见~

Recommend Projects

  • React photo React

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

  • Vue.js photo Vue.js

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

  • Typescript photo Typescript

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

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

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

Recommend Topics

  • javascript

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

  • web

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

  • server

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

  • Machine learning

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

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

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

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.