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

溫馨提示×

溫馨提示×

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

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

JavaScript原型與繼承實例分析

發布時間:2022-02-21 16:47:35 來源:億速云 閱讀:119 作者:iii 欄目:開發技術

今天小編給大家分享一下JavaScript原型與繼承實例分析的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

首先我們需要知道的是,JavaScript 是一種動態語言,本質上說它是沒有Class(類)的;但是它也需要一種繼承的方式, 那就是原型繼承;JavaScript 對象的一些屬性和方法都是繼承自別的對象。

很多同學對 JavaScript 的原型和繼承不是很理解,一個重要的原因就是大家沒有理解__proto__prototype這兩個屬性的意思。 接下來我們先來好好梳理一下這兩個屬性,看看它們存在哪里,代表了什么意義,又有什么作用。

首先來說一下__proto__這個屬性吧,我們需要知道的是,除了nullundefinedJavaScript中的所有數據類型都有這個屬性; 它表示的意義是:當我們訪問一個對象的某個屬性的時候,如果這個對象自身不存在這個屬性, 那么就從這個對象的__proto__(為了方便下面描述,這里暫且把這個屬性稱作p0)屬性上面 繼續查找這個屬性,如果p0上面還存在__proto__(p1)屬性的話,那么就會繼續在p1上面查找響應的屬性, 直到查找到這個屬性,或者沒有__proto__屬性為止。 

我們把一個對象的__proto__屬性所指向的對象,叫做這個對象的原型;我們可以修改一個對象的原型來讓這個對象擁有某種屬性,或者某個方法。

// 修改一個Number類型的值的原型
const num = 1;
num.__proto__.name = "My name is 1";
console.log(num.name); // My name is 1

// 修改一個對象的原型
const obj = {};
obj.__proto__.name = "dreamapple";
console.log(obj.name); // dreamapple

這里需要特別注意的是,__proto__這個屬性雖然被大多數的瀏覽器支持,但是其實它僅在ECMAScript 2015 規范中被準確的定義, 目的是為了給這個傳統的功能定制一個標準,以確保瀏覽器之間的兼容性。通過使用__proto__屬性來修改一個對象的原型是非常慢且影響性能的一種操作。 所以,現在如果我們想要獲取一個對象的原型,推薦使用Object.getPrototypeOf 或者Reflect.getPrototypeOf,設置一個對象的原型推薦使用Object.setPrototypeOf或者是Reflect.setPrototypeOf

到這里為止,我們來對__proto__屬性做一個總結:

  • 存在哪里? 除了nullundefined所有其他的JavaScript對象或者原始類型都有這個屬性

  • 代表了什么? 表示了一個對象的原型

  • 有什么作用? 可以獲取和修改一個對象的原型

說完__proto__屬性,接下來我們就要好好的來理解一下prototype屬性了;首先我們需要記住的是,這個屬性一般只存在于函數對象上面; 只要是能夠作為構造器的函數,他們都包含這個屬性。也就是說,只要這個函數能夠通過使用new操作符來生成一個新的對象, 那么這個函數肯定具有prototype屬性。因為我們自定義的函數都可以通過new操作符生成一個對象,所以我們自定義的函數都有prototype 這個屬性。

// 函數字面量
console.log((function(){}).prototype); // {constructor: ?}

// Date構造器
console.log(Date.prototype); // {constructor: ?, toString: ?, toDateString: ?, toTimeString: ?, toISOString: ?, …}

// Math.abs 不是構造器,不能通過new操作符生成一個新的對象,所以不含有prototype屬性
console.log(Math.abs.prototype); // undefined

那這個prototype屬性有什么作用呢?這個prototype屬性的作用就是:函數通過使用new操作符生成的一個對象, 這個對象的原型(也就是__proto__)指向該函數的prototype屬性。 那么一個比較簡潔的表示__proto__prototype 屬性之間關系的等式也就出來了,如下所示:

// 其中F表示一個自定義的函數或者是含有prototype屬性的內置函數
new F().__proto__ === F.prototype // true

看到上面等式,我想大家對于__proto__prototype之間關系的理解應該會更深一層了。

好,接下來我們對prototype屬性也做一個總結:

  • 存在哪里? 自定義的函數,或者能夠通過new操作符生成一個對象的內置函數

  • 代表了什么? 它表示了某個函數通過new操作符生成的對象的原型

  • 有什么作用? 可以讓一個函數通過new操作符生成的許多對象共享一些方法和屬性

