主頁 > 企業開發 > JavaScript:原型(prototype)

JavaScript:原型(prototype)

2022-12-24 06:59:03 企業開發

面向物件有一個特征是繼承,即重用某個已有類的代碼,在其基礎上建立新的類,而無需重新撰寫對應的屬性和方法,繼承之后拿來即用;

在其他的面向物件編程語言比如Java中,通常是指,子類繼承父類的屬性和方法;

我們現在來看看,JS是如何實作繼承這一個特征的;

要說明這個,我們首先要看看,每個物件都有的一個隱藏屬性[[Prototype]]

物件的隱藏屬性[[Prototype]]

在JS中,每個物件obj,都有這樣一個隱藏屬性[[Prototype]],它的值要么是null,要么是對另一個物件anotherObj的參考(不可以賦值為其他型別值),這另一個物件anotherObj,就叫做物件obj的原型;

通常說一個物件的原型,就是在說這個隱藏屬性[[Prototype]],也是在說它參考的那個物件,畢竟二者一致;

現在來創建一個非常簡單的字面量物件,來查看一下這個屬性:

image-20221219202044247

可以看到,物件obj沒有自己的屬性和方法,但是它還有一個隱藏屬性[[Prototype]],資料型別是Object,說明它指向了一個物件(即原型),這個原型物件里面,有很多方法和一個屬性;

其他的暫且不論,我們先重點看一下,紅框的constructor()方法和__proto__屬性;

訪問器屬性(__proto__)

訪問[[Prototype]]

從紅框可以看到,屬性__proto__是一個訪問器屬性,有getter/setter特性(這個屬性名前后各兩個下劃線);

問題是,它是用來訪問哪個屬性的?

我們來呼叫一下看看:

image-20221219205330882

可以看到,__proto__訪問器屬性,訪問的正是隱藏屬性[[Prototype]],或者說,它指向的正是原型物件;

值得一提的是,這是一個老式的訪問原型物件的方法,現代編程語言建議使用Object.getPrototypeOf/setPrototypeOf來訪問原型物件;

但是考慮兼容性,使用__proto__也是可以的;

請注意,__proto__不能代表[[Prototype]]本身,它只是其一個訪問器屬性;

設定[[Prototype]]

正因為它是訪問器屬性,也即具有getter和setter功能,我們現在可以控制物件的原型物件的指向了(并不建議這樣做):

image-20221219210505820

如上圖,現在將其賦值為null,好了,現在obj物件沒有原型了;

image-20221219212732241

如上圖,創建了兩個物件,并且讓obj1沒有了原型,讓obj2的原型是obj1

看看,此時obj2.name讀取到obj1的屬性name了,首先obj2在自身屬性里找name沒有找到,于是去原型上去找,于是找到了obj1name屬性了,換句話說,obj2繼承了obj1的屬性了;

這就是JS實作繼承的方式,通過原型這種機制;

讓我們看看下面的代碼:

image-20221219214739842

正常的obj2.name = 'Jerry'的添加屬性的陳述句,會成為obj2物件自己的屬性,而不會去覆寫原型的同名屬性,這是再正常不過了,繼承得來的東西,只能讀取,不能修改(訪問器屬性__proto__除外);

現在的問題是,為什么obj2.__proto__undefined?上面不是剛剛賦值為obj1了嗎?

原因就在于__proto__是訪問器屬性,我們讀取它實際上是在呼叫對應的getter/setter方法,而現在obj2的原型(即obj1)并沒有對應的getter/setter方法,自然是undefined了;

現在綜合一下,看下面代碼:

image-20221219220644268

為什么最后obj2.__proto__輸出的是hello world,為什么__proto__成了obj2自己的屬性了?

關鍵就在于紅框的三句代碼:

第一句let obj2 = {},此時obj2有原型,有訪問器屬性__proto__,一切正常;

第二句obj2.__proto__ = obj1,這句呼叫__proto__的setter方法,將[[Prototype]]的參考指向了obj1

