日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

javascirpt历史澄清误解基本概念特点编程语言web2.0网页javascript - javascirpt知识大全...

發布時間:2023/12/19 javascript 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javascirpt历史澄清误解基本概念特点编程语言web2.0网页javascript - javascirpt知识大全... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


目錄
1歷史 2澄清誤解 3基本概念 4特點 5與Java的不同 6開發工具


歷史
  大概在1992年,一家稱作Nombas的公司開始開發一種叫做C減減(C-minus-minus,簡稱Cmm)的嵌入式腳本語言。這個腳本語言捆綁在一個叫做CEnvi的共享軟件產品中,當Netscape Navigator嶄露頭角時,Nombas開發了一個可以嵌入網頁中的CEnvi的版本。這些早期的試驗稱為EspressoPage(濃咖啡般的頁面),它們代表了第一個在萬維網上使用的客戶端腳本語言。而Nombas絲毫沒有料到它的理念將會成為因特網的一塊重要基石。
澄清誤解
  * JavaScript是Java的變種嗎?
  JavaScript最初的確是受Java啟發而開始設計的,而且設計的目的之一就是“看上去像Java”[2],因此語法上有很多類似之處,許多名稱和命名規范也借自Java。但是實際上,JavaScript的主要設計原則源自Self和Scheme[3],它與Java本質上是不同的。它與Java名稱上的近似,是當時網景為了營銷考慮與Sun公司達成協議的結果。
  * JavaScript與JScript相同嗎?
  為了取得技術優勢,微軟推出了JScript來迎戰JavaScript的腳本語言。為了互用性,Ecma國際(前身為歐洲計算機制造商協會)建立了ECMA-262標準(ECMAScript)。現在兩者都屬于ECMAScript的實現。
  * JavaScript是一門簡單的語言嗎?
  盡管JavaScript作為給非程序人員的腳本語言,而非作為給程序人員的編程語言來推廣和宣傳,但是JavaScript是一門具有非常豐富特性的語言,它有著和其他編程語言一樣的復雜性,或更甚復雜。實際上,你必需對JavaScript有扎實的理解才能用它來撰寫比較復雜的程序。