其實到這里為止,關于JavaScript的原型和繼承已經講得差不多了;下面的內容是一些基于上面的一些拓展, 可以讓你更好地理解我們上面所說的。

當我們理解了上面的知識點之后,我們就可以對下面的表達式做一個判斷了:

// 因為Object是一個函數,函數的構造器都是Function
Object.__proto__ === Function.prototype // true

// 通過函數字面量定義的函數的__proto__屬性都指向Function.prototype
(function(){}).__proto__ === Function.prototype // true

// 通過對象字面量定義的對象的__proto__屬性都是指向Object.prototype
({}).__proto__ === Object.prototype // true

// Object函數的原型的__proto__屬性指向null
Object.prototype.__proto__ === null // true

// 因為Function本身也是一個函數,所以Function函數的__proto__屬性指向它自身的prototype
Function.__proto__ === Function.prototype // true

// 因為Function的prototype是一個對象,所以Function.prototype的__proto__屬性指向Object.prototype
Function.prototype.__proto__ === Object.prototype // true

如果你能夠把上面的表達式都梳理清楚的話,那么說明你對這部分知識掌握的還是不錯的。

談及JavaScript的原型和繼承,那么我們還需要知道另一個概念;那就是constructor,那什么是constructor呢? constructor表示一個對象的構造函數,除了nullundefined以外,JavaScript中的所有數據類型都有這個屬性; 我們可以通過下面的代碼來驗證一下:

null.constructor // Uncaught TypeError: Cannot read property 'constructor' of null ...
undefined.constructor // Uncaught TypeError: Cannot read property 'constructor' of undefined ...

(true).constructor // ? Boolean() { [native code] }
(1).constructor // ? Number() { [native code] }
"hello".constructor // ? String() { [native code] }

但是其實上面這張圖的表示并不算準確,因為一個對象的constructor屬性確切地說并不是存在這個對象上面的; 而是存在這個對象的原型上面的(如果是多級繼承需要手動修改原型的constructor屬性,見文章末尾的代碼),我們可以使用下面的代碼來解釋一下:

const F = function() {};
// 當我們定義一個函數的時候,這個函數的prototype屬性上面的constructor屬性指向自己本身
F.prototype.constructor === F; // true

關于constructor還有一些需要注意的問題,對與JavaScript的原始類型來說,它們的constructor屬性是只讀的,不可以修改。 我們可以通過下面的代碼來驗證一下:

(1).constructor = "something";
console.log((1).constructor); // 輸出 ? Number() { [native code] }

當然,如果你真的想更改這些原始類型的constructor屬性的話,也不是不可以,你可以通過下面的方式來進行修改:

Number.prototype.constructor = "number constructor";
(1).constructor = 1;
console.log((1).constructor); // 輸出 number constructor

當然上面的方式我們是不推薦你在真實的開發中去使用的,接下來,我會使用一些代碼來把今天講解的知識再大致的回顧一下:

function Animal(name) {
  this.name = name;
}

Animal.prototype.setName = function(name) {
  this.name = name;
};
Animal.prototype.getName = function(name) {
  return this.name;
};

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);

// 因為上面的語句將我們原來的prototype的指向修改了,所以我們要重新定義Dog的prototype屬性的constructor屬性
Reflect.defineProperty(Dog.prototype, "constructor", {
  value: Dog,
  enumerable: false, // 不可枚舉
  writable: true
});

const animal = new Animal("potato");
console.log(animal.__proto__ === Animal.prototype); // true
console.log(animal.constructor === Animal); // true
console.log(animal.name); // potato

const dog = new Dog("potato", "labrador");
console.log(dog.name); // potato
console.log(dog.breed); // labrador
console.log(dog.__proto__ === Dog.prototype); // true
console.log(dog.constructor === Dog); // true

以上就是“JavaScript原型與繼承實例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

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

AI

合阳县| 龙州县| 高雄市| 永丰县| 陆良县| 平远县| 凤庆县| 澜沧| 台山市| 敦化市| 镇赉县| 鹿邑县| 新宁县| 三河市| 定州市| 米林县| 临湘市| 蓬莱市| 乌鲁木齐县| 陆川县| 鄂托克前旗| 海南省| 东莞市| 绵阳市| 萍乡市| 东至县| 当涂县| 武邑县| 福贡县| 阳山县| 铜山县| 甘肃省| 商南县| 亳州市| 凤翔县| 南平市| 达尔| 蒙山县| 酉阳| 乐安县| 汉阴县|