這一句完成以后,obj2因為obj1這個原型而沒有訪問器屬性__proto__了;

所以第三句obj2.__proto__ = 'hello world'__proto__已經不再是訪問器屬性了,而是一個普通的屬性名了,所以這句就是一個普通的添加屬性的陳述句了;

構造器(constructor)

在隱藏屬性[[Prottotype]]那里,看到其有一個constructor()方法,顧名思義,這就是構造器了;

類物件與函式物件

  • 類物件

在其他編程語言比如Java中,構造方法通常是和類名同名的函式,里面定義了物件的一些初始化代碼;

當需要一個物件時,就通過new關鍵字去呼叫構造方法創建一個物件;

那在JS中,當我們let obj = {}去創建一個字面量物件的時候,發生了什么?

上面這句代碼,其實就是let obj = new Object()的簡寫,也是通過new關鍵字去呼叫一個和類名同名的構造方法去創建一個物件,在這里就是構造方法Object()

這種通過new className()呼叫構造方法創造的物件,稱為類物件;

  • 函式物件

但是,再等一下,JS早期是沒有類的概念的,那個時候大家又是怎么去創建物件的呢?

想一下,創建物件是不是需要一個構造方法(即一個函式),本質上是不是new Function()的形式去創建物件?

對咯,早期就是new Function()去創建物件的,這個Function就叫做建構式;

這種通過new Function()呼叫建構式創造的物件,稱為函式物件;

建構式和普通函式又有什么區別呢?除了要求是用function關鍵字宣告的函式,并且命名建議大駝峰以外,幾乎是沒有區別的:

image-20221219230237600

看,我們宣告了一個建構式Cat(),并通過new Cat()創造了一個物件tom

列印tom發現,它有一個原型,這個原型和字面量物件的原型不一樣,它有一個方法一個屬性;

方法是constructor()構造器,指向的正是Cat()函式;

屬性是另一個隱藏屬性[[Prototype]],暫時不去探究它是誰;

也就是說,函式物件的原型,是由另一個原型和constructor()方法組成的物件;

我們可以用代碼來驗證一下,類物件和函式物件的原型的異同點:

image-20221220180834768

如上所示,創建了一個函式物件tom和一個類物件obj

可以看出:

函式物件的原型的方法constructor()指向建構式本身;

函式物件的原型的隱藏屬性[[Prototype]]和字面量物件(Object物件)的隱藏屬性,他們兩的參考相同,指向的是同一個物件,暫時不去探究這個物件是什么,就認為它是字面量物件的原型即可;

還可以看到,無論是類物件,還是函式物件,其原型都有constructor()構造器;

這個構造器在創建物件的程序中,具體起了什么樣的作用呢?

讓我們先看看函式物件tom的這個原型是怎么來的?我們之前一直都是在說物件有一個隱藏屬性[[Prototype]]指向原型物件,究竟是哪一步,讓這個隱藏屬性指向了原型物件呢?

函式的普通屬性prototype

事實上,每個函式都有一個屬性prototype,默認情況下,這個屬性prototype是一個物件,其中只含有一個方法constructor,而這個constructor指向函式本身(還有一個隱藏屬性[[Prototype]],指向字面量物件的原型);

可以用代碼佐證,如下所示:

image-20221220122721686

注意,prototype要么是一個物件型別,要么是null,不可以是其他型別,這聽起來很像隱藏屬性[[Prototype]],不過prototype只是函式的一個普通屬性,物件是沒有這個屬性的;

來看下這個屬性的特性吧:

image-20221220183641004

可以看到,它不是一個訪問器屬性,只是一個普通屬性,但是它不可配置不可列舉,只能修改值;

它的value值,眼熟嗎?正是建構式創建的函式物件的原型啊;

它居然還有一個特性[[Prototype]],不要把它和value值里面的屬性[[Prototype]]弄混,前者是prototype屬性的特性,后者是prototype屬性的一個隱藏屬性,雖然此刻他們都指向字面量物件的原型,但是前者始終指向字面量物件的原型,后者則始終指向原型(而原型是會變的);

