ES6中的Symbol類型

来源:http://www.cnblogs.com/xiaohuochai/archive/2017/07/28/7245510.html
-Advertisement-
Play Games

[1]創建 [2]使用 [3]共用體系 [4]類型轉換 [5]屬性檢索 [6]內置Symbol ...


前面的話

  ES5中包含5種原始類型:字元串數字布爾值nullundefined。ES6引入了第6種原始類型——Symbol

  ES5的對象屬性名都是字元串,很容易造成屬性名衝突。比如,使用了一個他人提供的對象,想為這個對象添加新的方法,新方法的名字就有可能與現有方法產生衝突。如果有一種機制,保證每個屬性的名字都是獨一無二的,這樣就從根本上防止了屬性名衝突。這就是ES6引入Symbol的原因,本文將詳細介紹ES6中的Symbol類型

 

創建

  Symbol 值通過Symbol函數生成。這就是說,對象的屬性名可以有兩種類型:一種是字元串,另一種是Symbol類型。凡是屬性名屬於 Symbol 類型,就都是獨一無二的,可以保證不會與其他屬性名產生衝突

let firstName = Symbol();
let person = {};
person[firstName] = "huochai";
console.log(person[firstName]); // "huochai"

  [註意]Symbol函數前不能使用new命令,否則會報錯。因為生成的 Symbol 是一個原始類型的值,不是對象

//Uncaught TypeError: Symbol is not a constructor
let firstName = new Symbol();

  Symbol函數接受一個可選參數,可以添加一段文本來描述即將創建的Symbol,這段描述不可用於屬性訪問,但是建議在每次創建Symbol時都添加這樣一段描述,以便於閱讀代碼和調試Symbol程式

let firstName = Symbol("first name");
let person = {};
person[firstName] = "huochai";
console.log("first name" in person); // false
console.log(person[firstName]); // "huochai"
console.log(firstName); // "Symbol(first name)"

  Symbol的描述被存儲在內部[[Description]]屬性中,只有當調用Symbol的toString()方法時才可以讀取這個屬性。在執行console.log()時隱式調用了firstName的toString()方法,所以它的描述會被列印到日誌中,但不能直接在代碼里訪問[[Description]]

【類型檢測】

  Symbol是原始值,ES6擴展了typeof操作符,返回"symbol"。所以可以用typeof來檢測變數是否為symbol類型

let symbol = Symbol("test symbol");
console.log(typeof symbol); // "symbol"

 

使用

  由於每一個Symbol值都是不相等的,這意味著Symbol值可以作為標識符,用於對象的屬性名,就能保證不會出現同名的屬性。這對於一個對象由多個模塊構成的情況非常有用,能防止某一個鍵被不小心改寫或覆蓋

  所有使用可計算屬性名的地方,都可以使用Symbol

let firstName = Symbol("first name");
// 使用一個需計算字面量屬性
let person = {
    [firstName]: "huochai"
};
// 讓該屬性變為只讀
Object.defineProperty(person, firstName, { writable: false });
let lastName = Symbol("last name");
Object.defineProperties(person, {
    [lastName]: {
        value: "match",
        writable: false
    }
});
console.log(person[firstName]); // "huochai"
console.log(person[lastName]); // "match"

  在此示例中,首先通過可計算對象字面量屬性語法為person對象創建了個Symbol屬性firstName。後面一行代碼將這個屬性設置為只讀。隨後,通過Object.defineProperties()方法創建一個只讀的Symbol屬性lastName,此處再次使用了對象字面量屬性,但卻是作為object.defineProperties()方法的第二個參數使用  

  [註意]Symbol 值作為對象屬性名時,不能用點運算符

var mySymbol = Symbol();
var a = {};

a.mySymbol = 'Hello!';
a[mySymbol] // undefined
a['mySymbol'] // "Hello!"

  由上面結果看出,a.mySymbol和a['mySymbol']里的mySymbol是字元串類型的屬性名,a[mySymbol]里的mySymbol才是Symbol類型的屬性名。雖然都叫mySymbol,但值不相同

  儘管在所有使用可計算屬性名的地方,都可以使用Symbol來代替,但是為了在不同代碼片段間有效地共用這些Symbol,需要建立一個體系

 

共用體系

  有時希望在不同的代碼中共用同一個Symbol,例如,在應用中有兩種不同的對象類型,但是希望它們使用同一個Symbol屬性來表示一個獨特的標識符。一般而言,在很大的代碼庫中或跨文件追蹤Symbol非常困難而且容易出錯,出於這些原因,ES6提供了一個可以隨時訪問的全局Symbol註冊表

