JavaScript高级教程- 第五课

转载 2007年09月21日 10:07:00
第一页:JavaScript高级教程- 第5天

哇!- 今天是最后一天!真是好极了!作为对您这些天辛勤工作的奖励,我把今天的课程安排得非常放松 - 没有本质代码萦绕在你脑中,也没有多如牛毛的家庭作业,只是编码理论和指向资源的连接。

今天讨论以下话题:

  • 帮你写JavaScript的工具
  • 调试技术
  • 使你的JavaScript代码快速运行的技巧

可得到的工具

说实话,就算称我为老学究,我也只用字处理器来写JavaScript。 虽然有大量的可用来写JavaScript的工具,但是它们产生的代码非常笨拙而且很难更改。如果你真想使用一种工具来创建JavaScript代码,我向你推荐Dreamweaver,它能在很短时间内产生一些令人惊异的JavaScript代码。但是,如果你打算随后更改这些代码,就要做好面对一些非常难看的代码的准备。

你也能找到帮你调试JavaScript的工具。我也不用这些工具。网景有一个,微软也有一个,但我从未见过很成功地使用这些调试器的人。你可以试一试,或许可以证明我是错的。但是在有人能使我确信某种产品值得买(暗示:送我一套那种免费软件)之前,我宁愿用老方法调试我的代码。

调试技术

随着用JavaScript编程的深入,你会开始理解那些JavaScript给出的不透明错误信息。一旦你理解了你常犯的一般性错误,你就会很快知道怎样避免它们,这样你写的代码中的错误将越来越少。编程实际上是一种能随着时间不断飞快进步的技术。但是不管变得多么熟练,你仍然要花一些时间调试你的代码。

如果你做过家庭作业,或有过JacaScript编程经验,你会知道相当多的时间是花在调试上。这很正常 - 这只是编程者必须做的事之一。实际上,按照大量的研究,程序员平均百分之五十的时间花在解决代码中的错误。

关键是学会怎样有效地调试你的程序。我有一些技巧可以帮助你解决程序为什么没有象应该的那样运行,或者帮你首先避免写有很多错误的代码:

  • 用不同方式打印出变量
  • 注意一般性错误
  • 编码之前先想好

让我们以打印出那些变量开始。

第二页:打印变量

一旦你发现一个错误,就可以清除它。不幸的是,发现它们的出处并不总是很容易 - 你的大部分调试时间只是花在指出错误的位置。

最可靠的方法之一是在你的代码中加入一些简单的语句打印出正在发生什么。假如你在下面的两段程序中发现一个问题:

function getName()
{
    var first_name = prompt("what's your first name?","");
    var last_name = prompt("what's your last name?","");
    var the_name = first_name + " " + last_name;

}

function theGreeting()
{
    var the_name = "";
    the_name = getName();

    if (the_name == "Dave Thau")
    {
alert("Hello, oh greatest one!");
    } else {
alert("Ahoy palloi!");
    }
}

运行这段程序,看看你是否能发现出了什么问题(Netscape 3.x的用户可能会遇到一些错误检查的问题,这是由于Netscape 3.x本身的原因,以下的Javascript例子与此相同)。如果你在警告对话框中随意输入一些名字,你会得到问候:“Ahoy palloi!”。但是,如果你在第一个提示对话框中输入“Dave”,在第二个中输入“Thau”,你应该得到“Hello,oh greatest one!”这条信息。然而,你还是只得到“Ahoy palloi!”这条信息。很明显,
函数中出了错误。在这个简单的例子程序中,你或许只是查看JavaScript代码就能发现错误。然而,当你的代码变得越来越复杂时,只靠目测来发现错误会变得愈加困难。

如果JavaScript没能捕获你的错误,你也没有通过查看代码发现错误,有时打印出变量会对你有所帮助。最简单的方法是象下面这样使用一个alert():

// theGreeting gets a name using getName, then presents
// one or two alert boxes depending on what the name is
//function getName()
{
    var first_name = prompt("what's your first name?","");
    var last_name = prompt("what's your last name?","");
    var the_name = first_name + " " + last_name;
    alert("in getName, the_name is: " + the_name);

}