基本概念
  在這里只作簡單介紹,在以后的例子中結程序再作具體解釋其作用。
  1、運算符
  運算符就是完成操和的一系列符號,它有七類:
  賦值運算符(=,+=,-=,*=,/=,%=,<<=,>>=,|=,&=)、算術運算符(+,-,*,/,++,--,%)、比較運算符(>,<,<=,>=,==,===,!=,!==)、邏輯運算符(||,&&,!)、條件運算(?:)、位移運算符(|,&,<<,>>,~,^)和字符串運算符(+)。
  可能很多人不知道"==="什么。
  在這里,我為大家解釋一下,在javascript中 "==="才是全等 只有"==="兩邊的內存地址也相等 才會返回真
  而"=="只是值相等就會返回真
  例如:null==undefined 會返回真 , 但是null===undefined 就會返回假!
  2、表達式
  運算符和操作數的組合稱為表達式,通常分為四類:賦值表達式、算術表達式、布爾表達式和字符串表達式。
  3、語句
  Javascript程序是由若干語句組成的,語句是編寫程序的指令。Javascript提供了完整的基本編程語句,它們是:
  賦值語句、switch選擇語句、while循環語句、for循環語句、for each循環語句、do while循環語句、break循環中止語句、continue循環中斷語句、with語句、try...catch語句、
  if語句(if..else,if...else if ...)、let語句。
  4、函數
  函數是命名的語句段,這個語句段可以被當作一個整體來引用不著和執行。使用函數要注意以下幾點:
  1)函數由關鍵字function定義(也可由Function構造函數構造);
  2)使用function關鍵字定義的函數在一個作用域內是可以在任意處調用的(包括定義函數的語句前);而用var關鍵字定義的必須定義后才能調用;
  3)函數名是調用函數時引用的名稱,它對大小寫是敏感的,調用函數時不可寫錯函數名;
  4)參數表示傳遞給函數使用或操作的值,它可以是常量,也可以是變量,也可以是函數,在函數內部可以通過arguments對象(arguments對象是一個偽數組,屬性callee引?? 用被調用的函數)訪問所有參數;
  5)return語句用于返回表達式的值。
  6)yield語句扔出一個表達式,并且中斷函數執行直到下一次調用next。
  一般的函數都是以下格式:
  function myFunction(params){
  //執行的語句
  }
  函數表達式:
  var myFunction=function(params){
  //執行的語句
  }
  匿名函數,它常作為參數在其他函數間傳遞:
  window.addEventListener('load',function(){
  //執行的語句
  },false);
  5、對象
  Javascript的一個重要功能就是面向對象的功能,通過基于對象的程序設計,可以用更直觀、模塊化和可重復使用的方式進行程序開發。
  一組包含數據的屬性和對屬性中包含數據進行操作的方法,稱為對象。比如要設定網頁的背景顏色,所針對的對象就是document,所用的屬性名是bgcolor,如document.bgcolor="blue",就是表示使背景的顏色為藍色。
  6、事件
  用戶與網頁交互時產生的操作,稱為事件。事件可以由用戶引發,也可能是頁面發生改變,甚至還有你看不見的事件(如Ajax的交互進度改變)。絕大部分事都由用戶的動作所引發,如:用戶按鼠標的按鈕,就產生click事件,若鼠標的指針的鏈接上移動,就產生mouseover事件等等。在Javascript中,事件往往與事件處理程序配套使用。
  而對事件的處理,W3C的方法是用addEventListener()函數,它有三個參數:事件,引發的函數,是否使用事件捕捉。為了安全性,建議將第三個參數始終設置為false;
  傳統的方法就是定義元素的on...事件,它就是W3C的方法中的事件參數前加一個“on”。而IE的事件模型使用attachEvent和dettachEvent對事件進行綁定和刪除。javascript中事件還分捕獲和冒泡兩個階段,但是傳統綁定只支持冒泡事件。學習Javascript比較快速有效的方法是先熟悉一些基本概念,然后找幾個別人設計好的程序認真仔細地分析一遍,再稍作改動,再看看能否達到預期目的,不斷地舉一反三,既可以加深對一些參數、設計方法的理解,又可以快速地提高自己的水平。另外,再提醒一下:Javascript對大小寫是敏感的,特別是一些對象、方法、屬性的大小寫一定要一致,要養成一種良好的習慣,否則在調試程序時可要累死你了。
  7、變量
  如 var myVariable = "some value";
  變量有它的類型,上例中myVariable的類型為string(字符串)
  javascript支持的常用類型還有:
  object:對象
  array:數組
  number:數;
  boolean:布爾值,只有true和false兩個值,是所有類型中占用內存最少的;
  null:一個空值,唯一的值是null;
  undefined:沒有定義和賦值的變量
  實際上javascript的變量是弱變量類型,你賦值給他的是字符串,他就是String .
  是數字他就是整形。是true和false他就是boolean型(注意,不能加引號,不然會被當成字符串處理)。
特點
  能夠具有交互性,能夠包含更多活躍的元素,就有必要在網頁中嵌入其它的技術。如:Javascript、VBScript、Document Object Model(DOM,文檔對象模型)、Layers和 Cascading Style Sheets(CSS,層疊樣式表),這里主要講Javascript。那么Javascript是什么東東?Javascript就是適應動態網頁制作的需要而誕生的一種新的編程語言,如今越來越廣泛地使用于Internet網頁制作上。 Javascript是由 Netscape公司開發的一種腳本語言(scripting language),或者稱為描述語言。在HTML基礎上,使用Javascript可以開發交互式Web網頁。Javascript的出現使得網頁和用戶之間實現了一種實時性的、動態的、交互性的關系,使網頁包含更多活躍的元素和更加精彩的內容。 運行用Javascript編寫的程序需要能支持Javascript語言的瀏覽器。Netscape公司 Navigator 3.0以上版本的瀏覽器都能支持 Javascript程序,微軟公司 Internet Explorer 3.0以上版本的瀏覽器基本上支持Javascript。微軟公司還有自己開發的Javascript,稱為JScript。 Javascript和Jscript基本上是相同的,只是在一些細節上有出入。 Javascript短小精悍, 又是在客戶機上執行的,大大提高了網頁的瀏覽速度和交互能力。 同時它又是專門為制作Web網頁而量身定做的一種簡單的編程語言。
  JavaScript 使網頁增加互動性。JavaScript 使有規律地重復的HTML文段簡化,減少下載時間。JavaScript 能及時響應用戶的操作,對提交表單做即時的檢查,無需浪費時間交由 CGI 驗證。JavaScript 的特點是無窮無盡的,只要你有創意。
