自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JavaScript 中的面向?qū)ο?/h1>

開(kāi)發(fā) 前端
JavaScript 語(yǔ)言本身的設(shè)計(jì)缺陷,誤打誤撞,成了解釋最為徹底的“世界原本的樣子”的計(jì)算機(jī)編程語(yǔ)言;

[[430327]]

本文轉(zhuǎn)載自微信公眾號(hào)「勾勾的前端世界」,作者西嶺。轉(zhuǎn)載本文請(qǐng)聯(lián)系勾勾的前端世界公眾號(hào)。

回憶一下什么是對(duì)象:Coding 第一奧義:面向?qū)ο缶幊?/a>

JavaScript 語(yǔ)言本身的設(shè)計(jì)缺陷,誤打誤撞,成了解釋最為徹底的“世界原本的樣子”的計(jì)算機(jī)編程語(yǔ)言;

——西嶺《凡人凡語(yǔ)》

Everything is object (萬(wàn)物皆對(duì)象),JS 語(yǔ)言中將一切都視為 對(duì)象 。

JavaScript 語(yǔ)言的對(duì)象體系,不基于“類(lèi)” 創(chuàng)建對(duì)象,是基于構(gòu)造函數(shù)(constructor)和原型鏈(prototype)。

簡(jiǎn)單方式創(chuàng)建對(duì)象