這里也不再去追究為什么它會有這樣一個特性了,讓我們把重點放在prototype屬性本身;

new Function()的時候發生了什么

事實上,只有在呼叫new Function()作為建構式的時候,才會使用到這個prototype屬性;

image-20221220185833703

我們來仔細分析一下上面代碼具體發生了什么:

let tom = new Cat()這句代碼的執行流程如下:

  • 先呼叫Cat.prototype屬性的特性[[Prototype]](我們知道它指向字面量物件的原型)里面的constructor()構造器,創建一個字面量空物件,當然此時這個物件的隱藏屬性[[Prototype]]也都已經存在了,將這個物件分配給this指標;
  • 然后回傳this指標給tom,即tom參考了這個字面量空物件,同時this指向了tom
  • 然后執行建構式Cat()本身的陳述句,即this.name = "Tom",于是tom就有了一個屬性name
  • 然后將Cat.prototype屬性值value復制(注意,這里是復制,不是賦值,這意味著這里不是傳參考,而是傳值)給tom的隱藏屬性[[Prototype]],即tom.__proto__ = Cat.prototype

如果我們用代碼去描述上面整個程序,就類似于下面這樣:

// let tom = new Cat()的整個具體流程,類似于下面這樣
let tom = {}; //創建字面量物件,并賦值給變數tom
tom.name = "Tom"; // 執行Cat()函式
tom.__proto__ = Cat.prototype; // 將Cat的prototype的屬性值賦值給tom的隱藏屬性[[Prototype]]

現在已經說清楚了new Function()發生的具體程序,上面代碼的輸出結果也佐證了我們所說的:

函式物件tom的原型正是Cat函式的屬性prototype的值value,可以看到他們的constructor()構造器都指向Cat函式本身,并且tom.name的值Tom

然后我們修改了Cat函式的prototype的值valueCat.prototype = Dog.prototype陳述句將其設定成了Dog函式的prototype的值value

讓我們順著剛剛說的流程,看看let newTom = new Cat()的執行程序:

  • 先創建字面量空物件;
  • 然后賦值給newTom
  • 然后呼叫Cat()函式本身,即newTom.name = "Tom"
  • 然后執行陳述句newTom.__proto__ = Cat.prototype,而Cat.prototype = Dog.prototype,所以newTom.__proto__ = Dog.prototype

輸出結果佐證了我們的執行程序,函式newTom的原型正是Dog函式的屬性prototype的值value,他們的constructor()構造器都指向了Dog函式本身,但是newTom.name的值依然是"Tom";

從上面前后兩個輸出結果也可以看出來,最后一步的tom.__proto__ = Cat.prototype確實是復制而不是賦值,否則在Cat.prototype = Dog.prototype陳述句之后,tom.__proto__ = Cat.prototype = Dog.prototype了,但是輸出結果表面并沒有改變;

現在我們已經明白了函式物件的原型為什么是這個樣子的,也明白了函式物件的constructor()構造器指向了建構式本身;

現在讓我們像下面這樣,使用一下函式物件的constructor()構造器吧:

image-20221220204243512

看上面的代碼,我們現在已經知道let tom = new Cat()的時候都發生了什么,也知道此時tom的原型的constructor()構造器指向的是Dog函式;

所以let spike = new tom.constructor()這句代碼,當tom去自己的屬性里沒有找到constructor()方法的時候,就去原型里面去找,于是找到了指向Dog函式的constructor()構造器,所以這句代碼就等于let spike = new Dog()

通過這段代碼,好好體會一下函式物件的構造器吧,

建構式和普通函式的區別

其實從技術上來講,建構式和普通函式沒有區別;

