原型與原型鏈,作用域及閉包,非同步和單執行緒

2021-09-01 11:50:05 字數 4130 閱讀 6131

原型與原型鏈

說到原型,就不得不提一下建構函式,首先我們看下面乙個簡單的例子:
function dog(name,age)

let dog1 = new dog("哈士奇",3);

let dog2 = new dog("泰迪",2);

首先創造空的物件,再讓 this 指向這個物件,通過 this.name 進行賦值,最終返回 this,這其實也是 new 乙個物件的過程。

其實: let obj = {} 是 let obj = new object() 的語法糖; let arr = 是 let arr = new array() 的語法糖; function dog() 是 let dog = new fucntion() 的語法糖。

那什麼是原型那?

在 js 中,所有物件都是 object 的例項,並繼承 object.prototype 的屬性和方法,但是有一些是隱性的。

我們來看一下原型的規則

所有的引用型別(包括陣列,物件,函式)都具有物件特性;可自由擴充套件屬性。

var obj = {};

obj.attribute = "三座大山";

var arr = ;

arr.attribute = "三座大山";

function fn1 () {}

fn1.attribute = "三座大山";

所有的引用型別(包括數,物件,函式)都有隱性原型屬性(proto), 值也是乙個普通的物件。

nsole.log(obj.__proto__);
所有的函式,都有乙個 prototype 屬性,值也是乙個普通的物件。

console.log(obj.prototype);
所有的引用型別的proto屬性值都指向建構函式的 prototype 屬性值。

console.log(obj.__proto__ === object.prototype); // true
當試圖獲取物件屬性時,如果物件本身沒有這個屬性,那就會去他的proto(prototype)中去尋找。

function dog(name) 

dog.prototype.callname = function ()

let dog1 = new dog("three mountain");

dog1.printname = function ()

dog1.callname(); // three mountain wang wang

dog1.printname(); // three mountain

原型鏈:如下圖。
找乙個屬性,首先會在 f.proto中去找,因為屬性值為乙個物件,那麼就會去 f.proto.proto去找,同理如果還沒找到,就會一直向上去查詢,直到結果為 null 為止。這個串起來的鏈即為原型鏈。

作用域及閉包

講到作用域,你會想到什麼?當然是執行上下文。每個函式都有自己的 excution context,和 variable object。這些環境用於儲存上下文中的變數,函式宣告,引數等。只有函式才能製造作用域。

ps:for if else 不能創造作用域。

console.log(a) ; // undefined

var a = 1;

//可理解為

var a;

console.log(a); // undefined

a = 1;

執行 console.log 時,a 只是被宣告出來,並沒有賦值;所以結果當然是 undefined。

this

本質上來說,在 js 裡 this 是乙個指向函式執行環境的指標。this 永遠指向最後呼叫它的物件,並且在執行時才能獲取值,定義是無法確認他的值。

var a =  

} a.fn() // this === a

a 呼叫了fn() 所以此時this為a

a.fn.call () // this ===

使用call(),將this的值指定為

var fn1 = a.fn

fn1() // this === window

雖然指定fn1 = a.fn,但是呼叫是有window呼叫,所以this 為window

this 有多種使用場景,下面我會主要介紹 4 個使用場景:

作為建構函式執行

function  student(name,age) 

var s = new student("py1988",30)

function  fn () 

fn ()

作為物件屬性執行

var obj = 

}obj.printname ()

三個函式可以修改 this 的指向,具體請往下看:

var name = "小明" , age = "17"

var obj =

} console.log(obj.objage) // 17

obj.fun() // 安妮今年undefined

var name = "小明" , age = "17" 

var obj =

} var a =

obj.fun.call(a,"蘋果","香蕉") // jay今年23 喜歡吃蘋果不喜歡吃香蕉

obj.fun.bind(a,"蘋果","香蕉")() // jay今年23 喜歡吃蘋果不喜歡吃香蕉

閉包

閉包的概念很抽象,看下面的例子你就會理解什麼叫閉包了:

function a();

}var c = new a();

c.fun(); //1

c.fun(); //2

閉包就是能夠讀取其他函式內部變數的函式。在 js 中只有函式內部的子函式才能讀取區域性變數。所以可以簡單的理解為:定義在內部函式的函式。

用途主要有兩個:

非同步和單執行緒

我們先感受下非同步。

console.log("start");

settimeout(function () , 1000);

console.log("end");

使用非同步後,列印的順序為 start-> end->medium。因為沒有阻塞。

為什麼會產生非同步呢?

首先因為 js 為單執行緒,也就是說 cpu 同一時間只能處理乙個事務。得按順序,乙個乙個處理。

如上例所示,第一步:執行第一行列印 「start」;第二步:執行 settimeout,將其中的函式分存起來,等待時間結束後執行;第三步:執行最後一行,列印 「end」;第四部:處於空閒狀態,檢視暫存中,是否有可執行的函式;第五步:執行分存函式。

為什麼 js 引擎是單執行緒?

js 的主要用途是與使用者互動,以及操作 dom,這決定它只能是單執行緒。例:乙個執行緒要新增 dom 節點,乙個執行緒要刪減 dom 節點,容易造成分歧。

為了更好使用多 cpu,h5 提供了 web worker 標準,允許 js 建立多執行緒,但是子執行緒受到主線程控制,而且不得操作 dom。

任務列隊

單執行緒就意味著,所有的任務都要排隊,前乙個結束,才會執行後面的任務。如果列隊是因為計算量大,cpu 忙不過來,倒也算了。但是更多的時候,cpu 是閒置的,因為 io 裝置處理得很慢,例如 ajax 讀取網路資料。js 設計者便想到,主線程完全可以不管 io 裝置,將其掛起,然後執行後面的任務。等後面的任務結束掉,在反過頭來處理掛起的任務。

好,我們來梳理一下:

只要主線程空了,就會讀取任務列隊,這就是 js 的執行機制,也被稱為 event loop(事件迴圈)。

閉包 原型 原型鏈

1.閉包 函式內部的函式 2.優點 1.隔離作用域,防止汙染全域性 2.有自己的獨立變數 3.快取 3.缺點 1.不容易垃圾 2.消耗記憶體 4.原型 1.函式有乙個prototype物件,可以通過函式的原型物件來實現繼承 2.原型prototype物件上有乙個constructor屬性。是建構函式...

閉包和原型鏈

閉包 簡單的理解就是 閉包就是能夠讀取其他函式內部變數的函式,它兩個最大的用處 可以讀取函式內部的變數,讓變數的值始終保持在記憶體中。閉包與它的詞法環境綁在一起,因此閉包讓我們能夠從乙個函式內部訪問其外部函式的作用域 閉包特點 函式a巢狀函式b 函式b能訪問函式a的變數 最後返回函式b 函式b就是閉...

作用域鏈與原型鏈

1 什麼是作用域鏈 當 在乙個環境中執行時,會建立變數物件的乙個作用域鏈。由子級作用域返回父級作用域中尋找變數,就叫做作用域鏈。作用域鏈中的下乙個變數物件來自包含環境,也叫外部環境。而再下乙個變數物件則來自下乙個包含環境,一直延續到全域性執行環境。全域性執行環境的變數物件始終都是作用域鏈中的最後乙個...