6- js 函数的四种调用方式
2016年11月04日 13:41:54
阅读数:7559

  1. 函数的四种调用方式

函数有下列调用模式

函数调用模式
方法调用模式
构造器模式
上下文模式
  1. 函数调用 模式

要调用,就肯定要先定义,函数的定义方式:

声明式: function fuc() {}
表达式式: var func = function() {};
Function: new Function( ‘参数’,…,’函数体’ );

单独独立调用的,就是函数调用模式,即 函数名( 参数 ),不能加任何其他的东西, 对象 o.fuc() 就不是了。

在函数调用模式中, this 表示全局对象 window

任何自调用函数都是函数模式。

  1. 方法调用 模式 method

所谓方法调用,就是用对象的方法调用。方法是什么,方法本身就是函数,但是,方法不是单独独立的,而是要通过一个对象引导来调用。

就是说方法对象一定要有宿主对象。

即 对象.方法(参数)

this表示引导方法的对象,就是指宿主对象

对比-函数调用模式:

方法调用模式是不是独立的,需要宿主,而函数调用模式是独立的
方法调用模式方式:obj.fuc(); 函数调用模式方式: fuc();
方法调用模式中,this指宿主。而函数调用模式中 this 指 全局对象window

美团的一道面试题

var length = 10;
function fn() {console.log( this.length ); // 10
}
var obj = {length: 5,method: function ( fn ) {fn();   // 10 前面没有引导对象,是函数调用模式arguments[ 0 ](); // 2// arguments是一个伪数组对象, 这里调用相当于通过数组的索引来调用.// 这里 this 就是 指的这个伪数组, 所以 this.length 为 2}
};
obj.method( fn, 1 );    // 打印 10 和 2
//obj.method( fn, 1, 2, 3 );    // 打印 10 和 41
2
3
4
5
6
7
8
9
10
11
12
13
14
15

解析:

fn() 前面没有引导对象,是函数调用模式, this是全局对象,输出 10arguments[ 0 ](),arguments是一个伪数组对象, 这里调用相当于通过数组的索引来调用.这里引导对象即宿主就是 arguments对象。所以,执行时,this 就是指 arguments,由于传了两个参数,所以 输出为 arguments.length 就是 2
  1. 构造器模式(构造函数模式, 构造方法模式)

constructor

特点: 使用 new 关键字引导执行步骤:var p = new Person();new 是一个运算符, 专门用来申请创建对象, 创建出来的对象传递给构造函数的 this。然后利用构造函数对其初始化。function Person () {// new了 进入构造函数时, p 对象的原型 就指向了 构造函数 Person, // p.__proto__.constructor = function Person() {};// 而 this 指的的是 p 对象this.name = 'jim',this.age = 19;this.gender = 'male';}var p = new Person();123456789执行完 new 进入构造函数时, p 对象的原型 就指向了 构造函数 Person而 构造时,this 指的的是 p 对象,是通过对象动态添加属性来构造的小贴士:如果调用构造函数的时候, 构造函数没有参数, 圆括号是可以省略的。function Person() {this.name = 'jim';}var p = new Person; // 不传参,可以简写,不影响构造console.log( p );   // p 含有 name属性12345↑ 不传参,可以简写,不影响构造返回值不写 return 语句, 那么 构造函数 默认返回 this在构造函数 return 基本类型( return num, return 1223 ). 则忽略返回类型.在构造函数 return 引用类型, 那么构造函数返回该引用类型数据, 而忽略 thisfunction Person () {this.name = 'Jepson';return 123;}var p1 = new Person();console.log( p1 );123456↑ 忽略了 123,返回 this 对象, 指向构建的实例function Person () {this.name = 'Jepson';return { 'peter': 'nihao' };}var p1 = new Person();console.log( p1 );123456↑ 忽略了 this,返回 { ‘peter’: ‘nihao’ } 对象

构造函数结合性

如果构造函数没有参数, 可以省略 圆括号var p = new Person;如果希望创建对象并直接调用其方法( new Person () ).sayHello()-> 可以省略调整结核性的圆括号 new Person().sayHello()-> 如果想要省略构造函数的圆括号, 就必须添加结核性的圆括号 (new Person).sayHello()

面试题

一道面试题,大家可以自己尝试先做一下,再看下面的答案和解析

请问顺序执行下面代码,会怎样 alert

function Foo(){getName = function(){ alert(1); };return this;
}
Foo.getName = function(){ alert(2); };
Foo.prototype.getName = function(){ alert(3); };
var getName = function(){ alert(4); };
function getName(){ alert(5); }Foo.getName();  // alert ??
getName();  // alert ??
Foo().getName(); // alert ??
getName(); // alert ??
new Foo.getName(); // alert ??
new Foo().getName(); // alert ??
new new Foo().getName(); // alert ??1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

预解析,简化后的代码,以及答案

/* function getName(){ alert(5); } 执行到下面被覆盖了,直接删除 */
function Foo() {getName = function () { alert(1); };return this;
}
Foo.getName = function () { alert(2); };
Foo.prototype.getName = function () { alert(3); };
var getName = function () { alert(4); };Foo.getName();  // ------- 输出 2 -------
getName();      // ------- 输出 4 -------
Foo().getName();    // ------- 输出 1 -------
getName();  // ------- 输出 1 -------
new Foo.getName();     // ------- 输出 2 -------
new Foo().getName();    // ------- 输出 3 -------
var p = new new Foo().getName();     // ------- 输出 3 -------1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

全部解析过程 ↓

function Foo() {getName = function () { alert(1); };return this;
}
Foo.getName = function () { alert(2); };
Foo.prototype.getName = function () { alert(3); };
var getName = function () { alert(4); };Foo.getName();  // ------- 输出 2 -------
// 调用 Foo函数 作为 对象 动态添加的属性方法 getName
// Foo.getName = function () { alert(2); };getName();      // ------- 输出 4 -------
// 这里 Foo函数 还没有执行,getName还没有被覆盖
// 所以 这里还是 最上面的 getName = function () { alert(4); };Foo().getName();    // ------- 输出 1 -------
// Foo()执行,先覆盖全局的 getName 再返回 this,
// this 是 window, Foo().getName() 就是调用 window.getName
// 此时 全局的 getName已被覆盖成 function () { alert(1); };
// 所以 输出 1
/* 从这里开始 window.getName 已被覆盖 alert 1 */getName();  // -------- 输出 1 --------
// window.getName alert(1);new Foo.getName();     // ------- 输出 2 -------
// new 就是 找 构造函数(),由构造函数结合性,这里即使 Foo无参,也不能省略 (),所以不是 Foo().getName()
// 所以 Foo.getName 为一个整体,等价于 new (Foo.getName)();
// 而 Foo.getName 其实就是函数 function () { alert(2); } 的引用
// 那 new ( Foo.getName )(), 就是在以 Foo.getName 为构造函数 实例化对象。
// 就 类似于 new Person(); Person 是一个构造函数// 总结来看 new ( Foo.getName )(); 就是在以 function () { alert(2); } 为构造函数来构造对象
// 构造过程中 alert( 2 ),输出 2new Foo().getName();    // ------- 输出 3 -------
// new 就是 找 构造函数(),等价于 ( new Foo() ).getName();
// 执行 new Foo() => 以 Foo 为构造函数,实例化一个对象
// ( new Foo() ).getName; 访问这个实例化对象的 getName 属性
// 实例对象自己并没有 getName 属性,构造的时候也没有 添加,找不到,就到原型中找
// 发现 Foo.prototype.getName = function () { alert(3); };
// 原型中有,找到了,所以 ( new Foo() ).getName(); 执行,alert(3)var p = new new Foo().getName();     // ------- 输出 3 -------
// new 就是 找 构造函数(),等价于 new ( ( new Foo() ).getName )() 输出 3// 先看里面的 ( new Foo() ).getName
// new Foo() 以Foo为构造函数,实例化对象
// new Foo().getName 找 实例对象的 getName属性,自己没有,去原型中找,
// 发现 Foo.prototype.getName = function () { alert(3); }; 找到了// 所以里层 ( new Foo() ).getName 就是 以Foo为构造函数实例出的对象的 一个原型属性
// 属性值为一个函数 function () { alert(3); } 的引用// 所以外层 new ( (new Foo()).getName )()在以该函数 function () { alert(3); } 为构造函数,构造实例
// 构造过程中 执行了 alert(3), 输出 31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
  1. 上下文调用模式

就是 环境调用模式 => 在不同环境下的不同调用模式

简单说就是统一一种格式, 可以实现 函数模式与方法模式

-> 语法(区分)

call 形式, 函数名.call( … )
apply 形式, 函数名.apply( … )

这两种形式功能完全一样, 唯一不同的是参数的形式. 先学习 apply, 再来看 call 形式
apply方法的调用形式

存在上下文调用的目的就是为了实现方法借用,且不会污染对象。

如果需要让函数以函数的形式调用, 可以使用foo.apply( null ); // 上下文为 window如果希望他是方法调用模式, 注意需要提供一个宿主对象foo.apply( obj ); // 上下文 为 传的 obj 对象function foo () {console.log( this );
}
var o = { name: 'jim' };// 如果需要让函数以函数的形式调用, 可以使用
foo.apply( null ); //  this => window  // 或 foo.apply()// 如果希望他是方法调用模式, 注意需要提供一个宿主对象
foo.apply( o )  // this => o 对象1
2
3
4
5
6
7
8
9
10

带有参数的函数如何实现上下文调用?

function foo ( num1, num2 ) {console.log( this );return num1 + num2;
}// 函数调用模式
var res1 = foo( 123, 567 );// 方法调用
var o = { name: 'jim' };
o.func = foo;
var res2 = o.func( 123, 567 );1
2
3
4
5
6
7
8
9
10
11
12

使用 apply 进行调用, 如果函数是带有参数的. apply 的第一个参数要么是 null 要么是对象

如果是 null 就是函数调用如果是 对象就是 方法调用, 该对象就是宿主对象, 后面紧跟一个数组参数, 将函数所有的参数依次放在数组中.例如: 函数模式        foo( 123, 567 );apply         foo.apply( null, [ 123, 567 ] ) 以 window 为上下文执行 apply如果有一个函数调用:   func( '张三', 19, '男' ),
将其修改成 apply 模式:  func.apply( null, [ '张三', 19, '男'] )方法模式:           o.func( 123, 567 )
apply               var o = { name: 'jim' };foo.apply( o, [ 123, 567 ] ); 以 o 为上下文执行 apply1
2
3
4
5
6
7
8
9

方法借用的案例

需求, 获得 div 与 p 标签, 并添加边框 border: 1px solid red

一般做法:

var p_list = document.getElementsByTagName('p');
var div_list = document.getElementsByTagName('div');var i = 0;
for( ; i < p_list.length; i++ ) {p_list[ i ].style.border = "1px solid red";
}
for( i = 0; i < div_list.length; i++ ) {div_list[ i ].style.border = "1px solid red";
}1
2
3
4
5
6
7
8
9
10利用方法借用优化,元素获取var t = document.getElementsByTagName;
var p_list = t.apply( document, [ 'p' ] );  // 方法借用
var div_list = t.apply( document, [ 'div' ] ); // 方法借用1
2
3接下来考虑下面的优化,两个for循环,只要将数组合并了,就可以只用一个 for 循环数组合并var arr1 = [ 1, 2, 3 ];var arr2 = [ 5, 6 ];arr1.push.apply( arr1, arr2 );  // 方法调用,第一个给上对象// 等价于 Array.prototype.push.apply( arr1, arr2 );1234所以同理,利用 apply 方法借用,将两个伪数组合并成同一个数组var arr = [];   // 伪数组没有 push 方法,所以这里要 声明一个 数组arr.push.apply( arr, p_list );  // 将 p_list里的内容,一个个当成参数放了进来,相当于不用遍历了arr.push.apply( arr, div_list ); // 同上,方法借用console.log( arr );1234

将两者综合, 使用forEach,最终 6 行就解决了

var t = document.getElementsByTagName, arr = [];
arr.push.apply( arr, t.apply( document, [ 'p' ] ) );
arr.push.apply( arr, t.apply( document, [ 'div'] ) );
arr.forEach( function( val, index, arr ) {val.style.border = '1px solid red';
});1
2
3
4
5
6

call 调用

在使用 apply 调用的时候, 函数参数, 必须以数组的形式存在. 但是有些时候数组封装比较复杂

所以引入 call 调用, call 调用与 apply 完全相同, 唯一不同是 参数不需要使用数组

foo( 123, 567 );foo.apply( null, [ 123, 567 ] );foo.call( null, 123, 567 );1
2
3
4
5函数调用: 函数名.call( null, 参数1,参数2,参数3… );方法调用: 函数名.call( obj, 参数1,参数2, 参数3… );

不传参时,apply 和 call 完全一样
借用构造方法实现继承

function Person ( name, age, gender ) {this.name = name;this.age = age;this.gender = gender;
}function Student ( name, age, gender, course ) {// 原型链结构不会变化,同时实现了继承的效果Person.call( this, name, age, gender );// 借用Person构造方法this.course = course;
}var p = new Student ( 'jim', 19, 'male', '前端' );
console.log( p );1
2
3
4
5
6
7
8
9
10
11
12
13
14

补充知识 1. 函数的 bind 方法 ( ES5 )

bind 就是 绑定

还是上面那个案例 获得 div 与 p 标签, 并添加边框 border: 1px solid red

var t = document.getElementsByTagName, arr = [];
arr.push.apply( arr, t.call( document, 'p'  ) );
arr.push.apply( arr, t.call( document, 'div' ) );
arr.forEach( function( val, index, arr ) {val.style.border = '1px solid red';
});1
2
3
4
5
6

我们 让 t 包含函数体(上面的方式),同时包含 对象,就可以更精简

var t = document.getElementsByTagName.bind( document ), arr = [];
arr.push.apply( arr, t('p') );
arr.push.apply( arr, t('div') );
arr.forEach( function( val, index, arr ) {val.style.border = '1px solid red';
});1
2
3
4
5
6

bind : 就是让函数绑定对象的一种用法

函数本身就是可以调用, 但是其如果想要作为方法调用, 就必须传入宿主对象, 并且使用 call 或 apply 形式

但是 bind 使得我的函数可以与某一个对象绑定起来, 那么在调用函数的时候, 就好像是该对象在调用方法,就可以直接传参,而不需要传宿主对象。

语法: 函数.bind( 对象 )

返回一个函数 foo,那么调用 返回的函数 foo, 就好像 绑定的对象在调用 该方法一样

 t.call( document, 'p' );t( 'p' ); 绑定后,就不用传宿主对象了,这里调用时上下文已经变成了 documentbind 是 ES 5 给出的函数调用方法1
2
3
4
5

补充知识 2. Object.prototype 的成员

Object.prototype 的成员

constructor
hasOwnProperty 判断该属性是否为自己提供
propertyIsEnumerable 判断属性是否可以枚举
isPrototypeOf 判断是否为原型对象
toString, toLocaleString, valueOffunction Person() {this.name = 'jim';
}
Person.prototype.age = 19;
var p = new Person();
console.log( p.hasOwnProperty( 'name' ) );  // true; p 是否含有 name 属性,原型上不管
console.log( p.hasOwnProperty( 'age' ) ); // false;  p 是否含有 age 属性/* Person.prototype 是 p 的原型 */
console.log( p.isPrototypeOf( Person.prototype ) ); // false
console.log( Person.prototype.isPrototypeOf( p ) );  // true;1
2
3
4
5
6
7
8
9
10
11

用途:一般把一个对象拷贝到另一个对象时,可以进行判断,更加严谨,以防把原型中的属性也拷贝过去了…
补充知识 3. 包装类型

字符串 string 是基本类型, 理论上讲不应该包含方法

那么 charAt, substr, slice, …等等方法,理论上都不应该有,但确是有的

所以引入包装对象的概念,在 js 中为了更好的使用数据, 为三个基本类型提供了对应的对象类型

Number
String
Boolean

在 开发中常常会使用基本数据类型, 但是基本数据类型没有方法, 因此 js 引擎会在需要的时候自动的将基本类型转换成对象类型, 就是包装对象

“abc”.charAt( 1 )“abc” -> s = new String( “abc” )s.charAt( 1 ) 返回结果以后 s 就被销毁

当基本类型.方法 的时候. 解释器首先将基本类型转换成对应的对象类型, 然后调用方法.

方法执行结束后, 这个对象就被立刻回收

在 apply 和 call 调用的时候, 也会有转换发生. 上下文调用的第一个参数必须是对象. 如果传递的是数字就会自动转换成对应的包装类型
补充知识 4. getter 和 setter 的语法糖 ( ES5 )

语法糖: 为了方便开发而给出的语法结构

本身实现:

var o = (function () {var num = 123;return {get_num: function () {return num;},set_num: function ( v ) {num = v;}};
})();1
2
3
4
5
6
7
8
9
10
11希望获得数据  以对象的形式
o.get_num();            => o.num 形式希望设置数据  以对象的形式
o.set_num( 456 );       => o.num = 456 形式1
2
3
4
5

所以 getter 和 setter 诞生 了

var o = (function () {var num = 123;return {// get 名字 () { 逻辑体 }get num () {console.log( '执行 getter 读写器了' );return num;},// set 名字 ( v ) { 逻辑体 }set num ( v ) {console.log( '执行 setter 读写器了' );num = v;}};
})();console.log( o.num );   // 执行 getter 读写器了   123
o.num = 33; // 执行 setter 读写器了
console.log( o.num ); // 执行 getter 读写器了 331
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

为什么不直接用 对象呢 var o = { num : 123 } ,也可以读写呀?

因为语法糖还可以 限制其赋值的范围,使用起来特别爽

var o = (function () {var num = 13;return {// get 名字 () { 逻辑体 }get num () {console.log( '执行 getter 读写器了' );return num;},// set 名字 ( v ) { 逻辑体 }set num ( v ) {console.log( '执行 setter 读写器了' );if ( v < 0 || v > 150 ) {console.log( '赋值超出范围, 不成功 ' );return;}num = v;}};
})();
o.num = -1;         // 执行 setter 读写器了// 读写器赋值超出范围, 不成功1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

补充知识 5. ES5 中引入的部分数组方法

forEach
map
filter
some
every
indexOf
lastIndexOfforEach, 数组遍历调用,遍历arr,参数三个 1某项, 2索引, 3整个数组var arr = [ 'hello', ' js', {  }, function () {} ];// 遍历 数组arr.forEach( function ( v, i, ary ) {console.log( i + '=====' + v );console.log( ary );});123456map 映射语法: 数组.map( fn )返回一个数组, 数组的每一个元素就是 map 函数中的 fn 的返回值就是对每一项都进行操作,并返回var arr = [ 1, 2, 3, 4 ];// 数学中: x -> x * xvar a = arr.map(function ( v, i ) {return v * v;});// a [1, 4, 9, 16]123456filter 就是筛选, 函数执行结果是 false 就弃掉, true 就收着语法: 数组.filter( function ( v, i ) { return true/false })var arr = [ 1, 2, 3, 4, 5, 6 ];// 筛选奇数var a = arr.filter( function ( v ) { return v % 2 === 1; });// a [ 1, 3, 5 ]1234some 判断数组中至少有一个数据复合要求 就返回 true, 否则返回 falsevar arr = [ '123', {}, function () {}, 123 ];// 判断数组中至少有一个数字var isTrue = arr.some( function ( v ) { return typeof v === 'number'; } );  // true;123every 必须满足所有元素都复合要求才会返回 truevar arr = [ 1, 2, 3, 4, 5, '6' ];// 判断数组中每一个都是数字var isTrue = arr.every( function ( v ) { return typeof v === 'number'; } ); } ); // false;123indexOf 在数组中查找元素, 如果含有该元素, 返回元素的需要( 索引 ), 否则返回 -1var arr = [ 1, 2, 3, 4, 5 ];var res = arr.indexOf( 4 );    // 要找 4console.log( res );    // 3     找 4 在 索引为 3 找到var arr = [ 1, 2, 3, 4, 5, 4, 5, 6 ];var res = arr.indexOf( 4, 4 ); // 要找 4, 从索引 4开始找console.log( res );    // 找到了 索引为 51234567lastIndexOf 从右往左找var arr = [ 1, 2, 3, 4, 5, 4, 5, 6 ];var res = arr.lastIndexOf( 4 );console.log( res );    // 索引为 5, 从最后一项开始找,即从 length-1 项开始找

转载于:https://blog.51cto.com/13696285/2125628

jS四种函数的调用方式相关推荐

  1. Python:几种函数的调用方式

    第一种:class内部def函数与def函数之间的调用 test_getIdentify 函数调用test_getLastuser函数的返回值,只要在test_getIdentify 函数内写上sel ...

  2. jQuery中的四种事件监听方式

    jQuery中提供了四种事件监听方式,分别是bind.live.delegate.on,对应的解除监听的函数分别是unbind.die.undelegate.off.在开始看他们之前,先来声明一个例子 ...

  3. 微信小程序四种父子相互传值方式

    微信小程序四种父子相互传值方式 1. 绑定自定义属性(父传子),触发自定义方法 (子传父) 原生微信小程序+uni-app都可以实现 父组件: <template><view cla ...

  4. Cpp 对象模型探索 / 类静态成员函数的调用方式

    一.普通静态成员函数的调用方法 栗子: class CA { public:static void func() {} };int main() {CA A;A.func();CA::func();r ...

  5. html动态加载js方法,动态引入js四种方法总结

    这次给大家带来动态引入js四种方法总结,动态引入js四种方法的注意事项有哪些,下面就是实战案例,一起来看一下. index.html test.jsalert("hello! I am te ...

  6. Unity—AssetBundle的打包及四种加载资源方式

    AssetBundle打包:脚本放在Editor文件夹内 具体代码如下: using UnityEditor; using System.IO;public class CreateAssetBund ...

  7. js调用c语言程序设计,HTML页面,测试JS对C函数的调用简单实例

    HTML页面,测试JS对C函数的调用 //http://www.w3schools.com/jsref/event_onclick.asp //document.write('Hello World! ...

  8. post 表单中常见的四种表单请求方式

    //post 表单中常见的四种表单请求方式 typedef enum {     postformURLEncoded,                 /*对应Content-Type: appli ...

  9. java regex match 替换_java正则表达式四种常用的处理方式(匹配、分割、替代、获取)...

    java 正则表达式高级篇,介绍四种常用的处理方式:匹配.分割.替代.获取,具体内容如下 package test; import java.util.regex.Matcher; import ja ...

最新文章

  1. python增加一列数据计算年龄_无法使用python中的条件计算年龄。得到一个价值
  2. 哪种css实现方式优势更突出_【第十三课】更合理的CSS结构
  3. 网络营销专员浅析网络营销过程中如何做好网站权重流量的优化
  4. kafka内存不断增加_分布式发布订阅消息系统Kafka 为什么快
  5. 机器学习教程 一-不懂这些线性代数知识 别说你是搞机器学习的
  6. vb6.0 生成exe被简称是木马_使用MSF渗透框架生成PHP木马并实现控制远程服务器
  7. glide scaletype 无效_android 自定义圆角ImageView,后设置scaleType=centerCrop无效?
  8. 设置谷歌浏览器深色黑色背景
  9. 图片放大后模糊怎么变清晰?
  10. php怎么画五星红旗,PHP_php基于GD库画五星红旗的方法,本文实例讲述了php基于GD库画 - phpStudy...
  11. 系统更新win10服务器出错怎么办,windows10更新升级失败0x80072ee2解决方法
  12. k8s健康检查(七)
  13. ADP(自适应动态规划)-扩展HDP
  14. linux添加驱动模块,Linux驱动模块添加
  15. 苹果6严重卡顿_苹果手机iOS系统: 如果开放系统降级通道会怎么样?
  16. Python:实现graham scan葛立恒扫描法算法(附完整源码)
  17. Element UI, Ant Design Vue
  18. 移动端和前端开发的共性
  19. vue表格某一列的显示与隐藏
  20. 星舰到底要实现什么壮志?火星移民,月球旅行,亦是地球轨道运输

热门文章

  1. “芯片大脑“是什么?科学家提出了“忆阻性神经混合芯片“这一概念
  2. 正经“长生不老药”新进展:口服那种,贝佐斯投资 | 柳叶刀子刊
  3. 五分钟示范“教会”演员说外语,还可无缝切换语种,这家AI配音公司刚获2000万美元A轮融资...
  4. 谷歌年度AI技术总结来了!Jeff Dean执笔,附赠27个开源工具和数据大礼包
  5. 图灵YYDS!60年前不被看好的理论再次被证,这次是原子层面的
  6. 首次在观测中证实霍金黑洞面积定理!他们从引力波中算出黑洞真实面积
  7. 问答平台元老Yahoo Answers宣布将永久关闭,网友:爷青结
  8. 就挺凡尔赛的!李开复谈20年后的AI,崔宝秋论开源之道,清华唐杰的PPT成了“香饽饽” | MEET2021智能未来大会...
  9. Service Mesh:调度千军万马微服务,2.0妥妥的
  10. 百度的智能办公平台来了!12岁百度Hi今天全面升级,让协作「如流」