[筆記]你不知道的JavaScript(上)

来源:https://www.cnblogs.com/moqiutao/archive/2020/05/23/10550507.html
-Advertisement-
Play Games

前言 文章只記錄理解以及容易遺忘的知識點。 詞法作用域、塊作用域 詞法作用域 詞法作用域:簡單的說,詞法作用域就是定義在詞法階段的作用域。換句話說,詞法作用域就是在你寫代碼時將變數和塊作用域寫在哪裡來決定的,因此在詞法分析器處理代碼時會保持作用域不變(大部分情況是這樣的)。 當然有一些欺騙詞法作用域 ...


前言

文章只記錄理解以及容易遺忘的知識點。

詞法作用域、塊作用域

詞法作用域

詞法作用域:簡單的說,詞法作用域就是定義在詞法階段的作用域。換句話說,詞法作用域就是在你寫代碼時將變數和塊作用域寫在哪裡來決定的,因此在詞法分析器處理代碼時會保持作用域不變(大部分情況是這樣的)。

當然有一些欺騙詞法作用域的方法,這些方法在詞法分析器處理後依然可以改變作用域。

欺騙詞法作用域的方法有:

  • eval():可以接受一個字元串作為參數。
  • with:通常被當作重覆引用同一個對象中的多個屬性的快捷方式,可以不需要重覆引用對象本身。
var obj = {
    a:1,
    b:2,
    c:3
};

//單調乏味的重覆"obj"
obj.a=2;
obj.b=3;
obj.c=4;

//簡單的快捷方式
with(obj){
    a=2;
    b=3;
    c=4;
}

塊作用域

  • with
  • try/catch
  • let
  • const

簡單解釋下箭頭函數:簡單來說,箭頭函數在涉及this綁定時的行為和普通函數的行為完全不一致。它放棄了所有普通this綁定規則,取而代之的是用當前的詞法作用域覆蓋了this本來的值。

作用域閉包

現代的模塊機制

大多數模塊依賴載入器/管理器本質上都是將這種模塊定義封裝進一個友好的API。這裡並不會研究某個具體的庫,為了巨集觀瞭解簡單介紹一些核心概念:

var MyModules = (function Manager(){
    var modules = {};
    function define(name,deps,impl){
        for(var i = 0; i < deps.length; i++){
            deps[i] = modules[deps[i]];
        }
        modules[name] = impl.apply(impl,deps);
    }
    
    function get(name){
        return modules[name];
    }
    return {
        define:define,
        get:get
    }
})();

這段代碼的核心是modules[name] = impl.apply(impl,deps)。為了模塊的定義引入了包裝函數(可以傳入任何依賴),並且將返回值,也就是模塊的API,存儲在一個根據名字來管理的模塊列表中。

下麵用它來如何定義模塊:

MyModules.define("bar",[],function(){
    function hello(who){
        return "Let me introduce:" + who;
    }
    return {
        hello:hello
    }
});

MyModules.define("foo",['bar'],function(bar){
    var hungry = "hippo";
    function awesome(){
        console.log(bar.hello(hungry).toUpperCase());
    }
    return {
        awesome:awesome
    }
});

var bar = MyModules.get("bar");
var foo = MyModules.get("foo");

console.log(bar.hello("hippo")); //Let me introduce:hippo
foo.awesome();  //LET ME INTRODUCE:HIPPO

 “foo”和“bar”模塊都是通過一個返回公共API的函數來定義的。“foo”甚至接受“bar”的示例作為依賴參數,並能相應地使用它。

未來的模塊機制

bar.js
function hello(who){
    return "Let me introduce:" + who;
}
export hello;

foo.js
//僅從"bar"模塊導入hello()
import hello from "bar";
var hungry = "hippo";
function awesome(){
    console.log(hello(hungry).toUpperCase());
}
export awesome;

baz.js
//導入完整的"foo"和"bar"模塊
module foo from "foo";
module bar from "bar";
console.log(bar.hello("hippo")); //Let me introduce:hippo
foo.awesome();  //LET ME INTRODUCE:HIPPO

 import可以將一個模塊中的一個或多個API導入到當前作用域中,並分別綁定在一個變數上(在我們的例子里是hello)。module會將整個模塊的API導入並綁定到一個變數上(在我們的例子里是foo和bar).export會將當前模塊的一個標識符(變數、函數)導出為公共API。這些操作可以在模塊定義中根據需要使用任意多次。