// theGreeting gets a name using getName, then presents
// one of two alert boxes depending on what the name is
// function theGreeting()
{
   var the_name = "";
   the_name = getName();
   alert("after getName, the_name = " + the_name);
   if (the_name == "Dave Thau")
   {
   alert("hello, oh greatest one!");
   }else{
   alert("ahoy palloi!");
   }
}

请注意我们已经在所有重要的地方加入警告语句。现在试着运行这段程序。如果你输入名称“Dave”和“Thau”,你会注意到第一个警告显示“in getName, the_name is: Dave Thau,”,但是第二个警告显示“after getName, the_name = undefined,”,这就告诉你在getName()的最后一行事情变得糟糕起来。不知何故,the_name只在函数存在前正确,但是theGreeting没有给变量the_name正确赋值。当你写的函数能正确运行,但返回值出现
问题时,你最先要做的就是检查你是否的确让其返回了一个值。很明显,问题就出在这儿。getName()函数指出了名称,但没有返回它。所以我们应把语句“return the_name;”加到函数末尾。

把一些警告对话框加入你的代码中是很有帮助的。不幸的是,每隔一行就按一次“OK”也是一种痛苦。

不用警告对话框也能调试代码。一种选择是把调试信息写到窗体的一个文本区内。另一种可能是把调试信息写在另一个窗口上。这儿有一个把调试信息写在下面文本区的调试代码的例子。

使你的调试经历更舒适的第三个诀窍是这样的:创建不同的调试等级,然后设置“调试”变量。下面就是在此页上运行的JavaScript代码:

// debug can be either none, alert, or textarea
//  depending on the kind of debugging I want to do
// var debug = "none";
// function getName gets a first and last name,
// concatenates them with a space in between,
// and returns the name function getName()
{
    var first_name = prompt("what's your first name?","");
    var last_name = prompt("what's your last name?","");
    var the_name = first_name + " " + last_name;
    var error_message = "in getName, the_name is: " + the_name;
    doError("in getName, the_name is: " + the_name);
}

// theGreeting gets a name using getName, then presents
// one of two alert boxes depending on what the name is
// function theGreeting()
{
   var the_name = "";
   the_name = getName();
   doError("after getName, the_name = " + the_name);
   if (the_name == "Dave Thau")
   {
    alert("hello, oh greatest one!");
   } else {
    alert("ahoy palloi!");
   }
}

// doError is the error handling routine
// depending on the type of debug message
// it presents either no debug message, an alert
// or puts the message in a textarea
//
function doError(the_message)
{
    if (debug == "alert")
    {
    alert(the_message);
    } else if (debug == "textarea")
    {
    window.document.the_form.the_text.value +=    the_message + "<br>/n";
    }
}

    请注意我已经定义了一个叫“debug”的变量,它可以是“none”,“alert”或“textarea”。于是当我想产生一个错误信息时,我把它送给函数doError(),此函数可能什么也不做,或者显示一个消息对话框,或者把消息粘贴到一个文本区中,这取决于我怎样设置调试变量。当你想同时看到多条错误信息时,你可以设置调试变量为“textarea”。当你准备把你的代码显示给全世界时,你只需要把调试变量设为“none”,于是错误信息将不再出现,这样可以省去发现和清除所有调试语句的麻烦。

通常,程序员可以创建不同的调试等级,如“none”,“brief”和“extreme”。“brief”将打印一些调试信息,“extreme”将打印大量调试信息,“none”当然不会打印任何信息。

如果你按此方法建立你的调试系统,你可以在编码时把调试等级设为“brief”,在准备公布你的JavaScript时把调试变量设为“none”。如果有不可思议的事情发生,并且你不知道去哪儿发现问题,你可以把调试等级设为“extreme”,然后流览所有的调试信息直到发现可疑的地方。

好了,调试系统就讨论到这儿。现在让我们看看JavaScript编码
器产生的一般性错误。

第三页:一般性程序错误

多数错误只是无聊的语法错误。记住关闭那些引号,大括号和
小括号会花费很长时间,不过幸运的是JavaScript自动错误检
测器能捕获大部分此类错误。虽然JavaScript错误检测器随着
日渐复杂的流览器而不断完善,但是一些错误仍会溜走。下面
是一些需要留意的常见错误:

混淆变量名或函数名

