JavaScript權威指南 - 函數

来源:http://www.cnblogs.com/gao-yang/archive/2017/01/06/6256157.html
-Advertisement-
Play Games

函數本身就是一段JavaScript代碼,定義一次但可能被調用任意次。如果函數掛載在一個對象上,作為對象的一個屬性,通常這種函數被稱作對象的方法。用於初始化一個新創建的對象的函數被稱作構造函數。 相對於其他面向對象語言,在JavaScript中的函數是特殊的,函數即是對象。JavaScript可以把 ...


函數本身就是一段JavaScript代碼,定義一次但可能被調用任意次。如果函數掛載在一個對象上,作為對象的一個屬性,通常這種函數被稱作對象的方法。用於初始化一個新創建的對象的函數被稱作構造函數。

相對於其他面向對象語言,在JavaScript中的函數是特殊的,函數即是對象。JavaScript可以把函數賦值給變數,或者作為參數傳遞給其他函數,甚至可以給它們設置屬性等。

JavaScript的函數可以嵌套在其他函數中定義,這樣定義的函數就可以訪問它們外層函數中的任何變數。這也就是所謂的“閉包”,它可以給JavaScript帶來強勁的編程能力。

1.函數定義

函數使用function關鍵字定義,有函數語句函數表達式兩種定義方式。

//一.函數語句類:

//列印對象所有屬性名稱和值。
function printprops(obj) {
    for (var key in obj) {
        console.log(key + ":" + obj[key]);
    }
}
//計算階乘的遞歸函數,函數名稱將成為函數內部的一個局部變數。
function factorial(n) {
    if (n <= 1) return 1;
    return n * factorial(n);
}

//二.函數表達式類:

//計算n的平方的函數表達式。這裡將一個函數賦給一個變數。
var square = function (x) { return x * x; }

//兔子數列。函數表達式也可以包含名稱,方便遞歸。
var foo = function foo(n) {
    if (n <= 1) return 1;
    else foo(n - 1) + foo(n - 2);
}

//數組元素升序排列。函數表達式也能作為參數傳遞給其他函數。
var data = [5, 3, 7, 2, 1];
data.sort(function (a, b) { return a - b; });

//函數表達式有時定義後立即調用。
var tensquared = (function (x) { return x * x; }(10));

函數命名
函數名稱要求簡潔、描述性強,因為這樣可以極大改善代碼的可讀性,方便別人維護代碼;函數名稱通常是動詞或以動詞開頭的片語。通常來說,函數名編寫有兩種約定:

  1. 一種約定是函數名第一個單詞首字母小寫,後續單詞首字母大寫,就像likeThis()
  2. 當函數名包含多個單詞時,另一種約定是用下劃線來分割單詞,就像like_this()

項目中編寫方法名時儘量選擇一種保持代碼風格一致。還有,對於一些私有函數(不作為公用API的一部分),這種函數通常以一條下劃線作為前輟。

2.函數調用

函數聲明後需要通過調用才能被執行。JavaScript中通常有4種方式來調用函數:

  1. 作為普通函數;
  2. 作為對象方法;
  3. 作為構造函數;
  4. 通過它們的call()apply()方法間接調用。

下麵就通過一些具體示例來演示上述4中函數的調用方式。

1.對於普通函數,通過調用表達式就可直接調用,這種方式很直接也很常見。

//定義一個普通函數。
var strict = function () { return !this; }; //檢測當前運行環境是否為嚴格模式。
//通過函數名直接調用。
console.log(strict()); 

註:根據ES3和非嚴格的ES5對普通函數調用的規定,調用上下文(this)是全局對象;在嚴格模式下,調用上下文則是undefined。

2.通常,保存在對象屬性里的JavaScript函數被稱作“方法”。

//定義一個對象直接量。
var calc = { 
    a: null,
    b: null,
    add: function () { //將函數保存在對象屬性中。
        return this.a + this.b;
    }
};
//通過對象名調用方法。
calc.a = 1, calc.b = 2;
console.log(calc.add()); 

註:對象方法中的調用上下文(this)不同於普通函數中的上下文。這裡this指代當前對象。

方法鏈:當方法返回值是一個對象,那麼這個對象還可以再調用它的方法。每次調用的結果都是另外一個表達式的組成部分,這種方法調用方式最終會形成一個序列,也被稱為“方法鏈”。所以,在自己設計API的時候,當方法並不需要返回值時,最好直接返回this。這樣以後使用API就可以進行“鏈式調用”風格的編程。

