JavaScript學習筆記(二)——閉包、IIFE、apply、函數與對象

来源:http://www.cnblogs.com/SeeYouBug/archive/2017/01/03/6243789.html
-Advertisement-
Play Games

一、閉包(Closure)1.1、閉包相關的問題1.2、理解閉包二、對象2.1、對象常量(字面量)2.2、取值2.3、枚舉(遍歷)2.4、更新與添加2.5、對象的原型2.6、刪除2.7、封裝三、函數3.1、參數對象 (arguments)3.2、構造函數 3.3、函數調用3.3.1、call3.3.... ...


一、閉包(Closure)

1.1、閉包相關的問題

請在頁面中放10個div,每個div中放入字母a-j,當點擊每一個div時顯示索引號,如第1個div顯示0,第10個顯示9;方法:找到所有的div,for迴圈綁定事件。

示例代碼:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>閉包</title>
        <style type="text/css">
            div {
                width: 100px;
                height: 100px;
                background: lightgreen;
                float: left;
                margin: 20px;
                font: 30px/100px "microsoft yahei";
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div>a</div>
        <div>b</div>
        <div>c</div>
        <div>d</div>
        <div>e</div>
        <div>f</div>
        <div>g</div>
        <div>h</div>
        <div>i</div>
        <div>j</div>
        <script type="text/javascript">
            var divs=document.getElementsByTagName("div");
            for (var i=0;i<divs.length;i++) {
                divs[i].onclick=function(){
                    alert(i);
                }
            }
        </script>
    </body>
</html>

運行結果:

因為點擊事件的函數內部使用外部的變數i一直在變化,當我們指定click事件時並沒有保存i的副本,這樣做也是為了提高性能,但達不到我們的目的,我們要讓他執行的上下文保存i的副本,這種機制就是閉包。

修改後的代碼:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>閉包</title>
        <style type="text/css">
            div {
                width: 100px;
                height: 100px;
                background: lightgreen;
                float: left;
                margin: 20px;
                font: 30px/100px "microsoft yahei";
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div>a</div>
        <div>b</div>
        <div>c</div>
        <div>d</div>
        <div>e</div>
        <div>f</div>
        <div>g</div>
        <div>h</div>
        <div>i</div>
        <div>j</div>
        <script type="text/javascript">
            var divs=document.getElementsByTagName("div");
            for (var i=0;i<divs.length;i++) {
                divs[i].onclick=(function(n){
                    return function(){
                        alert(n);    
                    }
                })(i);
            }
        </script>
    </body>
</html>

運行結果:

n是外部函數的值,但是內部函數(點擊事件)需要使用,返回函數前的n被臨時駐留在記憶體中給點擊事件使用,簡單說就是函數的執行上下文被保存起來,i生成了多個副本。

1.2、理解閉包

閉包概念:當一個內部函數被調用,就會形成閉包,閉包就是能夠讀取其他函數內部變數的函數,定義在一個函數內部的函,創建一個閉包環境,讓返回的這個子程式抓住i,以便在後續執行時可以保持對這個i的引用。內部函數比外部函數有更長的生命周期;函數可以訪問它被創建時所處的上下文環境。

Javascript語言特有的"鏈式作用域"結構(chain scope),子對象會一級一級地向上尋找所有父對象的變數

二、對象

對象就是“鍵/值”對的集合併擁有一個連接到原型(prototype)對隱藏連接。

2.1、對象常量(字面量)

一個對象字面量就是包含在一對花括弧中的零個或多個“鍵/值”對。對象字面量可以出現在任何允許表達式出現的地方。

對象的定義:

        //空對象
        var obj1={};
        
        //對象中的屬性
        var obj2={name:"foo",age:19};
        var obj3={"nick name":"dog"};
        
        //對象中的方法
        var obj4={
            price:99,
            inc:function(){
                this.price+=1;
            }
        }

對象中可包含的內容:

對象常量可以出現在任何允許表達式出現的地方,對象、數組、函數可以相互間嵌套,形式可以多種多樣。對象的值可以是:數組,函數,對象,基本數據類型等。

            //對象中可包含的內容
            var obj5 = [{
                name: "jack"
            }, {
                name: "lucy",  //常量
                hobby:["讀書","上網","代碼"],  //數組
                friend:{name:"mark",height:198,friend:{}},  //對象
                show:function(){  //函數
                    console.log("大家好,我是"+this.name);
                }
            }];
            //對象中的this是動態的,指向的是:調用者
            obj5[1].show();

輸出:大家好,我是lucy

2.2、取值

方法一:直接使用點號運算

            //3取值
            var obj6={"nick name":"pig",realname:"Rose"};
            console.log(obj6.realname);
            //console.log(obj6.nick name);  錯誤

方法二:使用索引器,當對象中的key有空格是

            //3取值
            var obj6={"nick name":"pig",realname:"Rose"};
            
            console.log(obj6["realname"]);
            console.log(obj6["nick name"]);

2.3、枚舉(遍歷)

方法一:

            var obj7={weight:"55Kg","nick name":"pig",realname:"Rose"};
            
            for (var key in obj7) {
                console.log(key+":"+obj7[key]);
            }

運行結果:

輸出順序是不能保證的。

2.4、更新與添加

如果對象中存在屬性就修改對應值,如果不存在就添加。對象通過引用傳遞,它們永遠不會被覆制

            var obj8={realname:"King"};
            obj8.realname="Queen";  //修改
            obj8.weight=1000;  //添加屬性
            obj8.show=function()  //添加方法
            {
                console.log(this.realname+","+this.weight);
            }
            obj8.show();

輸出:

Queen,1000

            var obj8={realname:"King"};
            obj8.realname="Queen";  //修改
            obj8.weight=1000;  //添加屬性
            obj8.show=function()  //添加方法
            {
                console.log(this.realname+","+this.weight);
            }
            obj8.show();
            
            //引用
            var obj9=obj8;   //obj9指向obj8的引用
            obj9.realname="Jack";
            obj8.show();

輸出:

2.5、對象的原型

javascript是一種動態語言,與C#和Java這樣的靜態語言是不一樣的;javascript並沒有嚴格的類型,可以簡單認為javascript是由對象組成的,對象間連接到原型(prototype)實現功能的擴展與繼承。每個對象都鏈接到一個原型對象,並且可以從中繼承屬性,所有通過常量(字面量)創建的對象都連接到Object.prototype,它是JavaScript中的頂級(標配)對象,類似高級語言中的根類。

現在我們修改系統中的Object對象,添加一個創建方法,指定要創建對象的原型,實現類似繼承功能:

        <script type="text/javascript">
            if(typeof Object.beget !== "function")
            {
                Object.create = function(o) {
                    //構造函數,用於創建對象
                    var F = function() {};
                    //指定由構造函數創建的對象的原型
                    F.prototype = o;
                    //調用構造方法創建新對象
                    return new F();
                }
            }
            
            var rose={
                name:"rose",
                show:function(){
                    console.log("姓名:"+this.name);
                }
            };
            
            rose.show();  //輸出
            
            var lucy=Object.create(rose);  //簡單認為是:創建一個對象且繼承rose
            lucy.name="lucy";  //重寫
            lucy.show();
        </script>

運行結果:

原型關係是一種動態關係,如果修改原型,該原型創建的對象會受到影響。

            var lucy=Object.create(rose);  //簡單認為是:創建一個對象且繼承rose
            lucy.name="lucy";  //重寫
            
            var jack=Object.create(rose);
            jack.name="jack";
            
            //修改原型中的方法
            rose.show=function(){
                console.log("姓名->"+this.name);
            }
            
            lucy.show();
            jack.show();

結果:

關於原型在函數中會再講到。

2.6、刪除

            //刪除屬性
            delete mark.name;   
            //調用方法,輸出:姓名:undefined
            mark.show(); 
            
            //刪除函數
            delete mark.show;  
            //錯誤,mark.show is not a function
            mark.show();

刪除不用的屬性是一個好習慣,在某些情況下可能引發記憶體泄漏。

2.7、封裝

使用對象封裝的好處是可以減少全局變數的污染機會,將屬性,函數都隸屬一個對象。

封裝前:

var name="foo";   //name是全局的,被暴露
            i=1;  //全局的,沒有var關鍵字聲明的變數是全局的,與位置關係不大
            function show(){  //show 是全局的,被暴露
                console.log("name->"+name);
                console.log(++i);
            }
            
            //i是全局的 2
            show();  
            //3
            show();

封裝後:

//對外只暴露bar,使用閉包封裝
            var bar=function(){
                var i=1;
                return{
                    name:"bar",
                    show:function(){
                        console.log("name->"+this.name);
                        console.log(++i);
                    }
                };
            };
            
            var bar1=bar();
            //2
            bar1.show();
            //3
            bar1.show();
            
            var bar2=bar();
            //2,因為被封裝,且閉包,i是局部私有的
            bar2.show();

運行結果:

三、函數

javascript中的函數就是對象,對象就是“鍵/值”對的集合併擁有一個連接到原型對隱藏連接。

3.1、參數對象 (arguments)

第一個函數中有一個預設對象叫arguments,類似數組,但不是數組,該對象是傳遞給函數的參數。

        <script type="text/javascript">
            function counter(){
                var sum=0;
                for(var i=0;i<arguments.length;i++){
                    sum+=arguments[i];
                }
                return sum;
            }
            
            console.log(counter(199,991,1,2,3,4,5));
            console.log(counter());
        </script>

運行結果:

1205

這裡的arguments是一個隱式對象,不聲明也在函數中,內部函數可以訪問外部函數的任意內容,但是不能直接訪問外部函數的arguments與this對象。

            function f1()
            {
                console.log(arguments.length);
                f2=function()
                {
                    console.log(arguments.length);
                }
                return f2;
            }
            
            var f=f1(1,2,3);
            f();

運行結果:

3

0

3.2、構造函數

在javascript中對象構造函數可以創建一個對象。

           <script type="text/javascript">
           /*構造函數*/
          //可以簡單的認為是一個類型的定義
           function Student(name,age){
                 this.name=name;
                 this.age=age;
                 this.show=function(){
                     console.log(this.name+","+this.age);
                 }
           }
           
           //通過new關鍵字調用構造函數,創建一個對象tom
           var rose=new Student("rose",18);
           var jack=new Student("jack",20);
           
           rose.show();
           jack.show();
        </script>

3.3、函數調用

3.3.1、call

調用一個對象的一個方法,以另一個對象替換當前對象

call([thisObj[,args])

hisObj 可選項。將被用作當前對象的對象。args 將被傳遞方法參數序列。
call 方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。

示例:

           /*構造函數*/
           function Student(name,age){
                 this.name=name;
                 this.age=age;
           }
           
            show=function(add){
                     console.log(add+":"+this.name+","+this.age);
               }
           
           //通過new關鍵字調用構造函數,創建一個對象tom
           var rose=new Student("rose",18);
           var jack=new Student("jack",20);
          
          //調用show方法,指定上下文,指定調用對象,this指向rose,“大家好是參數”
          show.call(rose,"大家好");
          show.call(jack,"Hello");

運行結果:

call方法中的參數都可以省去,第1個參數表示在哪個對象上調用該方法,或this指向誰,如果不指定則會指向window對象。

示例:

          var name="無名";
          var age=18;
          show.call();

結果:

undefined:無名,18

3.3.2、apply

apply([thisObj[,argArray]])
應用某一對象的一個方法,用另一個對象替換當前對象,與call類似。
如果 argArray 不是一個有效的數組或者不是arguments對象,那麼將導致一個 TypeError。
如果沒有提供 argArray 和 thisObj 任何一個參數,那麼 Global 對象將被用作 thisObj, 並且無法被傳遞任何參數。
對於第一個參數意義都一樣,但對第二個參數:
apply傳入的是一個參數數組,也就是將多個參數組合成為一個數組傳入,而call則作為call的參數傳入(從第二個參數開始)。
如 func.call(func1,var1,var2,var3)對應的apply寫法為:func.apply(func1,[var1,var2,var3])
同時使用apply的好處是可以直接將當前函數的arguments對象作為apply的第二個參數傳入

示例代碼:

           /*構造函數*/
           function Student(name,age){
                 this.name=name;
                 this.age=age;
           }
           
            show=function(greeting,height){
                     console.log(greeting+":"+this.name+","+this.age+","+height);
               }
           
           //通過new關鍵字調用構造函數,創建一個對象tom
           var rose=new Student("rose",18);
           var jack=new Student("jack",20);
          
          //調用show方法,指定上下文,指定調用對象,this指向rose,“大家好是參數”
          show.apply(rose,["大家好","178cm"]);
          show.apply(jack,["Hello","188cm"]);

運行結果:

 

從上面的示例中可以發現apply的第2個參數是一個數組,數組中的內容將映射到被調用方法的參數中,如果單這樣看發現不如call方便,其實如果直接取方法的參數arguments則apply要方便一些。通過簡單的變化就可以替代call。

          function display(){
             show.apply(jack,arguments);
          }
          display("hi","224cm");

結果:

hi:jack,20,224cm

javascript里call和apply操作符可以隨意改變this指向
如果在javascript語言里沒有通過new(包括對象字面量定義)、call和apply改變函數的this指針,函數的this指針都是指向window的。
關於this指針,我的總結是:是誰調用的函數,那麼這個函數中的this指針就是它;如果沒有明確看出是誰調用的,那麼應該就是window調用的,那麼this指針就是window。

3.3.3、caller

在一個函數調用另一個函數時,被調用函數會自動生成一個caller屬性,指向調用它的函數對象。如果該函數當前未被調用,或並非被其他函數調用,則caller為null。
在JavaScript的早期版本中,Function對象的caller屬性是對調用當前函數的函數的引用

        function add()
        {
            console.log("add被調用");
            //add方法的調用函數,如果調用add方法的不是函數則為null
            console.log(add.caller);
        }
        
        function calc(){
            add();
        }
        
        //直接調用add方法
        add(); 
        //間接通過calc方法調用
        calc();

運行結果:

caller與this還是有區別的,this是指調用方法的對象,而caller是指調用函數的函數。

        <script type="text/javascript">
        function add(n)
        {
            console.log("add被調用");
            if(n<=2){
                return 1;
            }
            return add.caller(n-1)+add.caller(n-2);
        }
        
        function calc(n){
            console.log("calc被調用");
            return add(n);
        }
        
        //1 1 2
        console.log(calc(3));
        </script>

結果:

3.3.4、Callee

當函數被調用時,它的arguments.callee對象就會指向自身,也就是一個對自己的引用

           function add(n1,n2){
                  console.log(n1+n2);
                  //arguments.callee(n1,n2);  //指向add方法
                  return arguments.callee;
           }
           
           add(1,2)(3,4)(5,6)(7,8)(8,9);

運行結果:

當第1次調用add方法時輸入3,立即將函數返回再次調用,每次調用後又返回自己,這樣可以實現鏈式編程。

3.5、立即執行函數表達式 (IIFE)

IIFE即Immediately-Invoked Function Expression,立即執行函數表達式

3.5.1、匿名函數與匿名對象

匿名函數就是沒有名稱的函數,javascript中經常會使用匿名函數實現事件綁定,回調,實現函數級的私有作用域,如下所示:

        function(){
            console.log("這是一個匿名函數");
        };

匿名對象:

        {
            name:"foo",
            show:function(){
                console.log(this.name);
            }
        }

沒有名稱的匿名函數也叫函數表達式,它們間是有區別的。

3.5.2、函數與函數表達式

下麵是關於函數與函數表達式定義時的區別

a)、函數定義(Function Declaration)

function Identifier ( Parameters ){ FunctionBody }

function 函數名稱(參數){函數主體}

在函數定義中,參數(Parameters)標識符(Identifier )是必不可少的。如果遺漏,會報提示錯誤:

代碼:

        function(){
            console.log("這是一個匿名函數");
        };

 

結果:

b)、函數表達式(Function Expression)

function Identifier(Parameters){ FunctionBody }
函數表達式中,參數和標識符都是可選的,與函數定義的區別是標識符可省去。

其實,"function Identifier(Parameters){ FunctionBody }"並不是一個完整的函數表達式,完整的函數的表達式,需要一個賦值操作。
比如: var name=function Identifier(Parameters){ FunctionBody }

3.5.3、立即執行函數表達式與匿名對象

            //1 正常定義函數
            function f1(){
                console.log("正常定義f1函數");
            };
            
            //2 被誤解的函數表達式
            function(){
                console.log("報錯Unexpected token (");
            }();
            
            //3 IIFE,括弧中的內容被解釋成函數表達式
            (function(){
                console.log("IIFE,正常執行");
            })();
            
            //4 函數表達式
            var f2=function(){
                console.log("這也被視為函數表達式");
            };

第3種寫法為什麼這樣就能立即執行並且不報錯呢?因為在javascript里,括弧內部不能包含語句,當解析器對代碼進行解釋的時候,先碰到了(),然後碰到function關鍵字就會自動將()裡面的代碼識別為函數表達式而不是函數聲明。

如果需要將函數表達式或匿名對象立即執行,可以使用如下方法:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>IIFE</title>
    </head>

    <body>
        <script type="text/javascript">
            //調用匿名函數
            (function() {
                console.log("這是一個函數表達式");
            })();

            //調用匿名對象
            ({
                name: "foo",
                show: function() {
                    console.log(this.name);
                }
            }).show();

            console.log({
                a: 1
            }.a);

            console.log({
                a: function() {}
            }.a());
        </script>
    </body>

</html>

運行結果:

3.5.4、各種IIFE的寫法

//最常用的兩種寫法
(function(){ /* code */ }()); // 老師推薦寫法
(function(){ /* code */ })(); // 當然這種也可以

// 括弧和JS的一些操作符(如 = && || ,等)可以在函數表達式和函數聲明上消除歧義
// 如下代碼中,解析器已經知道一個是表達式了,於是也會把另一個預設為表達式
// 但是兩者交換則會報錯
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();

// 如果你不怕代碼晦澀難讀,也可以選擇一元運算符
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();

// 你也可以這樣
new function(){ /* code */ }
new function(){ /* code */ }() // 帶參

如果是函數表達式,可直接在其後加"()"立即執行。

如果是函數聲明,可以通過"()"、"+"、"-"、"void"、"new"等運算符將其轉換為函數表達式,然後再加"()"立即執行。

3.5.5、參數

函數表達式也是函數的一種表達形式,同樣可以像函數一樣使用參數,如下所示:

            (function (n){
                console.log(n);
            })(100);

輸出:100 

其實通過IIFE還能形成一個類似的塊級作用域,當塊內的程式在使用外部對象時將優先查找塊內的對象,再查找塊外的對象,依次向上。

            (function(win,undfd){
                win.console.log("Hello"==undfd);
            })(window,undefined);

3.5.6、添加分號

為了避免與其它的javascript代碼產生影響後報錯,常常會在IIFE前增加一個分號,表示前面所有的語句都結束了,開始新的一語句。

            var k=100
            (function (n){
                console.log(n);
            })(k);

上面的腳本會報錯,因為javascript解釋器會認為100是函數名。

            var k=100
            ;(function (n){
                console.log(n);
            })(k);

 

這樣就正確了,在javascript中一行語句的結束可以使用分號,也可以不使用分號,因為一般的自定義插件會使用IIFE,這是一段獨立的代碼,在應用過程中不能保證用戶會加上分號,所以建議在IIFE前加上分號。

3.5.7、IIFE的作用

1)、提高性能