大写和复数变量和函数名产生的错误令人烦恼地经
常出现,有时JavaScript错误检测器不能捕获它们。
通过建立和坚持使用一种对变量和函数的命名协定,
会大大减少这些麻烦的数量。例如,我全部用小写
字母定义变量,并用下划线代替空格 (my_variable,
the_data, an_example_variable),用内置符号表
示函数 (addThreeNumbers(), writeError()等)。
我避免使用任何复数,因为我总是忘记那些变量是
不是复数。

偶然地使用了保留字

一些字不能作为变量名,因为它们已经被JavaScript
使用。例如,不能定义一个叫“if”的变量,因为
它实际上是JavaScript的一部分 - 如果使用“if”,
你会遇到各种麻烦。当你因为使用命名为“if”的
变量而变得疯狂时,一个叫做“document”的变量
是很诱人的。不幸的是,“document”是一个
JavaScript对象。另一个经常遇到的问题是把变量
命名为“name”(窗体元素有“names”属性)。把
变量命名为“name”不会总出问题,只是有时 -
这会更使人迷惑 - 这就是避免使用“name”变量的
原因。

不幸的是,不同的流览器有不同的保留字,所以没
有办法知道该回避哪些字。最安全的办法是避免使
用已经成为JavaScript一部分的字和HTML使用的字。
如果你因为变量遇到问题,并且不能发现哪儿错了,
试着把变量改个名字。如果成功了,你或许就避开
了保留字。

记住在逻辑判断时应该用两个等号

一些流览器能捕获这种错误,有些却不能。这是一
种非常常见的错误,但是如果流览器不能替你指
出来,你就很难发现。下面是一个这种错误的例子:

var the_name = prompt("what's your name?", "");if (the_name = "the monkey"){    alert("hello monkey!");} else {    alert("hello stranger.");}

这段代码将产生“hello monkey!”警告对话框 -
不管你在提示里敲的是什么 - 这不是我们希望的。
原因是在if-then语句中只有一个等号,这句话告
诉JavaScript你想让一件事等于另一件。假设你在
提示中敲的是“robbie the robot”。最开始,变
量the_name的值是“robbie the robot”,但是随
后if语句告诉JavaScript你想把the_name设为
“the monkey.”。于是JavaScript很高兴地执行你
的命令,送一个“true”消息给if-then语句,结果
警告对话框每次都出现“hello monkey!”。

这种阴险的错误会使你发疯,所以注意使用两个
等号。

偶然给变量加上了引号,或忘了给字符串加引号

我不时遇到这个问题。JavaScript区分变量和字符
串的唯一方法是:字符串有引号,变量没有。下面
有一个明显的错误:

var the_name = 'koko the gorilla';alert("the_name is very happy");

虽然the_name是一个变量,但是程序还会产生一个
提示“the_name is very happy,”的警告对话框。
这是因为一旦JavaScript看见引号包围着某些东西
就不再考虑它,所以当你把the_name放在引号里,
你就阻止了JavaScript从内存中查找它。

下面是一个不太明显的此类错误的扩展(我们已经
在第三天的课程里见过):

function wakeMeIn3(){    var the_message = "Wake up!  Hey!  Hey!  WAKE UP!!!!";    setTimeout("alert(the_message);", 3000);}

这里的问题是你告诉JavaScript三秒后执行alert
(the_message)。但是,三秒后the_message将不再
存在,因为你已经退出了函数。这个问题可以这样
解决:

function wakeMeIn3(){   var the_message = "Wake up!";   setTimeout("alert('" + the_message+ "');", 3000);}