需要註意的是,this是一個關鍵字,Javascript語法不允許給它賦值。再者,關鍵字this沒有作用域的限制,嵌套的函數不會從外層調用它的函數中繼承this。也就是說,如果嵌套函數作為方法調用,其this指向為調用它的對象。如果嵌套函數作為函數調用,其this值不是全局對象就是undefined。下麵通過一段代碼來具體說明。

var o = {
    m: function () { //對象中的方法
        var self = this; //將this的值保存在一個變數中
        console.log(this === o); //輸出true,表明this就是這個引用對象o
        f(); //調用嵌套函數f()
        function f() { //定義一個嵌套函數(**普通函數,非對象方法)
            console.log(this === o); //輸出false,this的值為全局對象或undefined
            console.log(self === o); //輸出true,變數self指外部函數的this值
        }
    }
}

3.如果函數或者防方法調用之前帶有關鍵字new,它就構成構造函數調用。構造函數調用會創建一個新的對象,構造函數通常不使用return,函數體執行完畢它會顯示返回。還有,創建的對象繼承自構造函數的prototype屬性,構造函數中使用this關鍵字來引用這個新創建的對象。

//與普通函數一樣的定義方式。
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.say = function () {
        console.log("My name is " + this.name + ", I am " + this.age + " years old.");
    }
}
//用關鍵字new調用構造函數,實例化對象。
var obj = new Person("Lamb", "21");
obj.say();//調用對象方法。

4.我們知道Javascript中的函數也是對象,所以函數對象也是可以包含方法的,其中call()apply()兩個方法可以用來間接地調用函數,這兩個方法都可以顯式指定調用函數裡面的調用上下文this

//定義一個列印函數。
function print() {
    if (this.text) {
        alert(this.text);
    } else {
        alert("undefined");
    }
}
//call方法間接調用方法,並指定其調用上下文。
print.call({ text: "hello" });

關於call()apply()兩個方法的用法以及區別下麵詳細討論。

3.函數的實參和形參

JavaScript中的函數定義不需要指定函數形參的類型,調用函數時也不檢查傳入形參的個數。這樣,同時也會留下兩個疑問給我們:

  1. 當調用函數時的實參個數和聲明的形參個數不匹配的時候如何處理;
  2. 如何顯式測試函數實參的類型,以避免非法的實參傳入函數。

下麵就簡單介紹JavaScript是如何對上述兩個問題做出處理的。

可選參數
當調用函數的時候傳入的實參比函數定義時指定的形參個數要少,剩下的形參都將設置為undefined。一般來說,為了保持函數較好的適應性,都會給省略的參數設置一個合理的預設值。

function getPropertyNames(obj,/*optional*/arr) {
    arr=arr||[];
    for (var property in obj) { arr.push(property); }
    return arr;
}

需要註意的是,當使用這種可選實參來實現函數時,需要將可選實參放在實參列表的最後。一般來書,函數定義中使用註釋/*optional*/來強調形參是可選的。

實參對象
當調用函數時傳入的參數個數超過了原本函數定義的形參個數,那麼方法中可以通過實參對象來獲取,標識符arguments是指向實參對象的引用。實參對象是一個類數組對象,可以通過數字下標來訪問傳入函數的實參值。實參對象有一個重要的用處,就是讓函數可以操作任意數量的實參,請看下麵的例子:

//返回傳入實參的最大值。
function max(/* ... */) {
    var max = Number.NEGATIVE_INFINITY; //該值代表負無窮大。
    for (var i = 0; i < arguments.length; i++) {
        if (arguments[i] > max) {
            max = arguments[i];
        }
    }
    return max;
}
//調用。
var largest = max(10, 45, 66, 35, 21); //=>66

還有重要的一點,如果函數中修改arguments[]元素,同樣會影響對應的實參變數。

除以上之外,實參對象還包含了兩個屬性calleecaller

  • callee是ECMAScript標準規範的,它指代當前正在執行的函數。
  • caller是非標準屬性但是大多數瀏覽器都支持,它指代當前正在執行函數的函數。
//callee可以用來遞歸匿名函數。
var sum = function (x) {
    if (x <= 1) return 1;
    return x + arguments.callee(x - 1);
}