與Java的不同
  Java之于Javascript就好比Car(汽車)之于Carpet(地毯)。
  ——來自Usenet上的Javascript討論組
  中國本地版的說法應該是這樣的:Java之于JavaScript就好比雷鋒和雷峰塔的關系。
  很多人看到 Java 和 JavaScript 都有“Java”四個字,就以為它們是同一樣東西,連我自己當初也是這樣。事實上,JAVA語言和JavaScript語言是相關的,但是它們的聯系并非你想像的那樣緊密。首先Java語言是SUN Microsystems公司的產品,而JavaScript是Netscape公司的產品。
  其次它們在功能上也有些差異:Java在客戶端的運行的應用程序叫做 Java Applet,是嵌在網頁中,而又有自己獨立的運行窗口的小程序。Java Applet 是預先編譯好的,一個 Applet 文件(.class)用 Notepad 打開閱讀,根本不能理解。Java Applet 的功能很強大,可以訪問 http、ftp等協議,甚至可以在電腦上種病毒(已有先例了)。相比之下,JavaScript 的能力就比較小了。JavaScript 是一種“腳本”(“Script”),它直接把代碼寫到 HTML 文檔中,瀏覽器讀取它們的時候才進行編譯、執行,所以能查看 HTML 源文件就能查看JavaScript 源代碼。JavaScript 沒有獨立的運行窗口,瀏覽器當前窗口就是它的運行窗口。它們的相同點,我想只有同是以 Java 作編程語言一點了。
  Java是由Sun Microsystems公司于1995年5月推出的Java程序設計語言和Java平臺的總稱。用Java實現的HotJava瀏覽器(支持Java applet)顯示了Java的魅力:跨平臺、動感的Web、Internet計算。從此,Java被廣泛接受并推動了Web的迅速發展,常用的瀏覽器現在均支持Java applet。另一方面,Java技術也不斷更新。
  Java平臺由Java虛擬機(Java Virtual Machine)和Java 應用編程接口(Application Programming Interface、簡稱API)構成。Java 應用編程接口為Java應用提供了一個獨立于操作系統的標準接口,可分為基本部分和擴展部分。在硬件或操作系統平臺上安裝一個Java平臺之后,Java 應用程序就可運行。現在Java平臺已經嵌入了幾乎所有的操作系統。這樣Java程序可以只編譯一次,就可以在各種系統中運行。
  Java分為三個體系JavaSE,JavaEE,JavaME。
開發工具
  javascript程序是純文本的,且不需要編譯,所以任何純文本的編輯器都可以編輯javascript文件。在Dreamweaver CS4中不僅有很好的代碼高亮,還有較全的代碼提示和錯誤提示,相比其他編輯器來說是十分強大的。