只是默認建構式采用大駝峰命名法,并通過new運算子去創建一個函式物件;

  • new.target

    我們怎樣去判斷一個函式的呼叫是普通呼叫,還是new運算子呼叫的呢?

    image-20221221152944768

    如上所示,通過new.target,可以判斷該函式是被普通呼叫的還是通過new關鍵字呼叫的;

  • 建構式的回傳值

    建構式從技術上說,就是一個普通函式,所以當然也可能有return回傳值(通常建構式于情于理都是不會有return陳述句的);

    image-20221221153625673

    之前說過new Function()的時候的具體流程,我們來看一下:

    • 先創建一個字面量空物件;

    • 將空物件賦值給tom

    • 執行Cat()函式,讓tom有了屬性name

      但是Cat()函式有return陳述句,回傳了一個空物件{},由tom接收了,也就是說tom被覆寫賦值了;

    • 所以最后tom指向的是return陳述句的空物件,而不是最開始創建的空物件;

字面量物件的原型

new Object()的時候發生了什么

我們剛剛說了new Function()創建函式物件的時候,具體發生了什么,現在來看看創建類物件的時候,具體發生了什么;

Object為例,因為它是一個類,是JS其他所有類的祖先,這一點與Java類似;

我們先看一下Objectprototype屬性吧,是的,類和函式一樣,也有這個屬性(注意,是類有這個屬性,而不是類的實體即物件有這個屬性);

image-20221220205757060

看上圖,是不是很眼熟,這不就是字面量物件的原型嗎?

image-20221220210050576

是的,如上圖所示,就是它;

還記得原型鏈吧,那么這個原型物件還有原型嗎?

image-20221220221559466

如上所示,沒有了,指向null了,看樣子我們已經走到了原型鏈的原點了,為了方便,我們就稱呼Object.prototype為原始原型吧;

看看它的特性吧:

image-20221220210424571

和函式的prototype屬性的特性,如出一轍,但是注意,它的writable屬性是false了,這意味著我們再也無法對這個屬性做任何操作了;

這是當然,它可是所有類的祖先,怎么能隨意更改呢;

這下我們就能明白new ClassName()的時候大概流程是什么樣子了;

let obj = {}為例(其實就是let obj = new Object()):

  • 先呼叫Objecet.prototype屬性的特性[[Prototype]]里面的constructor()構造器(不再繼續深究這個構造器了),創建一個字面量空物件,當然此時這個物件的隱藏屬性[[Prototype]]也都已經存在了;
  • 然后將這個物件賦值給obj,即obj參考了這物件,同時this指標也就指向了obj
  • 然后執行構造方法Object()本身的陳述句,就不再進一步去研究這個構造方法了,總之此時obj已經是一個有著很多內置方法的字面量物件了;
  • 然后將Object.prototype屬性值value,復制給obj的隱藏屬性[[Prototype]],即obj.__proto__ = Object.prototype

注意,其實流程不完全是上面這樣子,與建構式的流程還有一點點區別,主要是第三步,還有一個構造器的執行,這和類的繼承有關系,詳細的在后面new className()的時候發生了什么里面具體說明;

更改原始原型

我們剛剛說了,Object.prototype屬性的所有特性都是false,意味著我們對這個屬性無法再做任何操作了;

這只是再說,我們不能對其本身做任何刪改的操作了,但是它本身依然是一個物件,這意味著我們可以正常的向其添加屬性和方法;

image-20221220223232974

如上圖所示,我們向Object.prototype屬性物件里添加了hello()方法,并且由obj物件通過原型呼叫了這個方法;

類物件的原型

我們已經了解了函式物件的原型,和原始原型,再來看看類物件的原型;

我們把這三種放一起做個比較吧:

image-20221220225535034

我們自定義了類classA,自定義了函式functionA,并創建了類物件clsA和函式物件funcA,以及字面量物件;

可以看出,類物件與函式物件的原型的形式,是一致的,只是各自原型里的constructor()指向各自的類/函式,即紅框部分不同;

而他們的原型的原型則是一致的,和字面量物件的原型一樣,都指向了原始原型,即綠框部分相同;