動態作用域

function foo(){
    console.log(a); //2
}
function bar(){
    var a = 3;
    foo();
}
var a = 2;
bar(); 

如果JS具有動態作用域,那麼列印的值就是3,而不是2了。需要明確的是,事實上JS並不具有動態作用域。它只有詞法作用域,簡單明瞭。但是this機制某種程度上很像動態作用域。

主要區別:詞法作用域是在寫代碼或者說定義時確定的,而動態作用域是在運行時確定的。(this也是!)詞法作用域關註函數在何處聲明,而動態作用域關註函數從何處調用。最後,this關註函數如何調用,這就表明瞭this機制和動態作用域之間的關係那麼緊密。

this解析

JS有許多的內置函數,都提供了一個可選的參數,通常被成為“上下文”(context),其作用和bind(...)一樣,確保你的回調函數使用指定的this。如下例子:

function foo(el){
    console.log(el,this.id);
}

var obj = {
    id:"awesome"
};

//調用foo(...)時把this綁定到obj
[1,2,3].forEach(foo,obj); //結果:1 "awesome" 2 "awesome"  3 "awesome"

 bind()

bind()方法創建一個新的函數,在調用時設置this關鍵字為提供的值。併在調用新函數時,將給定參數列表作為原函數的參數序列的前若幹項。

語法:function.bind(thisArg[, arg1[, arg2[, ...]]])

簡單例子:

var module = {
  x: 42,
  getX: function() {
    return this.x;
  }
}

var unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined

var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42

你可以將下麵這段代碼插入到你的腳本開頭,從而使你的 bind() 在沒有內置實現支持的環境中也可以部分地使用bind。

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          // this instanceof fBound === true時,說明返回的fBound被當做new的構造函數調用
          return fToBind.apply(this instanceof fBound
                 ? this
                 : oThis,
                 // 獲取調用時(fBound)的傳參.bind 返回的函數入參往往是這麼傳遞的
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    // 維護原型關係
    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    // 下行的代碼使fBound.prototype是fNOP的實例,因此
    // 返回的fBound若作為new的構造函數,new生成的新對象作為this傳入fBound,新對象的__proto__就是fNOP的實例
    fBound.prototype = new fNOP();

    return fBound;
  };
}

 詳細參考地址:《MDN:Function.prototype.bind()》

對象

對象鍵只能是字元串

symbol 出現之前,對象鍵只能是字元串,如果試圖使用非字元串值作為對象的鍵,那麼該值將被強制轉換為字元串,如下:

const obj = {};
obj.foo = 'foo';
obj['bar'] = 'bar';
obj[2] = 2;
obj[{}] = 'someobj';
console.log(obj);

結果:

2:2
[object Object]:"someobj"
bar:"bar"
foo:"foo"

屬性描述符

從ES5開始,所有的屬性都具備了屬性描述符。

思考如下代碼,使用Object.getOwnPropertyDescriptor()

var myObject = {
    a:2
};
var result = Object.getOwnPropertyDescriptor(myObject,"a");
console.log(result);

得到的結果如下:

{
    configurable:true,
    enumerable:true,
    value:2,
    writable:true
}

這個普通的對象屬性對應的屬性描述符除了有value值為2,還有另外三個特性:writable(可寫)enumerable(可枚舉)configurable(可配置)

使用Object.defineProperty()來添加一個新屬性或者修改一個已有屬性(如果它是configurable)並對特性進行設置。

writable

如下代碼:

var myObject = {}
Object.defineProperty(myObject,"a",{
    value:2,
    writable:false, //不可寫
    configurable:true,
    enumerable:true
});
myObject.a = 3;
console.log(myObject.a); //2

如果在嚴格模式下,上面這寫法報錯:

"use strict";
var myObject = {}
Object.defineProperty(myObject,"a",{
    value:2,
    writable:false, //不可寫
    configurable:true,
    enumerable:true
});
myObject.a = 3; //Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>'

configurable

var myObject = {}
Object.defineProperty(myObject,"a",{
    value:2,
    writable:true, 
    configurable:false, //不可配置
    enumerable:true
});
myObject.a = 5;
console.log(myObject.a); //5
delete myObject.a;
console.log(myObject.a); //configurable:false,禁止刪除這個屬性

Object.defineProperty(myObject,"a",{
    value:6,
    writable:true, 
    configurable:true, 
    enumerable:true
}); //TypeError: Cannot redefine property: a