//調用函數b,方法a中列印結果為函數b。
 var a = function () {
     alert(a.caller); 
 }
 var b = function () {
     a();
 }

註意,在ECMAScript 5嚴格模式下,對這兩個屬性進行讀寫會產生一個類型錯誤。

實參類型
聲明JavaScript函數時形參不需要指定類型,在形參傳入函數體之前也不會做任何類型檢查,但是JavaScript在必要的時候會進行類型轉換,例如:

function mult(a, b) {
    return a * b;
}
function conn(x, y) {
    return x + y;
}
console.log(mult(3, "2")); //字元串類型自動轉為數字類型,輸出結果:6
console.log(conn(3, "2")); //數字類型自動轉為字元串類型,輸出結果:"32"

上述的兩種類型存在隱式轉換關係所以JS可以自動轉換,但是還存在其他情況:比如,一個方法期望它第一個實參為數組,傳入一個非數組的值就可能引發問題,這時就應當在函數體中添加實參類型檢查邏輯。

4.作為值的函數

開篇提到過,在JavaScript中函數不僅是一種語法,函數即是對象,簡單歸納函數具有的幾種性質:

1.函數可以被賦值給一個變數;

function square(x) { return x * x; }
var s = square; //現在s和square指代同一個函數對象
square(5); //=>25
s(5); //=>25

2.函數可以保存在對象的屬性或數組元素中;

var array = [function (x) { return x * x; }, 20];
array[0](array[1]); //=>400

3.函數可以作為參數傳入另外一個函數;

//這裡定義一些簡單函數。
function add(x, y) { return x + y; }
function subtract(x, y) { return x - y; }
function multipty(x, y) { return x * y; }
function divide(x, y) { return x / y; }
//這裡函數以上面某個函數做參數。
function operate(operator, num1, num2) {
    return operator(num1, num2);
}
//調用函數計算(4*5)-(2+3)的值。
var result = operate(subtract, operate(multipty, 4, 5), operate(add, 2, 3));
console.log(result); //=>15

4.函數可以設置屬性。

//初始化函數對象的計數器屬性。
uniqueInteger.counter = 0;
//先返回計數器的值,然後計數器自增1。
function uniqueInteger() {
    return uniqueInteger.counter+=1; 
}

當函數需要一個“靜態”變數來在調用時保持某個值不變,最方便的方式就是給函數定義屬性,而不是定義全局變數,因為定義全局變數會讓命名空間變的雜亂無章。

5.作為命名空間的函數

函數中聲明的變數只在函數內部是有定義,不在任何函數內聲明的變數是全局變數,它在JavaScript代碼中的任何地方都是有定義的。JavaScript中沒有辦法聲明只在一個代碼塊內可見的變數的。基於這個原因,常常需要定義一個函數用作臨時的命名空間,在這個命名空間內定義的變數都不會污染到全局變數。

//該函數就可看作一個命名空間。
function mymodule() {
    //該函數下的變數都變成了“mymodule”空間下的局部變數,不會污染全局變數。
}
//最後需要調用命名空間函數。
mymodule();

上段代碼還是會暴露出一個全局變數:mymodule函數。更為常見的寫法是,直接定義一個匿名函數,併在單個表達式中調用它:

//將上面mymodule()函數重寫成匿名函數,結束定義並立即調用它。
(function () {
    //模塊代碼。
}());

6.閉包

閉包是JavaScript中的一個難點。在理解閉包之前先要明白變數作用域函數作用域鏈兩個概念。

  • 變數作用域:無非就是兩種,全局變數和局部變數。全局變數擁有全局作用域,在任何地方都是有定義的。局部變數一般是指在函數內部定義的變數,它們只在函數內部有定義。

  • 函數作用域鏈:我們知道JavaScript函數是可以嵌套的,子函數對象會一級一級地向上尋找所有父函數對象的變數。所以,父函數對象的所有變數,對子函數對象都是可見的,反之則不成立。需要知道的一點是,函數作用域鏈是在定義函數的時候創建的。

關於“閉包”的概念書本上定義很具體,但是也很抽象,很難理解。簡單的理解,“閉包”就是定義在一個函數內部的函數(這麼說並不准確,應該說閉包是函數的作用域)。

var scope = "global scope"; //全局變數
function checkscope() {
    var scope = "local scope"; //局部變數
    function f() { return scope; } //在作用域中返回這個值
    return f();
}
checkscope(); //=>"local scope"