上面的輸出結果佐證了這一點;

從這也可以看出來,其他類都是繼承自原始類Object的,只是原型鏈的長短罷了,最終都可以溯源到原始類Object

很顯然,類與建構式,很類似;

類與建構式的區別

盡管類物件和函式物件有相似的原型,但是不代表類與建構式就完全一樣了,他們之間的區別還是很大的:

  • 型別不同,定義形式不同

    image-20221221160907543

    類名后不需要括號,建構式名后需要加括號;

    類的方法宣告形式和建構式的方法不一樣;

    列印類和建構式,類前的型別是class,建構式前的型別是f,即function

    注意,不能使用typeof運算子,它會認為類和建構式都是function

  • prototype不一樣

    image-20221221161607599

    如上所示,類的方法,會成為prototype的方法,但是建構式的方法不會成為prototype的方法;

    也即建構式的prototype始終由constructor()和原始原型組成,函式物件無法通過原型去呼叫在建構式里定義的方法;

    函式物件如果想要呼叫method1()方法,就不能寫成let method1 = function(){},而是this.method1 = function(){},將其變為函式物件自己的方法;

  • prototype的特性不一樣

    image-20221221162205970

    類的prototype是不可寫的,但是建構式的prototype是可寫的;

  • 方法的特性不一樣

    image-20221221163658267

    由于函式物件不能通過原型繼承方法,這里只展示類的方法的特性,如上所示,類的方法,是不可列舉的,也即不會被for-in語法遍歷到;

  • 模式不同

    由于類是后來才有的概念,所以類總是使用嚴格模式,即不需要顯示使用use strict,類總是在嚴格模式下執行;

    而建構式則不同,默認是普通模式,需要顯示使用use strict才會在嚴格模式下執行;

  • [[IsClassConstructor]]

    類有隱藏屬性[[IsClassConstructor]],其值為true;

    這要求必須使用new關鍵字去呼叫它,像普通函式一樣呼叫會出錯:

    image-20221221164940516

    但是很顯然,建構式本身就是一個函式,是可以像普通函式一樣去呼叫的;

  • 構造器constructor

    由于函式物件不能通過原型繼承方法,所以無法自定義構造器;

    但是類物件可以繼承啊,所以可以自定義構造器并在new的時候呼叫;

    image-20221221170615072

    從圖上可以看出,我們是無法去自定義建構式的構造器的,它依然還是按照我們所說的流程去創建函式物件的;

    我們現在看看,類自定義構造器,是怎么按照我們的流程去創建類物件的:

    • 先呼叫classA.prototype的特性[[Prototype]]里的構造器去創建一個字面量空物件;

    • 將空物件賦值給變數clsA

    • 然后執行構造方法classA()本身的陳述句;

      首先添加了屬性outterName

      然后又遇到了constructor()方法(注意該構造器與classA.prototype.constructor不是同一個東西),于是又執行了這個構造器的陳述句,添加了屬性innerName

    由此我們可以得出,類在創建類物件的時候,流程依然是我們所述的流程;

    但是在遇到類里面的同名方法constructor()時候,不會將其作為原型方法,而是會立即運行該構造器;

    另外,像outterName這樣的屬性,不會成為prototype的屬性,也就是說,類只有定義的方法(除了constructor構造器)會進入prototype的屬性,成為原型被繼承;

new className()的時候發生了什么

上面剛剛描述了類自定義構造器之后,創建物件是一個什么樣的流程;

現在來仔細理解一下類的構造器,事實上,如果我們不顯式自定義構造器,類也會默認提供一個下面這樣的構造器:

constructor() {
	super();
}

這里的super()實際上就是在呼叫其父類的構造方法(注意不是指父類的構造器constructor(),而是指父類自身);

用代碼來驗證一下吧:

image-20221221191937504