使用方法
  一、Javascript在網頁的用法
  Javascript加入網頁有兩種方法:
  1、直接加入HTML文檔
  這是最常用的方法,大部分含有Javascript的網頁都采用這種方法,如:
  <script type="application/javascript">
  <!--
  document.writeln("這是Javascript!采用直接插入的方法!");
  //-Javascript結束-->
  </script>
  在這個例子中,我們可看到一個新的標簽: <script>……</script>,而<script language="Javascript"> 用來告訴瀏覽器這是用Javascript編寫的程序,需要調動相應的解釋程序進行解釋。(w3c已經建議使用新的標準:<script type="application/javascript">)
  HTML的注釋標簽<!--和-->:用來去掉瀏覽器所不能識別的Javascript源代碼的,這對不支持 Javascript 語言的瀏覽器來說是很有用的。
  注意再非xhtml文檔中插入script標簽時,如果不是引用外部文件,應該在script內加上cdata聲明,避免大于和小于運算符引起的瀏覽器解析錯誤
  //-Javascript結束:雙斜杠表示 Javascript的注釋部分,即從//開始到行尾的字符都被忽略。 至于程序中所用到的document.write()函數則表示將括號中的文字輸出到窗口中去, 這在后面將會詳細介紹。 另外一點需要注意的是,<script>……</script>的位置并不是固定的,可以包含在<head>......</head> 或<body>.....</body>中的任何地方。
  還有一個更高級版本的嵌入腳本,它使用了HTML中的CDATA語法(Character Data,就是把CDATA中的文本全部當作純文本處理,除非遇到CDATA的結束)
  <script language="javascript" type="text/javascript"><!--//--><!CDATA[[//><!--
  //javascript代碼
  //--><!]]></script>
  2、引用方式
  如果已經存在一個Javascript源文件(通常以js為擴展名),則可以采用這種引用的方式,以提高程序代碼的利用率。其基本格式如下:
  <script src=“url” type="text/javascript"></script>
  其中的Url就是程序文件的地址。同樣的,這樣的語句可以放在HTML文檔頭部或主體的任何部分。 如果要實現“直接插入方式”中所舉例子的效果,可以首先創建一個Javascript源代碼文件“Script.js”,其內容如下:
  document.writeln("這是Javascript!采用直接插入的方法!");
  在網頁中可以這樣調用程序:<script src="Script.js" type="text/javascript"></script> 。
  也可以同時在導入文件時制定javascript的版本,例如:<script src="Script.js" type="text/javascript; version=1.8"></script>
  注意:凡是指定了src屬性的script標簽里的內容都會被忽略
Javascript 腳本的調試
  隨著用JavaScript編程的深入,你會開始理解那些JavaScript給出的不透明錯誤信息。一旦你理解了你常犯的一般性錯誤,你就會很快知道怎樣避免它們,這樣你寫的代碼中的錯誤將越來越少。編程實際上是一種能隨著時間不斷飛快進步的技術。但是不管變得多么熟練,你仍然要花一些時間調試你的代碼。如果你做過家庭作業,或有過JacaScript編程經驗,你會知道相當多的時間是花在調試上。這很正常 - 這只是編程者必須做的事之一。實際上,按照大量的研究,程序員平均百分之五十的時間花在解決代碼中的錯誤。
  調試的技巧:
  根據瀏覽器的提示信息
  選擇瀏覽器是很重要的,不同的瀏覽器的錯誤提示都不同,在瀏覽器中錯誤信息最容易理解的,能最快找出錯誤的,就是firefox和opera了。它們都會給出詳細的出錯原因和行號。
  使用調試工具
  如果你是Firefox的用戶,那么你可以到添加組件的網頁中搜索一些用于網頁開發的組件
  推薦:Firebug
  一款非常優秀的組件,可以指出你的腳本中的錯誤,查看DOM樹,查看cookie,ajax通信,并且還有CSS的調試工具,而且也有不少firebug的擴展。
  javascript debugger
  這是mozilla開發的調試工具,項目代號叫venkman,和gecko的javascript解析器無縫集成,功能非常強大。
  清除瀏覽器緩存
  有時瀏覽器會在網頁明明修改過的時候卻依然使用緩存里的網頁來顯示,這時最好強制刷新網頁以重新載入數據,如果還不行就清除緩存。
  輸出變量
  如果你使用firebug調試的話,可以很方便地在腳本里用console.log()來輸出變量的值,而且幸運的是,firebug還會對你輸出的變量進行解析,在控制臺里顯示一個清晰的變量結構
  如果你沒有firebug,那么可以用alert代替,不過當有幾百個變量輸出時,很可能不得不強行關閉瀏覽器。在網頁里專門放置一個調試用的div也是一種不錯的解決辦法。