上面一段代碼就就實現了一個簡單的閉包,函數f()就是閉包。根據輸出結果,可以看出閉包可以保存外層函數局部變數,通過閉包可以把函數內的變數暴露在全局作用域下。

閉包有什麼作用呢?下麵一段代碼是上文利用函數屬性定義的一個計數器函數,其實它存在一個問題:惡意代碼可以修改counter屬性值,從而讓uniqueInteger函數計數出錯。

//初始化函數對象的計數器屬性。
uniqueInteger.counter = 0;
//先返回計數器的值,然後計數器自增1。
function uniqueInteger() {
    return uniqueInteger.counter+=1; 
}

閉包可捕捉到單個函數調用的局部變數,並將這些局部變數用作私有狀態,故我們可以利用閉包的特性來重寫uniqueInteger函數。

//利用閉包重寫。
var uniqueInteger = (function () { //定義函數並立即調用
    var counter = 0; //函數的私有狀態
    return function () {
        return counter += 1;
    };
})();
//調用。
uniqueInteger(); //=>1
uniqueInteger(); //=>2
uniqueInteger(); //=>3

當外部函數返回後,其他任何代碼都無法訪問counter變數,只有內部的函數才能訪問。根據輸出結果可以看出,閉包會使得函數中的變數都被保存在記憶體中,記憶體消耗大,所以要合理使用閉包。

counter一樣的私有變數在多個嵌套函數中都可以訪問到它,因為這多個嵌套函數都共用同一個作用域鏈,看下麵一段代碼:

function counter() {
    var n = 0;
    return {
        count: function () { return n += 1; },
        reset: function () { n = 0; }
    };
}
var c = counter(), d = counter(); //創建兩個計時器
c.count(); //=>0
d.count(); //=>0 能看出它們互不幹擾
c.reset(); //reset和count方法共用狀態
c.count(); //=>0 因為重置了計數器c
d.count(); //=>1 而沒有重置計數器d

書寫閉包的時候還需註意一件事,this是JavaScript的關鍵字,而不是變數。因為閉包內的函數只能訪問閉包內的變數,所以this必須要賦給that才能引用。綁定arguments的問題與之類似。

var name = "The Window";
var object = {
    name: "My Object",
    getName: function () {
        var that = this;
        return function () {
            return that.name;
        };
    }
};
console.log(object.getName()()); //=>"My Object"

到這裡如果你還不明白我在說什麼,這裡推薦兩篇前輩們寫的關於“閉包”的文章。
阮一峰,學習Javascript閉包(Closure)
russj,JavaScript 閉包的理解

7.函數屬性、方法和構造函數

前文已經介紹過,在JavaScript中函數也是對象,它也可以像普通對象一樣擁有屬性和方法。

length屬性
在函數體里,arguments.length表示傳入函數的實參的個數。而函數本身的length屬性表示的則是“形參”,也就是在函數調用時期望傳入函數的實參個數。

function check(args) {
    var actual = args.length; //參數的真實個數
    var expected = args.callee.length; //期望的實參個數
    if (actual!=expected) { //如果不同則拋出異常
        throw Error("Expected "+ expected+"args;got "+ actual);
    }
}
function f(x,y,z) {
    check(arguments); //檢查實參和形參個數是否一致。
    return x + y + z; 
}

prototype屬性
每個函數都包含prototype屬性,這個屬性指向一個對象的引用,這個對象也就是原型對象。當將函數用作構造函數的時候,新創建的對象會從原型對象上繼承屬性。

call()方法和apply()方法
上文提到,這兩個方法可以用來間接調用函數。call()apply()的第一個實參表示要調用函數的母對象,它是調用上下文,在函數內通過this來引用母對象。假如要想把函數func()以對象obj方法的形式來調用,可以這樣:

func.call(obj);
func.apply(obj);

call()apply()的區別之處是,第一個實參(調用上下文)之後的所有實參傳入的方式不同。

func.call(obj, 1, 2); //實參可以為任意數量
func.apply(obj, [1, 2]); //實參都放在了一個數組中

下麵看一個有意思的函數,他能將一個對象的方法替換為一個新方法。這個新方法“包裹”了原始方法,實現了AOP。