減少作用域查找時間。使用IIFE的一個微小的性能優勢是通過匿名函數的參數傳遞常用全局對象window、document、jQuery,在作用域內引用這些全局對象。JavaScript解釋器首先在作用域內查找屬性,然後一直沿著鏈向上查找,直到全局範圍。將全局對象放在IIFE作用域內提升js解釋器的查找速度和性能。

function(window, document, $) {

}(window, document, window.jQuery); 

2)、壓縮空間

通過參數傳遞全局對象,壓縮時可以將這些全局對象匿名為一個更加精簡的變數名

function(w, d, $) {  
  
}(window, document, window.jQuery);

3)、避免衝突

 匿名函數內部可以形成一個塊級的私有作用域。

4)、依賴載入

可以靈活的載入第三方插件,當然使用模塊化載入更好(AMD,CMD),示例如下。

A.html與B.html文件同時引用公用的common.js文件,但是只有A.html需要使用到StuObj對象,B.html不需要,但使用其它方法。

Student.js

var StuObj = {
    getStu: function(name) {
        return new Student(name);
    }
}

/*構造函數*/
function Student(name) {
    this.name = name;
    this.show = function() {
        console.log("Hello," + this.name);
    }
}

Common.js

function other1() {}

function other2() {}

(function($) {
    if($) {
        $.getStu("Tom").show();
    }
})(typeof StuObj=="undefined"?false:StuObj);