上面代碼可以看出,設置configurable為false是單向操作,無法撤銷。同時還會禁止刪除這個屬性。

註意:要註意一個小小的例外,即使屬性configurable:false,我們還是可以把writable的狀態有true改為false,但是無法由false改為true。

enumerable

從名字可以看出來,這個描述符控制的是屬性是否出現在對象的屬性枚舉中,比如for...in迴圈。

不變性

有時候我們希望屬性或者對象是不可改變的。ES5中有很多方法可以實現。

對象常量

結合writable:false和configurable:false就可以真正的創建一個常量屬性(不可修改、重定義或者刪除)。

var myObject = {}
Object.defineProperty(myObject,"a",{
    value:2,
    writable:false, 
    configurable:false
});

禁止擴展Object.preventExtensions()

如果你想禁止一個對象添加新的屬性並且保留已有屬性,可以使用Object.preventExtensions()

var myObject = {
    a:2
};
Object.preventExtensions(myObject);
myObject.b = 3;
console.log(myObject.b); //undefined

在嚴格模式下,將會拋出TypeError錯誤。

密封Object.seal()

Object.seal()會創建一個“密封”的對象,這個方法實際上會在現有對象上調用Object.preventExtensions()並把所有現有屬性標記為configurable:false。

所以,密封之後不僅不能添加新的屬性,也不能重新配置或者刪除任何屬性(雖然可以修改屬性的值)。

凍結Object.freeze()

Object.freeze()會創建一個凍結對象,這個方法實際上會在一個現有對象上調用Object.seal()並把所有“數據訪問”屬性標記為writable:false,這樣就無法修改它們的值。

這個方法是你可以應用在對象上的級別最高的不可變性,它會禁止對於對象本身及其任意直接屬性的修改(這個對象引用的其它對象是不受影響的)。

你可以“深度凍結”一個對象,具體方法為,首先在這個對象上調用Object.freeze(),然後遍歷它所有引用的所有對象併在這些對象上調用Object.freeze()。但你一定要小心,因為這樣做,你可能會在無意中凍結其它(共用)對象。

Getter和Setter

對象預設的[[Put]]和[[Get]]操作分別可以控制屬性值的設置和獲取。

當你給一個屬性定義getter、setter或者兩者都有時,這個屬性會被定義為“訪問描述符”(和“數據描述符”相對的)。對於訪問描述符來說,JS會忽略它們的value和writable特性,取而代之的是關心set和get(還有configurable和enumerable)特性。

思考如下代碼:

var myObject = {
    get a(){
        return 2;
    }
};

Object.defineProperty(myObject,"b",{
    get:function(){
        return this.a * 2;
    },
    enmuerable:true
})
console.log(myObject.a); //2
console.log(myObject.b); //4

為了讓屬性更合理,還應該定義setter,setter會覆蓋單個屬性預設的[[Put]](也被稱為賦值)操作。通常來說getter和setter是成對出現的。

var myObject = {
    get a(){
        return this._a_;
    },
    set a(val){
        this._a_ = val * 2;
    }
};
myObject.a = 2;
console.log(myObject.a); //4

遍歷

for...in迴圈可以用來遍歷對象的可枚舉屬性列表(包括[[Prototype]]鏈)。

ES5增加了一些數組的輔助迭代器,包括forEach()、every()和some()。每種迭代器都可以接受一個回調函數並把它應用到數組的每個元素上,唯一的區別就是它們對於回調函數返回值的處理方式不同。

  • forEach():會遍曆數組中的所有值並忽略回調函數的返回值。
  • every():會一直運行直到回調函數返回false(或者“假”值)。
  • some():會一直運行直到回調函數返回true(或者“真”值)。

註:every()和some()中特殊的返回值和普通for迴圈中的break語句相似,他們會提前終止遍歷。

使用for...in遍歷對象是無法直接獲得屬性值的 ,它只是遍歷了對象中所有可以枚舉的屬性,你需要手動獲取屬性值。

ES6增加了一種用來遍曆數組的for...of迴圈語法(如果對象本身定義了迭代器的話也可以遍歷對象):

var myArray = [1,2,3];
for(var v of myArray){
    console.log(v); //1 2 3
};

for...of迴圈首先會向被訪問對象請求一個迭代器對象,然後通過調用迭代器對象的next()方法來遍歷所有返回值。

數組有內置的@@iterator,因此for...of可以直接應用在數組上。我們使用內置的@@iterator來手動遍曆數組,看看它是怎麼工作的:

var myArray = [1,2,3];
var it = myArray[Symbol.iterator]();
var next1 = it.next();
var next2 = it.next();
var next3 = it.next();
var next4 = it.next();
console.log(next1); //{value: 1, done: false}
console.log(next2); //{value: 2, done: false}
console.log(next3); //{value: 3, done: false}
console.log(next4); //{value: undefined, done: true}

註:我們使用ES6中的符號Symbol.iterator來獲取對象的@@iterator內部屬性。@@iterator本身並不是一個迭代器對象,而是一個返回迭代器對象的函數--這一點非常精妙並且非常重要。

普通的對象並沒有內置的@@iterator,所以無法自動完成for...of遍歷。當然,你也可以給任何想遍歷的對象定義@@iterator,如下代碼:

var myObject = {
    a:2,
    b:3
};
Object.defineProperty(myObject,Symbol.iterator,{
    enumerable:false,
    writable:false,
    configurable:true,
    value:function(){
        var o = this,
            idx = 0,
            ks = Object.keys(o);
        return {
            next:function(){
                return {
                    value:o[ks[idx++]],
                    done:(idx > ks.length)
                }
            }
        }
    }
});

//手動遍歷myObject
var it = myObject[Symbol.iterator]();
var next1 = it.next();
var next2 = it.next();
var next3 = it.next();
console.log(next1); //{value: 2, done: false}
console.log(next2); //{value: 3, done: false}
console.log(next3); //{value: undefined, done: true}

//用for...of遍歷myObject
for(var v of myObject){
    console.log(v);
}
//2
//3

註:我們使用Object.defineProperty()定義了我們自己的@@iterator(主要是為了讓它不可枚舉),不過註意,我們把符號當做可計算屬性名。此外,也可以直接在定義對象時進行聲明,比如:

var myObject = {
    a:2,
    b:3,
    [Symbol.iterator]:function(){
        /*..*/
    }
};

對於用戶定義的對象來說,結合for...of和用戶自定義的迭代器可以組成非常強大的對象操作工具。

再看一個例子,寫一個迭代器生成“無限個”隨機數,我們添加一條break語句,防止程式被掛起,代碼如下:

var randoms = {
    [Symbol.iterator]:function(){
        return {
            next:function(){
                return {
                    value:Math.random()
                }
            }
        }
    }
};

var random_pool = [];
for(var n of randoms){
    random_pool.push(n);
    console.log(n);
    //防止無限運行
    if(random_pool.length === 10) break;
}

 constructor 屬性

語法:object.constructor

返回值:對象的constructor屬性返回創建該對象的函數的引用。

// 字元串:String()
var str = "張三";
alert(str.constructor); // function String() { [native code] }
alert(str.constructor === String); // true
 
// 數組:Array()
var arr = [1, 2, 3];
alert(arr.constructor); // function Array() { [native code] }
alert(arr.constructor === Array); // true
 
// 數字:Number()
var num = 5;
alert(num.constructor); // function Number() { [native code] }
alert(num.constructor === Number); // true
 
// 自定義對象:Person()
function Person(){
    this.name = "CodePlayer";
}
var p = new Person();
alert(p.constructor); // function Person(){ this.name = "CodePlayer"; }
alert(p.constructor === Person); // true
 
// JSON對象:Object()
var o = { "name" : "張三"};
alert(o.constructor); // function Object() { [native code] }
alert(o.constructor === Object); // true
 
// 自定義函數:Function()
function foo(){
    alert("CodePlayer");
}
alert(foo.constructor); // function Function() { [native code] }
alert(foo.constructor === Function); // true
 
// 函數的原型:bar()
function bar(){
    alert("CodePlayer");
}
alert(bar.prototype.constructor); // function bar(){ alert("CodePlayer"); }
alert(bar.prototype.constructor === bar); // true

原型

對象關聯

使用Object.create()可以完美的創建我們想要的關聯關係。

var foo = {
    something:function(){
        console.log("tell me something");
    }
};

var bar = Object.create(foo);
bar.something(); //tell me something

Object.create()的polyfill代碼,由於Object.create()是在ES5中新增的函數,所以在舊版瀏覽器中不支持,使用下麵這段代碼相容:

if(!Object.create){
    Object.create = function(o){
        function F(){};
        F.prototype = o;
        return new F();
    }
}