//調用原始方法之前和之後記錄日誌消息
function trace(o, m) {
    var original = o[m]; //在閉包中保存原始方法
    o[m] = function () { //定義新方法
        console.log(new Date(), "Entering:", m); //輸出日誌消息
        var result = original.apply(o, arguments); //調用原始方法
        console.log(new Date(), "Exiting:", m); //輸出日誌消息
        return result; //返回結果
    }
}

這種動態修改已有方法的做法,也被稱作“猴子補丁(monkey-patching)”。

bind()方法
bind()方法是ES5中新增的方法,這個方法的主要作用是將函數綁定至某個對象。該方法會返回一個新的函數,調用這個新的函數會將原始函數當作傳入對象的方法來調用。

function func(y) { return this.x + y; } //待綁定的函數
var o = { x: 1 }; //將要綁定的對象
var f = func.bind(o);//通過調用f()來調用o.func()
f(2); //=>3

ES3中可以通過下麵的代碼來實現bind()方法:

if (!Function.prototype.bind) {
    Function.prototype.bind = function (o /* , args */) {
        //將this和arguments保存在變數中,以便在嵌套函數中使用。
        var self = this, boundArgs = arguments;
        //bind()方法返回的是一個函數。
        return function () {
            //創建一個參數列表,將傳入bind()的第二個及後續的實參都傳入這個函數。
            var args = [], i;
            for (var i = 1; i < boundArgs.length; i++) {
                args.push(boundArgs[i]);
            }
            for (var i = 0; i < arguments.length; i++) {
                args.push(boundArgs[i]);
            }
            //現在將self作為o的方法來調用,傳入這些實參。
            return self.apply(o,args);
        }
    }
}

Function()構造函數
定義函數時需要使用function關鍵字,但是函數還可以通過Function()構造函數來定義。Function()構造函數可以傳入任意數量字元串實參,最後一個實參字元串表示函數體,每兩條語句之間也需要用分號分隔。

var f = Function("x", "y", "return x*y;");
//等價於下麵的函數
var f = function f(x, y) { return x * y; }

關於Function()構造函數需要註意以下幾點:

  • Function()構造函數允許Javascript在運行時動態創建並編譯函數;
  • 每次調用Function()構造函數都會解析函數體並創建新的函數。如果將其放在迴圈代碼塊中執行,執行效率會受到影響;
  • 最重要的一點,它所創建的函數並不是使用詞法作用域,相反,函數體代碼的編譯總是會在頂層函數執行。比如下麵代碼所示:

    var scope = "global scope"; 
    function checkscope() {
    var scope = "local scope"; 
    return Function("return scope;"); //無法捕獲局部作用域
    }
    checkscope(); //=>"global scope"

    Function()構造函數可以看作是在全局作用域中執行的eval(),在實際開發中很少見到。

8.函數式編程

JavaScript中可以像操控對象一樣操控函數,也就是說可以在JavaScript中應用函數式編程技術。

使用函數處理數組
假設有一個數組,數組元素都是數字,我們想要計算這些元素的平均值和標準差。可以利用map()reduce()等數組方法來實現,符合函數式編程風格。

//首先定義兩個簡單的函數。
var sum = function (x, y) { return x + y; }
var square = function (x) { return x * x }
//將上面的函數和數組方法配合使用計算出平均數和標準差。
var data = [1, 1, 3, 5, 5];
var mean = data.reduce(sum) / data.length;
var deviations = data.map(function (x) { return x - mean; });
var stddev = Math.sqrt(deviations.map(square).reduce(sum) / (data.length - 1));

高階函數
所謂高階函數就是函數操作函數,它接收一個或多個函數作為參數,並返回一個新的函數。

//返回傳入函數func返回值的邏輯非。
function not(func) {
    return function () {
        var result = func.apply(this, arguments);
        return !result;
    };
}
//判斷傳入參數a是否為偶數。
var even = function (x) {
    return x % 2 === 0;
}
var odd = not(even); //odd為新的函數,所做的事和even()相反。
[1, 1, 3, 5, 5].every(odd); //=>true 每個元素都是奇數。

這裡是一個更常見的例子,它接收兩個函數f()g(),並返回一個新的函數用以計算f(g())

//返回一個新的函數,計算f(g(...))。
function compose(f, g) {
    return function () {
        //需要給f()傳入一個參數,所以使用f()的call()方法。
        //需要給g()傳入很多參數,所以使用g()的apply()方法。
        return f.call(this, g.apply(this, arguments));
    }
}

