91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

深入理解 new 操作符

發布時間:2020-07-04 06:40:35 來源:網絡 閱讀:584 作者:狐貍菌 欄目:web開發

清明節來了,希望大家不要太悲傷!沒有對象的趕緊出對象,俗話說的好,萬物皆對象,JavaScript 中,為什么還要通過 new 來產生對象? 帶著這個問題,我們一步步來分析和理解 new 的一些特性:
1、認識 new 操作符

function Animal(name){
this.name = name;
}
Animal.color = "black";
Animal.prototype.say = function(){
console.log("I'm " + this.name);
};
var cat = new Animal("cat");

console.log(
cat.name, //cat
cat.height //undefined
);
cat.say(); //I'm cat

console.log(
Animal.name, //Animal
Animal.color //back
);
Animal.say(); //Animal.say is not a function

代碼解讀如下:

L1-3: 創建了一個函數Animal,并在其 this 上定義了屬性:name,name的值是函數被執行時的形參。
L4 : 在 Animal 對象(Animal本身是一個函數對象)上定義了一個靜態屬性:color,并賦值“black”
L5-7:在 Animal 函數的原型對象 prototype 上定義了一個 say() 方法,say方法輸出了 this 的 name 值。
L8: 通過 new 關鍵字創建了一個新對象 cat
L10-14: cat 對象嘗試訪問 name 和 color 屬性,并調用 say 方法。
L16-20: Animal 對象嘗試訪問 name 和 color 屬性,并調用 say 方法。

2、剖析 new 的內部原理

第8行代碼是關鍵:
var cat = new Animal("cat");
Animal 本身是一個普通函數,但當通過new來創建對象時,Animal 就是構造函數。

JS引擎執行這句代碼時,在內部做了很多工作,用偽代碼模擬其內部流程如下:

new Animal("cat") = {

var obj = {};

obj.__proto__ = Animal.prototype;

var result = Animal.call(obj,"cat");

return typeof result === 'object'? result : obj;

}

將上述流程分為 4 個步驟來理解:

【1】創建一個空對象 obj;

【2】把 obj 的proto 指向構造函數 Animal 的原型對象 prototype,此時便建立了 obj 對象的原型鏈:obj->Animal.prototype->Object.prototype->null

【3】在 obj 對象的執行環境調用 Animal 函數并傳遞參數 “ cat ” 。 相當于 var result = obj.Animal("cat")。

     當這句執行完之后,obj 便產生了屬性 name 并賦值為 "cat"。關于 call 的用法請參考:深入理解 call、apply 和 bind

【4】考察第 3 步的返回值,如果無返回值 或者 返回一個非對象值,則將 obj 作為新對象返回;否則會將 result 作為新對象返回。

根據以上過程,我們發現 cat 其實就是【4】的返回值,因此我們對 cat 對象的認知就多了一些:

cat的原型鏈是:cat->Animal.prototype->Object.prototype->null
cat上新增了一個屬性:name
分析完了 cat 的產生過程,我們再分析一下輸出結果:

cat.name : 在【3】中,obj 對象就產生了 name 屬性。因此 cat.name 就是這里的 obj.name
cat.color: cat 對象先查找自身的 color,沒有找到便會沿著原型鏈查找,在上述例子中,我們僅在 Animal 對象上定義了 color,并沒有在其原型鏈上定義,因此找不到。
cat.say: cat會先查找自身的 say 方法,沒有找到便會沿著原型鏈查找,在上述例子中,我們在 Animal 的 prototype 上定義了say,因此在原型鏈上找到了say 方法。
另外,在 say 方法中還訪問 this.name,這里的 this 指的是其調用者 obj,因此輸出的是 obj.name 的值。

對于Animal來說,它本身也是一個對象,因此它在訪問屬性和方法時也遵守上述查找規則,所以:

Animal.color -> " black "
Animal.name -> " Animal "
Animal.say() -> Animal.say is not a function
需要注意的是,Animal 先查找自身的 name,找到了 name,但這個 name 并不是我們定義的 name,而是函數對象內置的屬性,一般情況下,函數對象在產生時會內置 name 屬性并將函數名作為賦值(僅函數對象)。

另外,Animal 在自身沒有找到 say() 方法,也會沿著其原型鏈查找,Animal 的原型鏈如下所示:
Animal.proto
function(){}
Animal.proto == Function.prototype
true
Function.prototype.proto == Object.prototype
true
Object.prototype.proto
null

Animal 的原型鏈: Animal->Function.prototype->Object.prototype->null

由于 Animal 的原型鏈上也沒有定義 say 方法,因此返回異常提示。

3、探索 new 的真正意義
對 new 運算符有了較深入的理解之后,我們再回到開篇提到的問題:在JavaScript 中,萬物皆對象,為什么還要通過 new 來產生對象?

要弄明白這個問題,我們首先要搞清楚 cat 和 Animal 的關系:

【1】cat 繼承了 Animal 對象
通過上面的分析我們發現, cat 通過原型鏈繼承了 Animal 中的部分屬性,因此我們可以簡單的認為:Animal 和 cat 是繼承關系。

【2】cat 是 Animal 的實例
cat 是通過 new 產生的對象,那么 cat 到底是不是 Animal 的實例對象? 我們先來了解一下JS是如何來定義實例對象:

A instanceof B

如果上述表達式為 true,JavaScript 認為 A 是 B 的實例對象,我們用這個方法來判斷一下cat 和 Animal

cat instanceof Animal; //true

從結果看,cat 確實是 Animal 實例,要想更加證實這個結果,我們再來了解一下 instanceof 的內部原理:

var L = A.proto;
var R = B.prototype;
if(L === R)
return true;

如果 A 的proto 等價于 B 的 prototype,就返回true

在 new 的執行過程【2】中,cat 的 proto 指向了Animal 的 prototype,所以 cat 和 Animal 符合 instanceof 的判斷結果。

因此,通過 new 創建的 對象 和 構造函數 之間建立了一條原型鏈,原型鏈的建立,讓原本孤立的對象有了依賴關系和繼承能力,讓JavaScript 對象能以更合適的方式來映射真實世界里的對象,這是面向對象的本質。

4、實戰演練
下面是一個經典例子,涉及 new 、this、以及 原型鏈 相關問題,請看代碼:

function Foo(){
getName = function(){
console.log(1)
}
return this;
}
Foo.getName = function(){
console.log(2)
}
Foo.prototype.getName = function(){
console.log(3)
}
var getName = function(){
console.log(4)
}
function getName(){
console.log(5)
}
//output : ?
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

江油市| 固始县| 洪湖市| 航空| 滦平县| 瑞昌市| 疏附县| 城步| 扶风县| 察隅县| 任丘市| 土默特右旗| 洛浦县| 新密市| 花莲市| 桃园县| 怀远县| 嵩明县| 巢湖市| 雅江县| 崇礼县| 南丹县| 浑源县| 永修县| 简阳市| 犍为县| 兴海县| 洛南县| 西乡县| 会宁县| 巴彦县| 灵璧县| 阿荣旗| 喀喇沁旗| 凤凰县| 张家港市| 建昌县| 镇巴县| 南召县| 绥滨县| 凌云县|