標準ES5中內置的Object.create()函數還提供了一系列的附加功能。如下代碼:

var anotherObject= {
    a:2
};
var myObject = Object.create(anotherObject,{
    b:{
        enumerable:false,
        writable:true,
        configurable:false,
        value:3
    },
    c:{
        enumerable:true,
        writable:false,
        configurable:false,
        value:4
    }
});
console.log(myObject.hasOwnProperty('a')); //false
console.log(myObject.hasOwnProperty('b')); //true
console.log(myObject.hasOwnProperty('c')); //true

console.log(myObject.a); //2
console.log(myObject.b); //3
console.log(myObject.c); //4

Object.create(..)第二個參數指定了需要添加到新對象中的屬性名以及這些屬性的屬性描述符。

關聯關係是備用

下麵代碼可以讓你的API設計不那麼“神奇”,同時仍然能發揮[[Prototype]]關聯的威力:

var anotherObject= {
    cool:function(){
        console.log('cool!');
    }
};
var myObject = Object.create(anotherObject);
myObject.deCool = function(){
    this.cool();
}
myObject.deCool();

 行為委托

面向委托的設計:比較思維模型

下麵比較下這兩種設計模式(面向對象和對象關聯)具體的實現方法。下麵典型的(“原型”)面向對象風格:

function Foo(who){
    this.me = who;
}
Foo.prototype.identify = function(){
    return "I am " + this.me;
}