var square = function (x) { return x * x; }
var sum = function (x, y) { return x + y; }
var squareofsum = compose(square, sum);
squareofsum(2, 3); //=>25

記憶
能將上次計算的結果緩存起來,在函數式編程當中,這種緩存技巧叫做“記憶”。下麵的代碼展示了一個高階函數,memorize()接收一個函數作為實參,並返回帶有記憶能力的函數。

//返回f()的帶有記憶功能的版本。
function memorize(f) {
    //將值保存在閉包中。
    var cache = {};
    return function () {
        //將實參轉換為字元串形式,並將其用做緩存的鍵。
        var key = arguments.length + Array.prototype.join.call(arguments, ",");
        if (key in cache) {
            return cache[key];
        } else {
            return cache[key] = f.apply(this, arguments);
        }
    }
}

memorize()所返回的函數將它的實參數組轉換成字元串,並將字元串用做緩存對象的屬性名。如果緩存中存在這個值,則直接返回它,否則調用既定的函數對實參進行計算,將計算結果緩存起來並保存。下麵代碼展示瞭如何使用memorize()

//返回兩個整數的最大公約數。
function gcd(a, b) {
    var temp;
    if (a < b) { //確保 a >= b
        temp = b;
        b = a;
        a = temp;
    }
    while (b != 0) { //這裡是求最大公約數的歐幾里德演算法
        temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}
var gcdmemo = memorize(gcd);
gcdmemo(85, 187);

//當寫一個遞歸函數時,往往需要實現記憶功能。
var factorial = memorize(function (n) {
    return (n <= 1) ? 1 : n * factorial(n - 1);
});
factorial(5); //=>120

9.參考與擴展

本篇內容源自我對《JavaScript權威指南》第8章 函數 章節的閱讀總結和代碼實踐。總結的比較粗糙,你也可通過原著或MDN更深入瞭解函數。

[1] David Flanagan,JavaScript權威指南(第6版)
[2] MDN,JavaScript 參考文檔 - Functions - JavaScript | MDN

作者:gao-yang

出處:http://www.cnblogs.com/gao-yang/p/6256157.html

本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。




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

-Advertisement-
Play Games
更多相關文章
  • 這是在fcc上的中級演算法中的第一題,拉出來的原因並不是因為有什麼好說的,而是我剛看時以為是求兩個數字的和, 很顯然錯了。我感覺自己的文字理解能力被嚴重鄙視了- -。故拉出來折騰折騰。 要求: 給你一個包含兩個數字的數組。返回這兩個數字和它們之間所有數字的和。 最小的數字並非總在最前面。 思路:在正確 ...
  • 動畫分為: 1.css3動畫:(動畫性能遠高於js) 1).過渡動畫(transition) 2).關鍵幀動畫(@keyframes,animation) 2.js動畫: 過渡動畫(transition) 語法: (所有時長單位都是秒) 1.變化屬性(transition-property(屬性名) ...
  • 本文將介紹一款基於jquery的二維碼生成插件qrcode,在頁面中調用該插件就能生成對應的二維碼。 1、首先在頁面中加入jquery庫文件和qrcode插件。 2、在頁面佈局中添加一個div 3、調用qrcode插件。 4、我們試驗的時候發現不能識別中文內容的二維碼,通過查找多方資料瞭解到,jqu ...
  • html css 第一種方法:.box{clear:box} 第二種方法:.box{overflow:hidden} 第三種方法:.box{overflow:auto} 第四種方法:.box:after{ content:""; height:0; visibility:hidden; displa ...
  • 一、Node.js本質上是js的運行環境。 二、可以解析js代碼(沒有瀏覽器安全級的限制); 提供系統級的API:1、文件的讀寫 2、進程的管理 3、網路通信 三、可以關註的四個網站: 1、https://nodejs.org/en/(官網) 2、https://www.npmjs.com/ 3、h ...
  • 1、背景圖片中部放大、縮小 ...
  • border-image-source 屬性設置邊框的圖片的路徑[none | <image>] border-image-slice 屬性圖片邊框向內偏移[ <number> | <percentage> ](1,4) ?fill border-image-width 屬性設置圖片邊框的寬度[ < ...
  • border-radius 屬性設置邊框的園角 可能的值:像素,百分比 擴展延伸 html代碼 css代碼 結果 css代碼 結果 css代碼 結果 css代碼 結果 css代碼 結果 css代碼 結果 css代碼 結果 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...