【Symbol.for()】

  如果想創建一個可共用的Symbol,要使用Symbol.for()方法。它只接受一個參數,也就是即將創建的Symbol的字元串標識符,這個參數同樣也被用作Symbol的描述

let uid = Symbol.for("uid");
let object = {};
object[uid] = "12345";
console.log(object[uid]); // "12345"
console.log(uid); // "Symbol(uid)"

  Symbol.for()方法首先在全局Symbol註冊表中搜索鍵為"uid"的Symbol是否存在。如果存在,直接返回已有的Symbol,否則,創建一個新的Symbol,並使用這個鍵在Symbol全局註冊表中註冊,隨即返回新創建的Symbol

  後續如果再傳入同樣的鍵調用Symbol.for()會返回相同的Symbol

let uid = Symbol.for("uid");
let object = {
    [uid]: "12345"
};
console.log(object[uid]); // "12345"
console.log(uid); // "Symbol(uid)"
let uid2 = Symbol.for("uid");
console.log(uid === uid2); // true
console.log(object[uid2]); // "12345"
console.log(uid2); // "Symbol(uid)

  在這個示例中,uid和uid2包含相同的Symbol並且可以互換使用。第一次調用Symbol.for()方法創建這個Symbol,第二次調用可以直接從Symbol的全局註冊表中檢索到這個Symbol

【Symbol.keyFor()】

  還有一個與Symbol共用有關的特性:可以使用Symbol.keyFor()方法在Symbol全局註冊表中檢索與Symbol有關的鍵

let uid = Symbol.for("uid");
console.log(Symbol.keyFor(uid)); // "uid"
let uid2 = Symbol.for("uid");
console.log(Symbol.keyFor(uid2)); // "uid"
let uid3 = Symbol("uid");
console.log(Symbol.keyFor(uid3)); // undefined

  uid和uid2都返回了"uid"這個鍵,而在Symbol全局註冊表中不存在uid3這個Symbol,也就是不存在與之有關的鍵,所以最終返回undefined

  [註意]Symbol.for為Symbol值登記的名字,是全局環境的,可以在不同的 iframe 或 service worker 中取到同一個值

let iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);