把the_message放在引号外面,命令“alert('Wake
up!');”由setTimeout预定好,就可以得到你想
要的。

这只是一些可能在你的代码中作祟的很难调试的
错误。一旦发现了它们,就有不同的或好或差的方
法来改正错误。你很幸运,因为你能从我的经验和
错误中获益。


第四页:修正错误

找到错误,有时侯虽然很难,却只是第一步。然后你必须清除
错误。下面是一些在清除错误时应该做的一些事:

首先拷贝你的程序

有些错误很难清除。实际上,有时在根除错误时,
你会破坏整个程序 - 一个小错误使你疯狂。在开始
调试前保存你的程序是确保错误不会利用你的最好
方法。

一次修正一个错误

如果你知道有好几个错误,应该修正一个,检验其
结果,再开始下一个。一次修正许多错误而不检验
你的工作只会招致更多的错误。

警惕迷惑性错误

有时你知道存在一个错误,但不真正知道为什么。
假设有一个变量“index”,由于某种原因“index”
总比你期望的小1。你可以做下面两件事中的一件:
在那儿坐一会儿,解决它为什么变小了,或只是耸
耸肩;在使用“index”之前加1,然后继续进行。后
一种方法称为迷惑编程。当你开始思考“究竟是怎
么了 - 为什么index是2而不是3呢?好吧...我现在
先让它正常工作,以后再修改错误。”时,你正在
把一块护创膏布贴到一处潜在的硬伤上。

迷惑编程可能在短期内有用,但是你可以看到长期
的厄运 - 如果你没有完全理解你的代码到可以真正
清除错误的程度,那个错误将会回来困扰你。它或
者以另一种你不能解决的怪异错误的方式回来,或
者当下一个可怜的被诅咒的灵魂读你的代码时,他
会发现你的代码非常难以理解。

寻找小错误

有时侯,对程序员来说,剪切和粘贴代码的能力是
一种很坏的事。通常,你会在一个函数中写一些
JavaScript代码,然后把它们剪切和粘贴到另一个
函数中。如果第一个函数有问题,那么现在两个函
数都有问题。我并不是说你不应该剪切和粘贴代码。
但是错误会以某种方式繁殖,如果你发现了一个
错误,你就应该寻找与其相似的其它错误。(或者
在制作它的若干版本之前确切知道会发生什么。)
变量名拼写错误在一段JavaScript代码中会突然多
次出现 - 在一个地方把the_name错拼成teh_name,
你就有机会在其它地方发现这个错误。

如果所有其它的方法都失败了

如果你正坐在那儿盯着一个错误,并且不能指出是
怎么回事(或者根本没有发现错误,但是因为程序
不能正确运行,你知道存在错误),你最好从计算
机前走开。去读一本书,在角落散散步,或者拿一
杯可口的饮料 - 做些事,任何事,但不要去想程序
或问题。这种技术在某种情况下叫做“酝酿”,效
果非常好。在你稍做休息和放松后,再试着找出
错误。你会得到一幅比较清晰的景象。“酝酿”起
作用是因为它使你从思维混乱中解脱出来。如果沿
着一条错路走太远,你有时会发现无法转身。这种
情况下最好开辟一条新路。我知道这会令人发火,
但确实有效。真的!

如果上面的方法还不成功...

请求别人的帮助。有时你的思想会形成定式,只有
换一种眼光才能洞察问题之所在。在结构化编程环
境中,程序员们定期地互相复查别人的代码。这可
以适当地叫做“代码复查”,不仅可以帮助消除
错误,还可以得到更好的代码。不要怕把你的
JavaScript代码给别人看,它会使你成为更好的
JavaScript程序员。

但是消除错误的绝对最好的办法是...

一开始就创建没有错误的代码。>>

第五页:好的编程实践

编好程序的关键是程序是写给人的,不是写给计算机的。如
果你能明白其他人或许会阅读你的JavaScript,你就会写更
清晰的代码。代码越清晰,你就越不容易犯错误。机灵的代
码是可爱的,但就是这种机灵的代码会产生错误。最好的经
验法则是KISS,即Keep It Simple,Sweetie(保持简单,可爱)。

另一个有帮助的技术是在写代码之前作注释。这迫使你在动
手之前先想好。一旦写好了注释,你就可以在其下面写代码。
下面是一个用这种方法写函数的例子:

第一步:写注释

//function beSassy()
//  beSassy asks for a user's name, chooses a random 
//  insult and returns an alert box with the user's name and the
//  insult.
function beSassy()
{
//  first write a list of insults
//

//  next get the user's name
//

//  then choose a random insult  
//

//  finally, return the personalized sass
//
}

第二步:填充代码

//function beSassy()
//  beSassy asks for a user's name, chooses a random 
//  insult and returns an alert box with the user's name and the
//  insult.
function beSassy()
{
//  first write a list of insults
//
var the_insult_list = new Array;
the_insult_list[0] = "your shoe lace is untied";
the_insult_list[1] = "your mama!";
the_insult_list[2] = "it's hard to be insulting";

//  next get the user's name
//
var the_name = prompt("What's your name?", "");

//  then choose a random insult  
//
var the_number =  Math.random() * 5;
var insult_number = parseInt(the_number);
var the_insult = the_insult_list[insult_number];

//  finally, return the personalized sass
//
alert("Hey " + the_name + " " + the_insult);
}

这种先写注释的策略不仅迫使你在写代码前思考,而且
使编码的过程看起来容易些 - 通过把任务分成小的,
易于编码的各个部分,你的问题看起来就不太象珠穆朗
玛峰,而象一群令人愉悦的起伏的小山。

最后...

总以分号结束你的每一条语句。

虽然并不是严格必需,你应该养成以分号结束每一条语
句的习惯,这样可以避免这行后面再有代码。忘了加
分号,下一行好的代码会突然产生错误。

把变量初始化为“var”,除非你有更好的理由不这样做。

用“var”把变量局域化可以减少一个函数与另一个不相
关函数相混淆的机会。

好了,既然你已经知道了如何编码,下面就让我们学习怎样使
你的JavaScript快速运行。


第六页:按速度优化JavaScript代码

一旦你的JavaScript能运行,你就会想到使其运行得更快。
在讲解加速代码的方法之前,让我先讲讲“80/20规则”:
百分之八十的优化是由最初百分之二十的工作所完成的。竭
力实现剩余百分之二十的速度优化是一种巨大的痛苦,而且
经常导致完全不能读和难以管理的代码。简言之,如果你的
JavaScript运行得很慢,你可以用很多简单的方法来加速它,
但是除非你的代码确实运行得很慢,我不会对它进行再优化。
下面是一些使你的代码轻松运行的方法。

限制循环内的工作量

程序运行慢的最常见原因是循环内的重复工作。如果一
条命令只需要执行一次,就没有必要把它放在循环内。
例如:

var index = 0;
while (index <10)
{
   var the_date = new Date();
   var the_day = the_date.getDay();
   var the_name = prompt("what's the kid's name? " ,"");
   alert("On " + the_day + " " + the_name + " is a very special person.");
    index++;
}

此程序循环执行10次。每次得到当天的日期,询问小孩
的名字,然后打印出“On Monday,so-and-so is a
very special person.”。

但是日期是不会改变的,总是今天。所以没有必要把前
两行放在循环中。把它们从循环中拿出来,让其只执行
一次而不是10次,这样会节省时间:
var index = 0;
var the_date = new Date();
var the_day = the_date.getDay();
while (index <10)
{
var the_name = prompt("what's the kid's name? " ,"");
alert("On " + the_day + " " + the_name + " is a very special person.");
index++;
}

定制if-then-else语句,按最可能到最不可能的顺序

因为if-then-else语句在遇到条件为真时结束,你可以
通过把最有可能的条件放到最开始来减少需要判断的语
句的数量。例如:

var pet = prompt("what kind of pet do you have?", "");
if (pet  == "cat") 
{
    doCatStuff();
} else if (pet == "dog") 
{
    doDogStuff();
} else if (pet == "bird")
{
    doBirdStuff();
} else if (pet == "lizard")
{
    doLizardStuff();
}

一般来说,程序中的if子句比从lizard到dog需要执行的
逻辑判断要少。

最小化重复执行的表达式

如果你发现需要重复计算一个特定的表达式,如
var pi=22/7,只计算一次并把它放在一个全局变量中或
许是个好主意。例如,不象下面程序这样:

function theArea(radius)
{
var pi = 22/7;
var area = pi * radius * radius;
return area;
}

function theCircumference(radius)
{
var pi = 22/7;
var circumference = 2 * pi * radius;
return circumference;
}

而是这样做:

var pi = 22/7;
function theArea(radius)
{
var area = pi * radius * radius;
return area;
}
function theCircumference(radius)
{
var circumference = 2 * pi * radius;
return circumference;
}

我知道我在用一个全局变量,我也说过这不是一个好主意。
然而,一些数字,如pi,其值在程序中永远不会改变,是
此规则的特例。通过只计算pi一次,可以省去额外的计算。
或许时间上的一些小的节省,累加起来会很管用。

如果你发现代码运行很慢,你只要注意一些事情。这些都
很明显,但是当你发现你经常忽略象这样简单的优化技巧
时,你会很吃惊。

还有,我的朋友,让我们结束今天的课程,这也是整个
JavaScript高级教程的结束。如果你已经进行到这儿,
并且你至少读过过去五天课程中的一半,那么你已经看
过很多JavaScript代码了。实际上,如果你能理解跨越
第一部分和第二部分的10课的大部分内容,你就可以很
安全地把自己称为“JavaScript助手”。通往神秘真知
的路就在你的脚下。

第七页:下面讲什么?

既然你已经对JavaScript有了实际的理解,你就可以写一些非
常认真的JavaScript程序了。现在该是把目标转移到JavaScript
应用上的时候。Taylor的“动态HTML教程”是一个很好的开始。
学会动态HTML,你就可以实现更远大的梦想。不论如何,总该
有一些梦想吧。

但是首先,你需要练习,练习,再练习。把已有的代码拿过来,
使它变得面目全非。或者白手起家写代码。努力写出无错误的
代码,成为一个能修正各种无论如何也要溜走的错误的专家。
用眼睛盯着有趣的和新的JavaScript应用程序,指出它们是如
何实现的。你的代码运行得是否完美并不重要,因为它总能教
你些什么。你学得越多,你的代码就会变得越好,越快,越容
易创建。

现在开始吧,年轻的JavaScript程序员,做些让我骄傲的事!

 

相关文章推荐

Bootstrap 教程第五课:制作下拉菜单

在Bootstrap教程第二课制作网站菜单中,提到了制作下拉菜单的相关代码(Bootstrap教程第二课:制作网站导航条),只是没有细细讲解,这节,我们来说说下拉菜单的制作。 首页,制作一个按钮...

用OpenSceneGraph实现的NeHe OpenGL教程 - 第五课

简介 这节课将在第四课的基础上进行扩展,创建3D物体。我们将三角形变为3D的三棱锥形,把四边形变为立方体。同时三棱锥沿Y轴旋转,四边形沿着(1,1,1)方向旋转。 实现 本课与第二课十分类似,...

斯坦福大学公开课 iOS应用开发教程学习笔记(第五课)Protocols,手势识别

斯坦福大学iOS应用开发教程学习笔记(第五课)Protocols,手势识别 主要4部分组成:自动旋转、 Protocols、 手势识别、一个自定义UIView的Demo 1、自...

ionic入门教程第五课-举例子说明异步回调$q及$q在项目中的用法

继上一节中我们使用到$q来辅助完成了按需加载文件。 这节课我先简要的介绍一下$q 先从功能上做简要介绍的话: 我想通过一个故事来简要的介绍$q,就那最近比较普遍的叫餐服务举例吧 今天我想吃牛肉炒饭,所...

Android OpenGL教程-第五课

Android OpenGL 教程第五课3D空间: 我们使用多边形和四边形创建3D物体,在这一课里,我们把三角形变为立体的金子塔形状,把四边形变为立方体。先看看三角形的顶点变成啥了privateflo...

Lance老师UI系列教程第五课->自定义风格单选多选对话框的实现

UI系列教程第五课:自定义单选多选对话框的实现 在Android的应用中,常常会用到单选和多选对话框 最简单的方式是直接使用系统自带的对话框 不过有时候出于对应用程序整体风格的考虑 会用到自定...

斯坦福大学iOS应用开发教程学习笔记(第五课)Protocols,手势识别

第五课内容: 自动旋转、 Protocols、 手势识别、一个自定义UIView的Demo 1、自动旋转 当设备旋转时,你的controller会做什么呢?你可以控制界面是否和设备一起一起旋转。 ...
  • Dev_Ho
  • Dev_Ho
  • 2014-11-04 13:29
  • 2206

[译文]JOAL教程 第五课 多声源共享缓冲区

[译文]JOAL教程 第五课 多声源共享缓冲区 本文是DevMaster.net(http://devmaster.net/)的OpenAL教程对应的JOAL版本。C语言版原文作者为JesseMaur...

2011斯坦福大学iOS应用开发教程学习笔记(第五课)Protocols,手势识别

第五课内容: 自动旋转、 Protocols、 手势识别、一个自定义UIView的Demo 1、自动旋转 当设备旋转时,你的controller会做什么呢?你可以控制界面是否和设备一起一起旋转。 ...

Android OpenGL教程-第五课

第五课 3D空间:   我们使用多边形和四边形创建3D物体,在这一课里,我们把三角形变为立体的金子塔形状,把四边形变为立方体。 先看看三角形的顶点变成啥了 private float[] m...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)