編寫第一個JavaScript程序
  <html>
  <head>
  <script type="text/javascript">
  <!--
  document.write("Hello, world!") //直接在瀏覽器視窗顯示。
  ??????? alert("Hello, world!") //開啟對話視窗顯示。
  -->???????
  </script>
  </head>
  <body>
  </body>
  </html>
  JavaScript代碼由 <script type="text/javaScript">...</script>說明。在標識<script type ="text/javaScript">...</script>之間就可加入JavaScript腳本。 alert()是JavaScript的窗口對象方法,其功能是彈出一個具有OK對話框并顯示()中的字符串。 通過<!-- ...//-->標識說明:若不認識JavaScript代碼的瀏覽器,則所有在其中的標識均被忽略;若認識,則執行其結果。使用注釋這是一個好的編程習慣,它使其他人可以讀懂你的語言。 JavaScript 以 </Script> 標簽結束。
Javascript與DOM
  DOM是Document Object Model(文檔對象模型)的簡稱,它是讓javascript與頁面交互的一種方式,能夠動態修改文檔中的節點,元素,屬性等。
  DOM不僅適用于xhtml文檔,對于所有的xml文檔dom都是可以使用的。
  DOM的級別
  1級:基本的節點操作一級里都包括了
  2級:增加了對樣式表,文檔顯示,事件處理,等的支持
  3級:可以用javascript加載和保存文檔,檢查文檔錯誤
面向對象的javascript
  javascript中并沒有類的概念,但是javascript使用了一種叫原型化繼承的模型,而且javascript中也有作用域、閉包、繼承、上下文對象等概念
  
  作用域
  作用域是指變量存在的域,在文檔中的javascript腳本的作用域都是window。在javascript,function和let分隔作用域
  例如下面這個作用域的例子:
  var myVariable="outside";
  function myFunction(){
  var myVariable="inside";
  alert(myVariable);
  }
  myFunction();
  alert(myVariable);
  結果會是先彈出內容為“inside”的對話框,然后彈出內容為“outside”的對話框,這就是function建立了一個作用域,而第一次提示的是myFunction作用域內的myVariable
  下面是一個let控制作用域的例子:
  var myVariable="outside";
  let(myVarialbe="inside") alert(myVariable); // inside
  alert(myVariable); // outside
  let語句是在javascript 1.7中加入的
  閉包
  閉包也和作用域有關,它指的就是一個封閉的作用域(擁有外部變量,函數無法訪問的變量和函數),一般都是用一個匿名函數來做成閉包的
  (function(){
  var myVariable="private",
  })();
  alert(myVariable); // undefined
  上下文對象
  上下文對象指的就是this對象。它是一個只能讀取而不能直接賦值的對象(就是你只能對this擁有的屬性和方法賦值)。上下文對象在javascript可以說發揮的淋漓盡致。
  如果你在一個對象(Object)中使用this,指的就是這個對象
  var obj={
  getThis:function(){
  return this;
  }
  };
  alert(obj.getThis===obj); // true
  同樣的,在作用域中已經提到過文檔中javascript對象都屬于window,那么下面這個例子
  alert(window===this);
  也將提示true。
  上下文對象在事件偵聽器中指的就是發生事件的對象
  document.body.addEventListener('click',function(){
  alert(this===document.body); // true
  },false);
  this在構造函數中則是指實例
  function Person(name){
  this.name=name;
  }
  var Sam=new Persom();
  這里this指的就是Sam。
Javascript庫
  庫,指得是可以方便應用到現有開發體系中的、現成的代碼資源。庫不僅為大部分日常的DOM教本變成工作提供了快捷的解決方案,而且也提供了許多獨特的工具。雖然庫使用起來很方便,但它們也并非能解決你所有的問題。在使用庫之前,一定要保證真正理解javascript的DOM原理。
  這些庫一般是一個(或多個)js文件,只要把他們導入你的網頁就能使用了。
  查用的庫有:
  jQuery:javascript庫中的新成員,提供css和xpath選擇符查找元素,ajax,動畫效果等
  dojo:一個巨大的庫,包括的東西很多,dijit和dojox是dojo的擴展,幾乎你想要的各種javascript程序都包括了。
  prototype:一個非常流行的庫,使用了原型鏈向javascript中添加了很多不錯的函數
  YUI:yahoo!用戶界面,非常使用,提供各種解決方案。