我們先來看一下let c = new classC()的時候,具體流程是什么樣的吧:

  • 首先呼叫classC.prototype屬性的特性[[Prototype]](它總是指向原始原型),創建一個字面量空物件;
  • 然后將其賦值給變數c
  • 然后執行構造方法classC()的陳述句,通常會有添加物件的屬性和方法的陳述句,這里沒有;
  • 接著查看是否顯式宣告了constructor()構造器(如果沒有就提供一個默認的構造器),這里有,于是立即執行這個構造器;
    • 首先是super(),實際上就是執行建構式classA()的陳述句,于是添加了屬性nameA
    • 然后是this.nameB = 'C',于是添加了屬性nameC
  • 最后,將classC.prototypevalue值,復制給c的隱藏屬性[[Prototype]],即c.__proto__ = classC.prototype

整個完整流程如上所示;

現在來試著對著流程看看let b = new classB()吧:

  • 首先創建字面量空物件;
  • 賦值給變數b
  • 執行classB()的陳述句,添加了屬性nameB
  • 沒有構造器,提供默認的構造器,執行super()即執行classA()的陳述句,于是添加了屬性nameA
  • 最后,復制b的原型為classB.prototypevalue值;

輸出結果也驗證了我們所說的;

操作原型的現代方法

之前已經說過,通過__proto__屬性去操作原型的方法,是歷史的過時的方法,實際上并不推薦;

現代JS有以下方法,供我們去操作原型:

  • Object.getPrototypeOf(obj)

    此方法,回傳物件obj的隱藏屬性[[Prototype]]

  • Object.setPrototypeOf(obj, proto)

    此方法,將物件obj的隱藏屬性[[Prototype]]指向新的物件proto

  • Object.create(proto, descriptors)

    此方法,創建一個空物件,并將其隱藏屬性[[Prototype]]指向proto

    同時,可選引數descriptors可以給空物件添加屬性,如下所示:

    image-20221220233321028

原型鏈與繼承

現在應該已經理解了原型是一個什么樣的概念,以及如何去訪問原型;

正如繼承有兒子繼承父親,父親繼承爺爺一樣,有這樣一個往上溯源的關系,原型也可以這樣往上溯源,這就是原型鏈的概念;

用代碼去理解一下吧:

image-20221219222154114

我們定義了三個物件A/B/C,并且設定C的原型是B,B的原型是A;

讀取C.nameA的時候,首先在C自己的屬性里去找,沒有找到;

于是去原型B的屬性里去找,沒有找到;

再去B的原型A的屬性里去找,找到并輸出;

可以看C展開的一層層結構,可以很清晰的看到原型鏈的存在;

由此也可以看出,JS是單繼承的,同Java一致;

但是正常的繼承,肯定不是這樣手動去設定物件的原型的,而是自動去設定的;

在JS中,繼承的關鍵字也是extends,也是描述類的父子關系的;

image-20221221194842123

上面代碼,classC繼承classB,而classB繼承classA

所以classC的物件,繼承了他們的屬性,便有了三個屬性nameA/nameB/nameC,這也說明,屬性是不放在原型里的,而是會在創建物件的時候,直接成為classC的屬性;

classC的原型,有一個屬性一個方法,方法是constructor()構造器指向自己,屬性是另一個原型;

注意,列印出來的原型后面標注的classX,原型指的是物件,不是類,所以classC的原型不是指classB這個類本身,而是指其來源于classB

紫色框:物件c的原型,即c.__proto__ == classC.prototype

橘色框:classB.prototype,即物件c的原型的原型c.__proto__.__proto__ == classB.prototype

綠色框:classA.prototype,即物件c的原型的原型的原型c.__proto__.__proto__.__proto__ == classA.prototype

紅色框:Object.prototype,也即原始原型c.__proto__.__proto__.__proto__.__proto__ == Object.prototype

這是一條完整的原型鏈,從中也能看出繼承是什么樣的一個形式;

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/540646.html

標籤:其他

上一篇:教你用JavaScript實作計數器

下一篇:一文讀懂 HTTP/1 HTTP/2 HTTP/3

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more