function Bar(who){
    Foo.call(this,who);
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.speak = function(){
    console.log("hello, " + this.identify() + ".");
}
var b1 = new Bar("b1");
var b2 = new Bar("b2");

b1.speak(); //hello, I am b1.
b2.speak(); //hello, I am b2.

子類Bar繼承了父類Foo,然後生成了b1和b2兩個實例,b1委托了Bar.prototype,後者委托了Foo.prototype。這種風格很常見。

對象關聯風格實現相同的功能:

var Foo = {
    init:function(who){
        this.me = who;
    },
    identify:function(){
        return "I am " + this.me;
    }
};

var Bar = Object.create(Foo);

Bar.speak = function(){
    console.log("hello, " + this.identify() + ".");
}

var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2");

b1.speak(); //hello, I am b1.
b2.speak(); //hello, I am b2.

這段代碼同樣利用[[Prototype]]把b1委托給Bar並把Bar委托給Foo,和上一段代碼一模一樣。我們仍然實現了三個對象直接的關聯。

類與對象

web開發一種典型的前端場景:創建UI控制項(按鈕,下拉列表等等)。

控制項“類”

下麵代碼是在不使用任何“類”輔助庫或者語法的情況下,使用純JavaScript實現類風格的代碼:

//父類
function Widget(width,height){
    this.width = width || 50;
    this.height = height || 50;
    this.$elem = null;
};
Widget.prototype.render = function($where){
    if(this.$elem){
        this.$elem.css({
            width:this.width + "px",
            height:this.height + "px"
        }).appendTo($where);
    }
};

//子類
function Button(width,height,label){
    //調用"super"構造函數
    Widget.call(this,width,height);
    this.label = label || "Default";
    this.$elem = $("<button>").text(this.label);
}

//讓子類“繼承”Widget
Button.prototype = Object.create(Widget.prototype);

//重寫render()
Button.prototype.render = function($where){
    Widget.prototype.render.call(this,$where);
    this.$elem.click(this.onClick.bind(this));
}
Button.prototype.onClick = function(evt){
    console.log("Button '"+this.label+"'clicked! ");
};

$(document).ready(function(){
    var $body = $(document.body);
    var btn1 = new Button(125,30,"Hello");
    var btn2 = new Button(150,40,"World");
    btn1.render($body);
    btn2.render($body);
});

ES6的class語法糖

class Widget {
    constructor(width,height) {
        this.width = width || 50;
        this.height = height || 50;
        this.$elem = null;
    }
    render($where){
        if(this.$elem){
            this.$elem.css({
                width:this.width + "px",
                height:this.height + "px"
            }).appendTo($where);
        }
    }
}

class Button extends Widget {
    constructor(width,height,label){
        super(width,height);
        this.label = label || "Default";
        this.$elem = $("<button>").text(this.label);
    }
    render($where){
        super($where);
        this.$elem.click(this.onClick.bind(this));
    }
    onClick(evt){
        console.log("Button '"+this.label+"'clicked! ");
    }
}

$(document).ready(function(){
    var $body = $(document.body);
    var btn1 = new Button(125,30,"Hello");
    var btn2 = new Button(150,40,"World");
    btn1.render($body);
    btn2.render($body);
});

委托控制項對象

下麵例子使用對象關聯風格委托來更簡單地實現Wiget/Button:

var Widget = {
    init:function(width,height){
        this.width = width || 50;
        this.height = height || 50;
        this.$elem = null;
    },
    insert:function($where){
        if(this.$elem){
            this.$elems.css({
                width:this.width + "px",
                height:this.height + "px"
            }).appendTo($where);
        }
    }
}

var Button = Object.create(Widget);
Button.setup = function(width,height,label){
    //委托調用
    this.init(width,height);
    this.label = label || "Default";
    this.$elem = $("<button>").text(this.label);
}
Button.build = function($where){
    //委托調用
    this.insert($where);
    this.$elem.click(this.onClick.bind(this));
}
Button.onClick = function(evt){
    console.log("Button '"+this.label+"'clicked! ");
}

$(document).ready(function(){
    var $body = $(document.body);
    
    var btn1 = Object.create(Button);
    btn1.setup(125,30,"Hello");
    
    var btn2 = Object.create(Button);
    btn2.setup(150,40,"World");
    
    btn1.build($body);
    btn2.build($body);
})

對象關聯可以更好的支持關註分離(separation of concerns)原則,創建和初始化並不需要合併成一個步驟。

 


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

-Advertisement-
Play Games
更多相關文章
  • 在前後端數據交互的過程中,為了能夠減少ajax請求次數,減輕帶寬壓力,後端往往會將當前介面所需的參數以對象的形式集體返回。這樣就導致一個問題:對象內欄位屬性過多,而有些小組件功能又壓根不需要這麼一個大對象參數(主要是對象屬性過多,難得理,也懶得找),這時就需要對這個大對象做再加工處理。 比如:將小組 ...
  • h5+ 開發微信、QQ分享功能 此處只做微信網頁分享示例代碼 方式一、JS+HTML+h5Plus 1.html代碼 <div class="button" onclick="shareWeb()">分享網頁</div> 2.JS代碼 // H5 plus事件處理function plusReady ...
  • 今天終於把樸靈老師寫的《深入淺出Node.js》給學習完了, 這本書不是一本簡單的Node入門書籍,它沒有停留在Node介紹或者框架、庫的使用層面上,而是從不同的視角來揭示Node自己內在的特點和結構。建議有一定Node基礎或者做過Node方面的小項目的同學閱讀,看完以後你的思維會有很奇特的碰撞,我 ...
  • 現在這個社會是信息爆炸的社會,各個網站、app上鋪天蓋地的都是各種新聞和信息。 為了獲取信息,我們每天都要進行各種麻煩的操作,打開各種網站或者手機app,操作顯得低效,後來發現了一個神器,那就是RSS。 什麼是RSS RSS中文名是簡易信息聚合,就是讓網站一個按照一定周期更新網站的文章概要內容(有些 ...
  • 今天小編要跟大家分享的文章是關於想要學習web前端需要掌握哪些技能和工具?互聯網的快速發展和激烈競爭,使得用戶體驗成為一個重要的關註點,導致專業前端工程師成為熱門職業,各大公司對前端工程師的需求量都很大,要求也越來越高,優秀的前端工程師更是稀缺。因此想要學習前端技術的人越來越多,那麼零基礎學習web ...
  • 前端開發因為其上手快,開發難度適中,而應用非常廣泛,成為目前大部分想進入IT行業的年輕人的首選。目前前端開發崗位人員主要分類三類:高校畢業生,培訓生,自學人士三大類。今天主要和大家一起來探討一下,自學前端需要掌握哪些知識點。 ...
  • Ajax 非同步 JavaScript 和 XML 第一步: 創建 XMLHttpRequest 對象,var 對象名 = new XMLHttpRequest(); Xmlhttprequest 對象用來和伺服器交換數據 第二步: XMLHttpRequest 對象的 open()和 send()方 ...
  • JavaScript箭頭函數 語法 基礎語法 高級語法 描述 引入箭頭函數有兩個方面的作用:更簡短的函數並且不綁定 this 。 更短的函數 不綁定 this 在箭頭函數出現之前,每個新定義的函數都有它自己的 this 值(在構造函數的情況下是一個新對象,在嚴格模式的函數調用中為underfined ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...