如何提升JavaScript的運行速度
  遞歸是拖慢腳本運行速度的大敵之一。太多的遞歸會讓瀏覽器變得越來越慢直到死掉或者莫名其妙的突然自動退出(在firefox中彈出腳本無響應的對話框),所以我們一定要解決在JavaScript中出現的這一系列性能問題。在這個系列文章的第二篇中,我曾經簡短的介紹了如何通過memoization技術來替代函數中太多的遞歸調用。memoization是一種可以緩存之前運算結果的技術,這樣我們就不需要重新計算那些已經計算過的結果。對于通過遞歸來進行計算的函數,memoization簡直是太有用了。我現在使用的memoizer是由Crockford寫的,主要應用在那些返回整數的遞歸運算中。當然并不是所有的遞歸函數都返回整數,所以我們需要一個更加通用的memoizer()函數來處理更多類型的遞歸函數。
  function memoizer(fundamental, cache){ cache = cache || {} var shell = function(arg){ if (!(arg in cache)){ cache[arg] = fundamental(shell, arg) } return cache[arg]; }; return shell;}這個版本的函數和Crockford寫的版本有一點點不同。首先,參數的順序被顛倒了,原有函數被設置為第一個參數,第二個參數是緩存對象,為可選參數,因為并不是所有的遞歸函數都包含初始信息。在函數內部,我將緩存對象的類型從數組轉換為對象,這樣這個版本就可以適應那些不是返回整數的遞歸函數。在shell函數里,我使用了in操作符來判斷參數是否已經包含在緩存里。這種寫法比測試類型不是undefined更加安全,因為undefined是一個有效的返回值。我們還是用之前提到的斐波納契數列來做說明:
  var fibonacci = memoizer(function (recur, n) { return recur(n - 1) + recur(n - 2); }, {"0":0, "1":1});同樣的,執行fibonacci(40)這個函數,只會對原有的函數調用40次,而不是夸張的331,160,280次。memoization對于那些有著嚴格定義的結果集的遞歸算法來說,簡直是棒極了。然而,確實還有很多遞歸算法不適合使用memoization方法來進行優化。
  我在學校時的一位教授一直堅持認為,任何使用遞歸的情況,如果有需要,都可以使用迭代來代替。實際上,遞歸和迭代經常會被作為互相彌補的方法,尤其是在另外一種出問題的情況下。將遞歸算法轉換為迭代算法的技術,也是和開發語言無關的。這對JavaScript來說是很重要的,因為很多東西在執行環境中是受到限制的(the importance in JavaScript is greater, though, because the resources of the execution environment are so restrictive.)。讓我們回顧一個典型的遞歸算法,比如說歸并排序,在JavaScript中實現這個算法需要下面的代碼:
  function merge(left, right){ var result = []; while (left.length > 0 && right.length > 0){ if (left[0] < right[0]){ result.push(left.shift()); } else { result.push(right.shift()); } } return result.concat(left).concat(right);}//采用遞歸實現的歸并排序算法function mergeSort(items){ if (items.length == 1) { return items; } var middle = Math.floor(items.length / 2), left = items.slice(0, middle), right = items.slice(middle); return merge(mergeSort(left), mergeSort(right));}調用mergeSort()函數處理一個數組,就可以返回經過排序的數組。注意每次調用mergeSort()函數,都會有兩次遞歸調用。這個算法不可以使用memoization來進行優化,因為每個結果都只計算并使用一次,就算緩沖了結果也沒有什么用。如果你使用mergeSort()函數來處理一個包含100個元素的數組,總共會有199次調用。1000個元素的數組將會執行1999次調用。在這種情況下,我們的解決方案是將遞歸算法轉換為迭代算法,也就是說要引入一些循環(關于算法,可以參考這篇《List Processing: Sort Again, Naturally》)。
參考資料:
1.https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide
2.https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference


本文由 http://www.qqywf.com/ 提供,原文地址:http://www.qqywf.com/view/b_4862548.html

總結

以上是生活随笔為你收集整理的javascirpt历史澄清误解基本概念特点编程语言web2.0网页javascript - javascirpt知识大全...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。