我們可以直接通過(guò) new Object() 創(chuàng)建:

  1. var person = new Object() 
  2. person.name = 'Jack' 
  3. person.age = 18 
  4.  
  5. person.sayName = function () { 
  6.     console.log(this.name

字面量方式創(chuàng)建對(duì)象

每次創(chuàng)建通過(guò) new Object() 比較麻煩,所以可以通過(guò)它的簡(jiǎn)寫(xiě)形式對(duì)象字面量來(lái)創(chuàng)建:

  1. var person = { 
  2.   name'Jack'
  3.   age: 18, 
  4.   sayName: function () { 
  5.     console.log(this.name
  6.   } 

構(gòu)造函數(shù)

JavaScript 語(yǔ)言使用構(gòu)造函數(shù)作為對(duì)象的模板。

所謂 "構(gòu)造函數(shù)",就是一個(gè)普通的函數(shù),只不過(guò)我們專(zhuān)門(mén)用它來(lái)生成對(duì)象,這樣使用的函數(shù),就是構(gòu)造函數(shù)。

它提供模板,描述對(duì)象的基本結(jié)構(gòu)。一個(gè)構(gòu)造函數(shù),可以生成多個(gè)對(duì)象,這些對(duì)象都有相同的結(jié)構(gòu)。

  1. function Person (name, age) { 
  2.   this.name = name 
  3.   this.age = age 
  4.   this.sayName = function () { 
  5.     console.log(this.name
  6.   } 
  7.  
  8. var p1 = new Person('Jack', 18) 
  9. p1.sayName() // => Jack 
  10.  
  11. var p2 = new Person('Mike', 23) 
  12. p2.sayName() // => Mike 

解析構(gòu)造函數(shù)代碼的執(zhí)行

在上面的示例中,使用 new 操作符創(chuàng)建 Person 實(shí)例對(duì)象;

以這種方式調(diào)用構(gòu)造函數(shù)會(huì)經(jīng)歷以下 5 個(gè)步驟:

  • 創(chuàng)建一個(gè)空對(duì)象,作為將要返回的對(duì)象實(shí)例。
  • 將這個(gè)空對(duì)象的原型,指向構(gòu)造函數(shù)的prototype屬性。先記住,后面講
  • 將這個(gè)空對(duì)象賦值給函數(shù)內(nèi)部的this關(guān)鍵字。
  • 執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼。
  • 返回新對(duì)象 (this)
  1. function Person (name, age) { 
  2.   // 當(dāng)使用 new 操作符調(diào)用 Person() 的時(shí)候,實(shí)際上這里會(huì)先創(chuàng)建一個(gè)對(duì)象 
  3.   // 然后讓內(nèi)部的 this 指向新創(chuàng)建的對(duì)象 
  4.   // 接下來(lái)所有針對(duì) this 的操作實(shí)際上操作的就是剛創(chuàng)建的這個(gè)對(duì)象 
  5.  
  6.   this.name = name 
  7.   this.age = age 
  8.   this.sayName = function () { 
  9.     console.log(this.name
  10.   } 
  11.  
  12.   // 在函數(shù)的結(jié)尾處會(huì)將 this 返回,也就是這個(gè)新對(duì)象 

構(gòu)造函數(shù)和實(shí)例對(duì)象的關(guān)系

構(gòu)造函數(shù)是根據(jù)具體的事物抽象出來(lái)的抽象模板,實(shí)例對(duì)象是根據(jù)抽象的構(gòu)造函數(shù)模板得到的具體實(shí)例對(duì)象。

實(shí)例對(duì)象由構(gòu)造函數(shù)而來(lái),一個(gè)構(gòu)造函數(shù)可以生成很多具體的實(shí)例對(duì)象,而每個(gè)實(shí)例對(duì)象都是獨(dú)一無(wú)二的。

每個(gè)對(duì)象都有一個(gè) constructor 屬性,該屬性指向創(chuàng)建該實(shí)例的構(gòu)造函數(shù)。

反推出來(lái),每一個(gè)對(duì)象都有其構(gòu)造函數(shù)

  1. console.log(p1.constructor === Person) // => true 
  2. console.log(p2.constructor === Person) // => true 
  3. console.log(p1.constructor === p2.constructor) // => true 

因此,我們可以通過(guò)實(shí)例對(duì)象的 constructor 屬性判斷實(shí)例和構(gòu)造函數(shù)之間的關(guān)系。

構(gòu)造函數(shù)存在的問(wèn)題

以構(gòu)造函數(shù)為模板,創(chuàng)建對(duì)象,對(duì)象的屬性和方法都可以在構(gòu)造函數(shù)內(nèi)部定義。

  1. function Cat(name, color) { 
  2.   this.name = name
  3.   this.color = color; 
  4.   this.say = function () { 
  5.     console.log('hello'+this.name,this.color); 
  6.   }; 
  7. var cat1 = new Cat('貓''白色');  
  8. var cat2 = new Cat('貓''黑色');  
  9. cat1.say(); 
  10. cat2.say(); 

在該示例中,從表面上看好像沒(méi)什么問(wèn)題,但是實(shí)際上這樣做,有一個(gè)很大的弊端。那就是對(duì)于每一個(gè)實(shí)例對(duì)象, name 和 say 都是一模一樣的內(nèi)容,每一次生成一個(gè)實(shí)例,都必須為重復(fù)的內(nèi)容,多占用一些內(nèi)存,如果實(shí)例對(duì)象很多,會(huì)造成極大的內(nèi)存浪費(fèi)。

那么,能不能將相同的內(nèi)容,放到公共部分,節(jié)約計(jì)算機(jī)資源呢?

原型

JavaScript 的每個(gè)對(duì)象都會(huì)繼承一個(gè)父級(jí)對(duì)象,父級(jí)對(duì)象稱(chēng)為 原型 (prototype) 對(duì)象。

原型也是一個(gè)對(duì)象,原型對(duì)象上的所有屬性和方法,都能被子對(duì)象 (派生對(duì)象) 共享,通過(guò)構(gòu)造函數(shù)生成實(shí)例對(duì)象時(shí),會(huì)自動(dòng)為實(shí)例對(duì)象分配原型對(duì)象。而每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性,這個(gè)屬性就是實(shí)例對(duì)象的原型對(duì)象。

null 沒(méi)有自己的原型對(duì)象。

這也就意味著,我們可以把所有對(duì)象實(shí)例需要共享的屬性和方法直接定義在構(gòu)造函數(shù)的 prototype 屬性上,也就是實(shí)例對(duì)象的原型對(duì)象上。

  1. function Cat(color) { 
  2.   this.color = color; 
  3.  
  4. Cat.prototype.name = "貓"
  5. Cat.prototype.sayhello = function(){ 
  6.     console.log('hello'+this.name,this.color); 
  7. Cat.prototype.saycolor = function (){ 
  8.     console.log('hello'+this.color); 
  9.  
  10. var cat1 = new Cat('白色');  
  11. var cat2 = new Cat('黑色');  
  12. cat1.sayhello(); 
  13. cat2.saycolor(); 

這時(shí)所有實(shí)例對(duì)象的 name 屬性和 sayhello() 、saycolor 方法,其實(shí)都是在同一個(gè)內(nèi)存地址的對(duì)象中,也就是構(gòu)造函數(shù)的 prototype 屬性上,因此就提高了運(yùn)行效率節(jié)省了內(nèi)存空間。

原型及原型鏈

構(gòu)造函數(shù)的 prototyp 屬性,就是由這個(gè)構(gòu)造函數(shù) new 出來(lái)的所有實(shí)例對(duì)象的 原型對(duì)象

所有對(duì)象都有原型對(duì)象。

  1. function Cat(name, color) { 
  2.     this.name = name
  3.  } 
  4.  
  5. var cat1 = new Cat('貓'); 
  6.  
  7. console.log(cat1.__proto__.__proto__.__proto__); 

而原型對(duì)象中的屬性和方法,都可以被實(shí)例對(duì)象直接使用。

每當(dāng)代碼讀取某個(gè)對(duì)象的某個(gè)屬性時(shí),都會(huì)執(zhí)行一次搜索,目標(biāo)是具有給定名字的屬性。

  • 搜索首先從對(duì)象實(shí)例本身開(kāi)始
  • 如果在實(shí)例中找到了具有給定名字的屬性,則返回該屬性的值
  • 如果沒(méi)有找到,則繼續(xù)搜索指針指向的原型對(duì)象,在原型對(duì)象中查找具有給定名字的屬性
  • 如果在原型對(duì)象中找到了這個(gè)屬性,則返回該屬性的值
  • 如果還是找不到,就到原型的原型去找,依次類(lèi)推。
  • 如果直到最頂層的Object.prototype還是找不到,則返回undefined。

而這正是多個(gè)對(duì)象實(shí)例共享原型所保存的屬性和方法的基本原理。

對(duì)象的屬性和方法,有可能是定義在自身內(nèi),也有可能是定義在它的原型對(duì)象上。由于原型本身也是對(duì)象,又有自己的原型,所以形成了一條可向上追溯的鏈條,叫 原型鏈(prototype chain)。

注意,不在要原型上形成多層鏈?zhǔn)讲檎?,非常浪費(fèi)資源。

內(nèi)置標(biāo)準(zhǔn)庫(kù)與包裝對(duì)象

在內(nèi)置標(biāo)準(zhǔn)對(duì)象中,對(duì)象是 JavaScript 語(yǔ)言最主要的數(shù)據(jù)類(lèi)型,三種原始類(lèi)型的值——數(shù)值、字符串、布爾值——在一定條件下,也會(huì)自動(dòng)轉(zhuǎn)為對(duì)象,也就是原始類(lèi)型的“包裝對(duì)象”(wrapper)。

所謂“包裝對(duì)象”,就是分別與數(shù)值、字符串、布爾值相對(duì)應(yīng)的Number、String、Boolean三個(gè)原生對(duì)象。這三個(gè)原生對(duì)象可以把原始類(lèi)型的值變成(包裝成)對(duì)象。

  1. var v1 = new Number(123); 
  2. var v2 = new String('abc'); 
  3. var v3 = new Boolean(true); 
  4.  
  5. typeof v1 // "object" 
  6. typeof v2 // "object" 
  7. typeof v3 // "object" 
  8.  
  9. v1 === 123 // false 
  10. v2 === 'abc' // false 
  11. v3 === true // false 

包裝對(duì)象的最大目的,首先是使得 JavaScript 的對(duì)象涵蓋所有的值,其次使得原始類(lèi)型的值可以方便地調(diào)用某些方法。

原始類(lèi)型的值,可以自動(dòng)當(dāng)作對(duì)象調(diào)用,即調(diào)用各種對(duì)象的方法和參數(shù)。

這時(shí),JavaScript 引擎會(huì)自動(dòng)將原始類(lèi)型的值轉(zhuǎn)為包裝對(duì)象實(shí)例,在使用后立刻銷(xiāo)毀實(shí)例。

比如,字符串可以調(diào)用length屬性,返回字符串的長(zhǎng)度。

  1. 'abc'.length // 3 

上面代碼中,abc是一個(gè)字符串,本身不是對(duì)象,不能調(diào)用length屬性。JavaScript 引擎自動(dòng)將其轉(zhuǎn)為包裝對(duì)象,在這個(gè)對(duì)象上調(diào)用length屬性。調(diào)用結(jié)束后,這個(gè)臨時(shí)對(duì)象就會(huì)被銷(xiāo)毀。這就叫原始類(lèi)型與實(shí)例對(duì)象的自動(dòng)轉(zhuǎn)換。

 

責(zé)任編輯:武曉燕 來(lái)源: 勾勾的前端世界
相關(guān)推薦

2009-06-10 22:06:29

JavaScript面向?qū)ο?/a>

2017-04-21 09:07:39

JavaScript對(duì)象編程

2012-01-17 09:34:52

JavaScript

2018-12-19 19:30:46

JavaScript創(chuàng)建對(duì)象前端

2012-02-27 09:30:22

JavaScript

2012-12-25 10:51:39

IBMdW

2011-05-13 11:05:52

javascript

2011-05-25 10:21:44

Javascript

2011-05-25 11:15:02

Javascript繼承

2011-05-13 12:38:58

javascript

2011-05-13 09:58:46

javascript

2011-05-13 10:51:25

javascript

2011-05-13 11:17:18

javascript

2011-05-13 11:27:59

javascript

2011-05-25 10:59:26

Javascript繼承

2012-03-13 16:39:52

Java

2009-07-14 16:51:50

Jython中的對(duì)象

2010-10-08 09:13:15

oop模式JavaScript

2011-06-28 14:11:33

JavaScript

2022-08-15 15:39:23

JavaScript面向?qū)ο?/a>數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)