A.HTML

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>A</title>
    </head>
    <body>
        <script src="js/Student.js" type="text/javascript" charset="utf-8"></script<

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、舉例 用控制台程式做一個非常簡單的電腦,實現加減乘除運算即可,那麼,大家自然而然的會寫出如下代碼 二、演繹 1、第一步演繹 ①由於在判斷運算符時,用的是if語句,這意味著每個條件都需要做判斷,相當於電腦做了三次無用功。 ②沒有輸入校驗,例如,除數不能為零的問題等等 就上述兩個問題,做如下修改 ...
  • 下麵將帶領大家一步步學習nodejs,知道怎麼使用nodejs搭建伺服器,響應get/post請求,連接資料庫等。 搭建伺服器頁面輸出hello world 基本語句說明: 1)require 語句,模塊通過它載入。 對於該語句的解析可參見我的文章《require() 源碼解讀》(http://ww ...
  • CSS3的@keyframes,它可以取代許多網頁動畫圖像,Flash動畫,和JAVAScripts。 CSS3的動畫屬性 下麵的表格列出了 @keyframes 規則和所有動畫屬性: 瀏覽器支持 表格中的數字表示支持該屬性的第一個瀏覽器版本號。 緊跟在 -webkit-, -ms- 或 -moz- ...
  • 開始之前,安利一本正在看的書《站在兩個世界的邊緣》,作者程浩,上帝丟給他太多理想,卻忘了給他完成理想的時間。OK,有興趣的可以看一看。 node.js如標題一樣,我也是剛開始接觸,大家一起學習,有不當的地方望指正。node.js是做什麼的,有什麼優勢等問題。首先,它是什麼,它是採用C++語言編寫而成 ...
  • 資料搜索 選擇star最多的兩個 第一個就是用的比較多的jquery.qrcode.js(但不支持中文,不能帶logo)啦,第二個支持ie6+,支持中文,根據第二個源代碼,使得,jquery.qrcode.js,支持中文。 資料搜索 選擇star最多的兩個 第一個就是用的比較多的jquery.qrc ...
  • 在項目開發中我們經常會遇到需要更改input單選和多選樣式的情況,今天就給大家介紹一種簡單改變input單選和多選樣式的辦法。 在這之前先簡單介紹一下:before偽類 :before 選擇器向選定的元素前插入內容。使用content 屬性來指定要插入的內容(content是必須的哦)。 相信這並不 ...
  • 眾所周知,微信小程式在發佈的時候,對提交的代碼有1M大小的限制!所以,如果你正在寫一個功能稍微複雜一點的小程式,就必須得時刻小心註意你的代碼是不是快觸及這個底線了。 在設計一個小程式之初,我們就需要重點考慮這一點,採取一些方法,來避免太早的遭遇這個問題。 請避免在小程式的UI上使用大圖片,應該儘可能 ...
  • angular做單頁面應用是一個比較好的框架,但是它有一定的入門難度,對於新手來說可能會碰到很多坑,也有許多難題,大部分仔細看文檔,找社區是能解決的。 但有些問題也許資料比較少,最近遇到過一個要緩存父頁面的問題,就是點擊進入子頁後,再返回時父頁面的數據要緩存下來,包括滾動條的位置。再做的過程當中查過 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...