console.log(iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo'));// true

  上面代碼中,iframe 視窗生成的 Symbol 值,可以在主頁面得到

  Symbol全局註冊表是一個類似全局作用域的共用環境,也就是說不能假設目前環境中存在哪些鍵。當使用第三方組件時,儘量使用Symbol鍵的命名空間以減少命名衝突。例如,jQuery的代碼可以為所有鍵添加"jquery"首碼,就像"jquery.element"或其他類似的鍵

 

類型轉換

  類型轉換是JS中的一個重要語言特性,然而其他類型沒有與Symbol邏輯等價的值,因而Symbol使用起來不是很靈活

  使用console.log()方法來輸出Symbol的內容,它會調用Symbol的String()方法並輸出有用的信息。也可以像這樣直接調用string()方法來獲得相同的內容

let uid = Symbol.for("uid"),
    desc = String(uid);
console.log(desc); // "Symbol(uid)"

  String()函數調用了uid.toString()方法,返回字元串類型的Symbol描述里的內容。但是,如果嘗試將Symbol與一個字元串拼接,會導致程式拋出錯誤

let uid = Symbol.for("uid"),
desc = uid + ""; // 引發錯誤!

  將uid與空字元串拼接,首先要將uid強制轉換為一個字元串,而Symbol不可以被轉換為字元串,故程式直接拋出錯誤

  同樣,也不能將Symbol強制轉換為數字類型。將Symbol與每一個數學運算符混合使用都會導致程式拋出錯誤

let uid = Symbol.for("uid"),
sum = uid / 1; // 引發錯誤!

  嘗試將Symbol除1,程式直接拋出錯誤。而且無論使用哪一個數學操作符,都無法正常運行

  [註意]布爾值除外,因為Symbol與JS中的非空值類似,其等價布爾值為true

let uid = Symbol.for("uid");
console.log(uid);//'Symbol(uid)'
console.log(!uid);//false
console.log(Boolean(uid));//true

 

屬性檢索

  Symbol作為屬性名,該屬性不會出現在for...in、for...of迴圈中,也不會被Object.getOwnPropertyNames()、Object.keys()、JSON.stringify()返回。於是,在ES6中添加了一個Object.getOwnpropertySymbols()方法來檢索對象中的Symbol屬性

  Object.getOwnPropertySymbols()方法的返回值是一個包含所有Symbol自有屬性的數組

let uid = Symbol.for("uid");
let object = {
    [uid]: "12345"
};
let symbols = Object.getOwnPropertySymbols(object);
console.log(symbols.length); // 1
console.log(symbols[0]); // "Symbol(uid)"
console.log(object[symbols[0]]); // "12345"

  在這段代碼中,object對象有一個名為uid的Symbol屬性,object.getOwnPropertySymbols()方法返回了包含這個屬性的數組

  另一個新的API——Reflect.ownKeys()方法可以返回所有類型的鍵名,包括常規鍵名和 Symbol 鍵名

let obj = {
  [Symbol('my_key')]: 1,
  enum: 2,
  nonEnum: 3
};
console.log(Reflect.ownKeys(obj));//  ["enum", "nonEnum", Symbol(my_key)]

  由於以 Symbol 值作為名稱的屬性,不會被常規方法遍歷得到。可以利用這個特性,為對象定義一些非私有的、但又希望只用於內部的方法

var size = Symbol('size');

class Collection {
  constructor() {
    this[size] = 0;
  }

  add(item) {
    this[this[size]] = item;
    this[size]++;
  }

  static sizeOf(instance) {
    return instance[size];
  }
}

var x = new Collection();
Collection.sizeOf(x) // 0

x.add('foo');
Collection.sizeOf(x) // 1

Object.keys(x) // ['0']
Object.getOwnPropertyNames(x) // ['0']
Object.getOwnPropertySymbols(x) // [Symbol(size)]

  上面代碼中,對象x的size屬性是一個Symbol值,所以Object.keys(x)、Object.getOwnPropertyNames(x)都無法獲取它。這就造成了一種非私有的內部方法的效果

 

內置Symbol

  除了定義自己使用的Symbol值以外,ES6還提供了11個內置的Symbol值,指向語言內部使用的方法

  1、Symbol.haslnstance

  一個在執行instanceof時調用的內部方法,用於檢測對象的繼承信息

  2、Symbol.isConcatSpreadable

  一個布爾值,用於表示當傳遞一個集合作為Array.prototype.concat()方法的參數時,是否應該將集合內的元素規整到同一層級

  3、Symbol.iterator

  一個返回迭代器的方法

  4、Symbol.match

  一個在調用String.prototype.match()方法時調用的方法,用於比較字元串

  5、Symbol.replace

  一個在調用String.prototype.replace()方法時調用的方法,用於替換字元串的子串

  6、Symbol.search

  一個在調用String.prototype.search()方法時調用的方法,用於在字元串中定位子串

  7、Symbol.species

  用於創建派生類的構造函數

  8、Symbol.split

  一個在調用String.prototype.split()方法時調用的方法,用於分割字元串

  9、Symbol.toprimitive

  一個返回對象原始值的方法

  10、Symbol.ToStringTag

  一個在調用Object.prototype.toString()方法時使用的字元串,用於創建對象描述

  11、Symbol.unscopables

  一個定義了一些不可被with語句引用的對象屬性名稱的對象集合

【Symbol.haslnstance】

  每個函數都有一個Symbol.haslnstance方法,用於確定對象是否為函數的實例。該方法在Function.prototype中定義,所有函數都繼承了instanceof屬性的預設行為。為了確保Symbol.haslnstance不會被意外重寫,該方法被定義為不可寫、不可配置並且不可枚舉

  Symbol.haslnstance方法只接受一個參數,即要檢查的值。如果傳入的值是函數的實例,則返回true

obj instanceof Array;

  以上這行代碼等價於下麵這行

Array[Symbol.hasInstance](obj);

  本質上,ES6只是將instanceof操作符重新定義為此方法的簡寫語法。現在引入方法調用後,就可以隨意改變instanceof的運行方式了

class MyClass {
  [Symbol.hasInstance](foo) {
    return foo instanceof Array;
  }
}
console.log([1, 2, 3] instanceof new MyClass()); // true

  假設定義一個無實例的函數,就可以將Symbol.haslnstance的返回值硬編碼為false

function MyObject() {
    // ...
}
Object.defineProperty(MyObject, Symbol.hasInstance, {
    value: function(v) {
        return false;
    }
});
let obj = new MyObject();
console.log(obj instanceof MyObject); // false

  只有通過Object.defineProperty()方法才能夠改寫一個不可寫屬性,上面的示例調用這個方法來改寫symbol.haslnstance,為其定義一個總是返回false的新函數,即使obj實際上確實是Myobject類的實例,在調用過object.defineProperty()方法之後,instanceof運算符返回的也是false

  當然,也可以基於任意條件,通過值檢查來確定被檢測的是否為實例。例如,可以將1~100的數字定義為一個特殊數字類型的實例,具體實現的代碼如下

function SpecialNumber() {
  // empty
}
Object.defineProperty(SpecialNumber, Symbol.hasInstance, {
    value: function(v) {
        return (v instanceof Number) && (v >=1 && v <= 100);
    }
});
let two = new Number(2),
zero = new Number(0);
console.log(two instanceof SpecialNumber); // true
console.log(zero instanceof SpecialNumber); // false

  在這段代碼中定義了一個symbol.hasInstance方法,當值為Number的實例且其值在1~100之間時返回true。所以即使SpecialNumber函數和變數two之間沒有直接關係,變數two也被確認為specialNumber的實例

  如果要觸發Symbol.haslnstance調用,instanceof的左操作數必須是一個對象,如果左操作數為非對象會導致instanceof總是返回false  

  當然,可以重寫所有內建函數(如Date和Error函數)預設的symbol.haslnstance屬性。但是這樣做的後果是代碼的運行結果變得不可預期且有可能令人感到困惑,所以不推薦這樣做,最好的做法是,只在必要情況下改寫自己聲明的函數的Symbol.haslnstance屬性

【Symbol.isConcatSpreadable】

  對象的Symbol.isConcatSpreadable屬性是布爾值,表示該對象使用Array.prototype.concat()時,是否可以展開

let arr1 = ['c', 'd'];
['a', 'b'].concat(arr1, 'e') // ['a', 'b', 'c', 'd', 'e']
arr1[Symbol.isConcatSpreadable] // undefined

let arr2 = ['c', 'd'];
arr2[Symbol.isConcatSpreadable] = false;
['a', 'b'].concat(arr2, 'e') // ['a', 'b', ['c','d'], 'e']

  上面代碼說明,數組的預設行為是可以展開。Symbol.isConcatSpreadable屬性等於undefined或true,都有這個效果

  類數組對象也可以展開,但它的Symbol.isConcatSpreadable屬性預設為false,必須手動打開

let obj = {length: 2, 0: 'c', 1: 'd'};
['a', 'b'].concat(obj, 'e') // ['a', 'b', obj, 'e']

obj[Symbol.isConcatSpreadable] = true;
['a', 'b'].concat(obj, 'e') // ['a', 'b', 'c', 'd', 'e']

  對於一個類來說,Symbol.isConcatSpreadable屬性必須寫成實例的屬性

class A1 extends Array {
  constructor(args) {
    super(args);
    this[Symbol.isConcatSpreadable] = true;
  }
}
class A2 extends Array {
  constructor(args) {
    super(args);
    this[Symbol.isConcatSpreadable] = false;
  }
}
let a1 = new A1();
a1[0] = 3;
a1[1] = 4;
let a2 = new A2();
a2[0] = 5;
a2[1] = 6;
[1, 2].concat(a1).concat(a2)
// [1, 2, 3, 4, [5, 6]]

  上面代碼中,類A1是可展開的,類A2是不可展開的,所以使用concat時有不一樣的結果

【Symbol.species】

  對象的Symbol.species屬性,指向當前對象的構造函數。創造實例時,預設會調用這個方法,即使用這個屬性返回的函數當作構造函數,來創造新的實例對象

class MyArray extends Array {
  // 覆蓋父類 Array 的構造函數
  static get [Symbol.species]() { return Array; }
}

  上面代碼中,子類MyArray繼承了父類Array。創建MyArray的實例對象時,本來會調用它自己的構造函數,但是由於定義了Symbol.species屬性,所以會使用這個屬性返回的的函數,創建MyArray的實例

  這個例子也說明,定義Symbol.species屬性要採用get讀取器。預設的Symbol.species屬性等同於下麵的寫法

static get [Symbol.species]() {
  return this;
}

  下麵是一個例子

class MyArray extends Array {
  static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);

mapped instanceof MyArray // false
mapped instanceof Array // true

  上面代碼中,由於構造函數被替換成了Array。所以,mapped對象不是MyArray的實例,而是Array的實例

【Symbol.match】

  對象的Symbol.match屬性,指向一個函數。當執行str.match(myObject)時,如果該屬性存在,會調用它,返回該方法的返回值

String.prototype.match(regexp)
// 等同於
regexp[Symbol.match](this)

class MyMatcher {
  [Symbol.match](string) {
    return 'hello world'.indexOf(string);
  }
}

'e'.match(new MyMatcher()) // 1

【Symbol.replace】

  對象的Symbol.replace屬性,指向一個方法,當該對象被String.prototype.replace方法調用時,會返回該方法的返回值

String.prototype.replace(searchValue, replaceValue)
// 等同於
searchValue[Symbol.replace](this, replaceValue)

  下麵是一個例子

const x = {};
x[Symbol.replace] = (...s) => console.log(s);

'Hello'.replace(x, 'World') // ["Hello", "World"]

  Symbol.replace方法會收到兩個參數,第一個參數是replace方法正在作用的對象,上面例子是Hello,第二個參數是替換後的值,上面例子是World

【Symbol.search】

  對象的Symbol.search屬性,指向一個方法,當該對象被String.prototype.search方法調用時,會返回該方法的返回值

String.prototype.search(regexp)
// 等同於
regexp[Symbol.search](this)

class MySearch {
  constructor(value) {
    this.value = value;
  }
  [Symbol.search](string) {
    return string.indexOf(this.value);
  }
}
'foobar'.search(new MySearch('foo')) // 0

【Symbol.split】

  對象的Symbol.split屬性,指向一個方法,當該對象被String.prototype.split方法調用時,會返回該方法的返回值

String.prototype.split(separator, limit)
// 等同於
separator[Symbol.split](this, limit)

  下麵是一個例子

class MySplitter {
  constructor(value) {
    this.value = value;
  }
  [Symbol.split](string) {
    var index = string.indexOf(this.value);
    if (index === -1) {
      return string;
    }
    return [
      string.substr(0, index),
      string.substr(index + this.value.length)
    ];
  }
}
'foobar'.split(new MySplitter('foo'))// ['', 'bar']
'foobar'.split(new MySplitter('bar'))// ['foo', '']
'foobar'.split(new MySplitter('baz'))// 'foobar'

  上面方法使用Symbol.split方法,重新定義了字元串對象的split方法的行為

【Symbol.iterator】

  對象的Symbol.iterator屬性,指向該對象的預設遍歷器方法

var myIterable = {};
myIterable[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

[...myIterable] // [1, 2, 3]

  對象進行for...of迴圈時,會調用Symbol.iterator方法,返回該對象的預設遍歷器

class Collection {
  *[Symbol.iterator]() {
    let i = 0;
    while(this[i] !== undefined) {
      yield this[i];
      ++i;
    }
  }
}

let myCollection = new Collection();
myCollection[0] = 1;
myCollection[1] = 2;

for(let value of myCollection) {
  console.log(value);
}
// 1
// 2

【Symbol.toPrimitive】

  對象的Symbol.toPrimitive屬性,指向一個方法。該對象被轉為原始類型的值時,會調用這個方法,返回該對象對應的原始類型值

  Symbol.toPrimitive被調用時,會接受一個字元串參數,表示當前運算的模式,一共有三種模式

  1、Number:該場合需要轉成數值

  2、String:該場合需要轉成字元串

  3、Default:該場合可以轉成數值,也可以轉成字元串

let obj = {
  [Symbol.toPrimitive](hint) {
    switch (hint) {
      case 'number':
        return 123;
      case 'string':
        return 'str';
      case 'default':
        return 'default';
      default:
        throw new Error();
     }
   }
};

2 * obj // 246
3 + obj // '3default'
obj == 'default' // true
String(obj) // 'str'

【String.toStringTag】

  對象的Symbol.toStringTag屬性,指向一個方法。在該對象上面調用Object.prototype.toString方法時,如果這個屬性存在,它的返回值會出現在toString方法返回的字元串之中,表示對象的類型。也就是說,這個屬性可以用來定製[object Object][object Array]object後面的那個字元串

// 例一
({[Symbol.toStringTag]: 'Foo'}.toString())
// "[object Foo]"

// 例二
class Collection {
  get [Symbol.toStringTag]() {
    return 'xxx';
  }
}
var x = new Collection();
Object.prototype.toString.call(x) // "[object xxx]"

  ES6新增內置對象的Symbol.toStringTag屬性值如下、

    JSON[Symbol.toStringTag]:'JSON'
    Math[Symbol.toStringTag]:'Math'
    Module[Symbol.toStringTag]:'Module'
    ArrayBuffer.prototype[Symbol.toStringTag]:'ArrayBuffer'
    DataView.prototype[Symbol.toStringTag]:'DataView'
    Map.prototype[Symbol.toStringTag]:'Map'
    Promise.prototype[Symbol.toStringTag]:'Promise'
    Set.prototype[Symbol.toStringTag]:'Set'
    %TypedArray%.prototype[Symbol.toStringTag]:'Uint8Array'
    WeakMap.prototype[Symbol.toStringTag]:'WeakMap'
    WeakSet.prototype[Symbol.toStringTag]:'WeakSet'
    %MapIteratorPrototype%[Symbol.toStringTag]:'Map Iterator'
    %SetIteratorPrototype%[Symbol.toStringTag]:'Set Iterator'
    %StringIteratorPrototype%[Symbol.toStringTag]:'String Iterator'
    Symbol.prototype[Symbol.toStringTag]:'Symbol'
    Generator.prototype[Symbol.toStringTag]:'Generator'
    GeneratorFunction.prototype[Symbol.toStringTag]:'GeneratorFunction'

【Symbol.unscopables】

  對象的Symbol.unscopables屬性,指向一個對象。該對象指定了使用with關鍵字時,哪些屬性會被with環境排除。

Array.prototype[Symbol.unscopables]
// {
//   copyWithin: true,
//   entries: true,
//   fill: true,
//   find: true,
//   findIndex: true,
//   includes: true,
//   keys: true
// }

Object.keys(Array.prototype[Symbol.unscopables])
// ['copyWithin', 'entries', 'fill', 'find', 'findIndex', 'includes', 'keys']

  上面代碼說明,數組有7個屬性,會被with命令排除

// 沒有 unscopables 時
class MyClass {
  foo() { return 1; }
}

var foo = function () { return 2; };

with (MyClass.prototype) {
  foo(); // 1
}

// 有 unscopables 時
class MyClass {
  foo() { return 1; }
  get [Symbol.unscopables]() {
    return { foo: true };
  }
}

var foo = function () { return 2; };

with (MyClass.prototype) {
  foo(); // 2
}

  上面代碼通過指定Symbol.unscopables屬性,使得with語法塊不會在當前作用域尋找foo屬性,即foo將指向外層作用域的變數

 

 


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

-Advertisement-
Play Games
更多相關文章
  • 原題: Your Ride Is Here It is a well-known fact that behind every good comet is a UFO. These UFOs often come to collect loyal supporters from here on Ea ...
  • 認真對待學習 最近又重新閱讀了spring官方文檔 對裡面的有用的高頻的配進行記錄和分享。 簡介 控制反轉(IoC)又被稱作依賴註入(DI)。它是一個對象定義其依賴的過程,它的依賴也就是與它一起合作的其它對象,這個過程只能通過構造方法參數、工廠方法參數、或者被構造或從工廠方法返回後通過settter ...
  • Step1 Plotting the Data 在處理數據之前,我們通常要瞭解數據,對於這次的數據集合,我們可以通過離散的點來描繪它,在一個2D的平面里把它畫出來。 6.1101,17.592 5.5277,9.1302 8.5186,13.662 7.0032,11.854 5.8598,6.82 ...
  • 大型網站架構技術一覽 網站系統架構層次如下圖所示: 1、 前端架構 前端指用戶請求到達網站應用伺服器之前經歷的環節,通常不包含網站業務邏輯,不處理動態內容。 (1) 瀏覽器優化技術; (2) CDN; (3) 動靜分離,靜態資源獨立部署; (4) 圖片服務; (5) 反向代理; (6) DNS:功能變數名稱 ...
  • zookeeper單機模式安裝 更多文章: "http://blogxinxiucan.sh1.newtouch.com/2017/07/26/zookeeper單機模式安裝/" 下載zookeeper ubuntu下直接用命令下載 解壓 更改配置文件 進入到 目錄下複製zoo_sample.cfg ...
  • 一張圖,清晰的說明 SLB和 CLB的優劣。 ...
  • 背景:之前一直用的artdialog,但是樣式不是很好看,後來偶然看到layer,覺得不錯,但是對於.net mvc來說,不能像artdialog一樣彈出分部視圖是很難受的。所以下麵的方法就解決了。 ...
  • html部分代碼 這是一個下拉多選框,現在要動態往裡添加下拉選項。 js代碼 關鍵在於$(".selectpicker" ).selectpicker('refresh'); 如果沒有這句數據是綁定不進去的。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...