重學《JavaScript 高級程序設計》筆記 第6章對象

第6章 面向對象的程序設計

ECMAScript中沒有類的概念;

1.創建對象-歷史

1.1 創建實例,添加方法和屬性 → 對象字面量

缺點: 使用同一接口創建很多對象,產生大量重復代碼

var person = new Object()
person.name = "Y"
person.age = 18
person.job = "police"person.sayName = function() {alert(this.name)
}

var person = {name = "Y",age = 18,job = "police",sayName = function() {alert(this.name)}    
}

1.2 工廠模式 (返回對象)

缺點: 沒有解決對象識別的問題:怎樣知道一個對象的類型;
特點: 內部創建對象,并返回

function createPerson(name, age, job) {var o = new Object()o.name = nameo.age = ageo.job = jobo.sayName = function () { alert(this.name)}return o
}

1.3 構造函數模式

缺點: 每個方法都要在每個實例上重新創建一遍!不同實例上的同名函數是不相等的,然而,創建2個完成同樣任務的Function實例的確沒有必要。
特點
沒有顯示創建對象;
沒有return;
將方法屬性賦值給this對象;
首字母大寫;
構造函數創建的實例標識為一種特定的類型

1.3.1 理解面試題

調用構造函數創建對象,實際會經歷以下4個步驟:

  1. 創建一個新對象;
  2. 將構造函數的作用域賦值給新對象(this指向這個新對象)
  3. 執行構造函數代碼(為這個新對象添加屬性方法)
  4. 返回新對象
function Person(name, age, job) {this.name = namethis.age = agethis.job = jobthis.sayName = function () { // 每定義一個函數,就是實例化一個對象alert(this.name)}
}
var p1 = new Person("Y",18,"police")
var p2 = new Person("H",8,"teacher")
// p1.constructor == Person
// p2.constructor == Person// ( p1 instanceOf Object  )  true
//  ( p1 instanceOf Person  )  true
// ( p2 instanceOf Object  )  true
//  ( p2 instanceOf Person  )  true
  • 在全局作用域調用函數,this總是指向GLOBAL對象
function person(name, age, job) {this.name = namethis.age = agethis.job = jobthis.sayName = function () { alert(this.name)}
}
person('Leo', 16, 'doctor') 
window.sayName() //leo

1.3.2 將構造函數當做函數

任何函數,只要通過new操作符來調用,便可以作為構造函數;若不用,即與普通函數無異。this會指向Global對象(在瀏覽器中就是window)

1.3.3 將方法定義到構造函數外部

缺點: 在全局作用域上定義的函數,若只能被某個對象調用,不合理;并且,如果對象需要定義很多方法,則需要定義很多個全局函數,對于這個自定義的引用類型就絲毫沒有封裝性可言。

function Person(name, age, job) {this.name = namethis.age = agethis.job = job
}
function sayName() {alert(this.name)
}

1.4 原型模式

1.4.1 理解原型模式

function Person() {}
Person.prototype.name = "Y" 
Person.prototype.age = 18
Person.prototype.job = "police" Person.prototype.sayName = function () {alert(this.name)
}
  1. 使用原型對象的好處:讓所有的對象實例共享它所包含的屬性和方法;
  2. 只要創建了一個新函數,就會為該函數創建一個prototype屬性,指向函數的原型對象
  3. 原型對象會自動獲得constructor屬性,該屬性包含一個指向prototype屬性所在函數的指針(constructor屬性指向構造函數);
  4. 對象的constructor屬性最初是用來表示對象類型的;
  5. 構造函數創建的實例,實例內部包含一個指針,指向構造函數的原型對象
  6. Person.prototype.isPrototypeOf(p1) // true
  7. Object.getPrototypeOf(p1) == Person.prototype // true
  8. 代碼讀取某個對象某個屬性時,先搜索對象實例,若無再搜索原型對象;
  9. 若實例中添加的屬性和原型屬性同名,會屏蔽原型中的屬性(因為實例只能訪問原型中的值,而不能重寫);
  10. 若將實例中的同名屬性設為null,并不能恢復與原型的連接,需要使用delete操作符完全刪除實例屬性
  11. p1.hasOwnProperty("name")// true hasOwnProperty()方法可以檢測一個屬性是存在于實例中還是存在于原型,若來自實例則返回true
    在這里插入圖片描述

1.4.2 in操作符

in操作符會在通過對象能訪問給定屬性時返回true,無論屬性存在于實例還是原型中

"name" in p1 // true

1.4.3 確認屬性存在于原型

function hasPrototypeProperty(object,name) {return !object.hasOwnProperty(name) && (name in object)
}

1.4.4 更簡單的原型語法

缺點: constructor屬性不再指向Person,切斷了實例和原型對象的聯系;對包含引用類型值的屬性,被實例共享會造成問題。
特點: 減少不必要的輸入(每添加一個屬性/方法就要多敲一遍Person.prototype)

將Person.prototype設置為一個以對象字面量形式創建的新對象,本質上重寫了prototype對象(創建函數時自動創建的原型對象),導致constructor屬性指向Object構造函數,盡管instanceof還能返回正確的結果。

function Person() {}
Person.prototype = {name : "Y",age : 18,job : "police",sayName: function () {alert(this.name)}
}
p1 instanceof Object // true
p1 instanceof Person // true
p1.constructor == Person // false
p1.constructor == Object // true

增加constructor屬性,確保該屬性能訪問到適當的值。

function Person() {}
Person.prototype = {constructor : Person,name : "Y",age : 18,job : "police",sayName: function () {alert(this.name)}
}

1.4.5 原生對象的問題

function Person() {}
Person.prototype = {constructor : Person,friends:["Yoona","Jessica"], // 數組,引用類型name : "Y",age : 18,job : "police",sayName: function () {alert(this.name)}
}
p1.friends.push("Krystal")
p1.friends == p2.friends

1.4.6 組合使用構造函數模式和原型模式

構造函數模式用于定義實例屬性,原型模式用于定義方法和共享的屬性。(實例屬性中的引用類型互不干擾)

function Person(name, age, job) {this.name = namethis.age = agethis.job = jobthis.friends = ["Yoona","Jessica"]
}Person.prototype = {constructor : Person,sayName: function () {alert(this.name)}
}

1.4.7 原生對象的原型

通過原生對象的原型,不僅可以取得所有默認方法的引用,也可以定義新方法。但不推薦在產品化的程序中修改原生對象的原型:
如果因為某個實現中缺少某個方法,就在原始對象的原型中添加,那么當在另一個支持該方法的實現中運行代碼時,就可能會導致命名沖突,而且這樣做也可能會意外地重寫原生方法。

1.5 梳理

在這里插入圖片描述

1.6 修改原生對象的原型

String.prototype.startsWith = function(){}

在當前環境中,所有字符串都可以調用startsWith,但不推薦,可能會產生命名沖突,也可能會意外地重寫原生方法。

String.prototype.
toString = function () {console.log('修改原生對象默認方法')
}'str'.toString() // 修改原生對象默認方法

將原生對象原型指向空,沒效果

String.prototype = null
console.log('str'.toString()) // str

2. 屬性類型 P139

2.1 數據屬性

  1. [[Configurable]]:能否通過delete刪除屬性,默認為true
  2. [[Enumerable]]:能否通過for-in循環返回屬性,默認為true
  3. [[Writeable]]:能否修改屬性的值,默認為true
  4. [[Value]]:屬性值,默認為undefined
  • 一旦把屬性定義為不可配置的,就不能再把它變回可配置了;
  • 要修改屬性默認的特性,必須使用Object.defineProperty(),3個參數:對象、屬性名、描述符對象(屬性必須是數據屬性),若不指定數據屬性,則默認為false;

2.2 訪問器屬性

  1. 包含一對getter和setter函數(都不是必須的),有4個特性:
    1) [[Configurable]]
    2) [[Enum而able]]
    3) [[Get]]:讀取屬性時默認調用的函數,默認值undefined
    4) [[Set]]:寫入屬性時默認調用的函數,默認值undefined
  • 屬性 _year 前面的下劃線用于表示只能通過對象方法訪問的屬性;
  • 使用訪問器屬性的常見方式:設置一個屬性的值會導致其他屬性發生變化;

2.3 讀取屬性

Object.getOwnPropertyDescriptor(),2個參數:對象、屬性

var descriptor = Object.getOwnPropertyDescriptor(person,"age")
alert(age.value)
alert(age.enumerable)
alert(age.configurable)
alert(age.get)

方法集合

Object.defineProperty() // 修改屬性默認值
Object.getOwnPropertyDescriptor() //讀取屬性的描述符
誰誰的原型對象.isPrototypeOf(實例) // 參數是實例,判斷實例內部是否有指向構造函數原型對象的指針
hasOwnProperty() // 檢測屬性來自實例(返回true)還是原型

3. 繼承(子類繼承父類的特征和行為)

3.1 原型鏈

原型鏈的問題

  1. P166 原型鏈雖然很強大,可以用它來實現繼承,但它也存在一些問題,其中最主要的問題來自包含引用類型值的原型。包含引用類型值的原型屬性會被所有實例共享,因此要在構造函數,而不是原型對象中定義屬性。
  2. 在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。(沒有辦法在不影響所有對象實例的情況下,給超類型的構造函數傳遞參數)

讓原型對象等于另一個類型的實例。

SubType.prototype = new SuperType()

SubType的實例指向SubType的原型,進而又指向SuperType的原型
在這里插入圖片描述

3.2 默認的原型

所有引用類型默認都繼承了Object,所有函數的默認原型都是Object的實例,因此默認原型都會包含一個內部指針,指向Object.prototype,這也正是所有自定義類型都會繼承toString()、valueOf()等默認方法的根本原因。完整的原型鏈如下:
在這里插入圖片描述

instance instanceof Object // true
instance instanceof SuperType // true
instance instanceof SubType // trueObject.prototype.isPrototypeOf(instance) // true
SuperType.prototype.isPrototypeOf(instance) // true
SubType.prototype.isPrototypeOf(instance) // true
function Fun() {}console.log(Fun.prototype.__proto__==Object.prototype) // true

3.3 組合繼承

  1. 父構造函數內有引用類型屬性值
  2. 子構造函數內使用call(保證了實例不會都指向同一個引用類型)
  3. 子構造函數原型指向父構造函數原型(Object.create
  4. 子構造函數原型里的構造器指向自己(知曉實例由誰創建)
    在這里插入圖片描述

4. 方法整理

  • A.isPrototypeOf(a)
    // 實例a的__proto__指向A的原型
    // 判斷原型對象A是否是實例a的原型,是則返回true
  • a.hasOwnProperty(‘name’) 判斷屬性是否存在于實例中(實例屬性),是則返回true
    Object.keys() 獲得對象上所有可枚舉的屬性
  • ‘name’ in a 無論原型/實例,只要是能訪問得到的屬性,in操作符返回true(包括constructor)'name’字符串
    for-in循環,返回所有能通過對象訪問的、可枚舉的屬性 ,(遍歷一個實例對象,原型上的屬性也會打印、要只打印實例屬性,需要配合hasOwnProperty
  • Object.getOwnPropertyNames(),得到所有實例屬性,包括constructor
function Test(name) {this.name = name
}
Test.prototype.name = 'hhh'
let tObj = new Test('yyy')
console.log('name' in tObj) // true
console.log('constructor' in tObj) // true
for(var prop in tObj){console.log('for-in', prop) // name
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/251344.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251344.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251344.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java-reflect(反射)初步理解_1

27.01_反射(類的加載概述和加載時機) A:類的加載概述 當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,連接,初始化三步來實現對這個類進行初始化。加載 就是指將class文件讀入內存,并為之創建一個…

javascrip --- 構造函數的繼承

兩點需要注意的. 第一是在構造函數聲明時,會同時創建一個該構造函數的原型對象,而該原型對象是繼承自Object的原型對象 // 聲明一個構造函數Rectengle function Rectangle(length, width) {this.length length;this.width width; }// 即:看見function 后面函數名是大寫,一般…

Ruby實例方法和類方法的簡寫

創建: 2017/12/12 類方法 Sample.func實例方法 Sample#func轉載于:https://www.cnblogs.com/lancgg/p/8281677.html

《JavaScript 高級程序設計》筆記 第7章及以后

第7章 函數表達式 匿名函數的name屬性是空字符串;閉包是函數:閉包是有權訪問另一個函數作用域中變量的函數;(P181 副作用,解釋了點擊li彈出循環最后值的原因)當某個函數第一次被調用時,會創建一個執行環境及相應作用域鏈&#xf…

[樹形dp] Jzoj P1046 尋寶之旅

Description 探險隊長凱因意外的弄到了一份黑暗森林的藏寶圖,于是,探險隊一行人便踏上了尋寶之旅,去尋找傳說中的寶藏。藏寶點分布在黑暗森林的各處,每個點有一個值,表示藏寶的價值。它們之間由一些小路相連&#xff0…

javascript --- 使用語法糖class定義函數

本文討論的是通過class聲明的函數,有什么特點,或者說是指向了哪里. class A() {} // A是一個類// 要看class聲明的函數指向哪里,只需將其[[Prototype]]屬性打印到控制臺,下面看看A和它的原型對象的指向 // 注:[[Prototype]]屬性通過__proto__訪問 console.log(A.__proto__…

前端知識點整理收集(不定時更新~)二

目錄 require() 加載文件機制 線程和進程 線程 單線程 Nodejs的線程與進程 網絡模型 初識 TCP 協議 三次握手 I/O I/O 先修知識 阻塞與非阻塞 I/O 同步與異步 I/O Git 基礎命令 分支操作 修改遠程倉庫地址 遠程分支獲取最新的版本到本地 拉取遠程倉庫指定分支…

SpringBoot零基礎入門指南--搭建Springboot然后能夠在瀏覽器返回數據

File->new Project 修改默認包名,根據自己的喜好修改 選擇初始化需要導入的包,盡量不要一開始就導入很多,特別是數據庫,不然啟動可能會有問題,創建好的目錄如下: 配置文件寫在application.properties下&…

JavaScript算法相關

1. 排序 1.1.冒泡排序 每一輪比較&#xff0c;從左至右交換相鄰&#xff0c;每輪結束&#xff0c;最后一個為最大下一輪&#xff0c;需要比較的個數 - 1 j < len - i (范圍動態縮小)共 len - 1 輪比較 function bubbleSort(arr) {var len arr.length;for (var i 1; i &…

javascript --- 編程風格

字符串 const a foobar; const b foo${a}bar; // 此處是反引號(tab鍵上) const c foobar;解構賦值 const [first, second] arr;function getFullName({ firstName, lastName }) { }function processInput(input) {return { left, right, top, bottom }; } const { left…

$ - 字符串內插

$ 特殊字符將字符串文本標識為內插字符串。 內插字符串是可能包含內插表達式的字符串文本。 將內插字符串解析為結果字符串時&#xff0c;帶有內插表達式的項會替換為表達式結果的字符串表示形式。 此功能在 C# 6 及該語言的更高版本中可用。 與使用字符串復合格式設置功能創建…

數據結構基礎知識

排序 參考&#xff1a;https://www.bilibili.com/video/av38482633/?spm_id_fromtrigger_reload 目錄 排序 插入排序 直接插入排序 折半排序 希爾排序 ? 交換排序 冒泡排序 快速排序 選擇排序 堆排序 流量單位計算 什么是計數排序 復雜度分析&#xff1a; 什…

linux中安裝軟件,查看、卸載已安裝軟件方法

各種主流Linux發行版都采用了某種形式的包管理系統&#xff08;PMS&#xff09;來控制軟件和庫的安裝。 軟件包存儲在服務器上&#xff0c;可以利用本地Linux系統上的PMS工具通過互聯網訪問。這些服務器稱為倉庫。 由于Linux發行版眾多,目前還沒有統一的PMS標準工具。 這里分別…

html5 --- 使用javascript腳本控制媒體播放

H5中的標簽(<audio…/> 和 <video…/>)對于JS中的HTMLAudioElement對象和HTMLVideoElement對象 對象有以下幾個方法: play(): 播放 pause(): 暫停播放 load(): 重新裝載音頻、視頻 canPlayType(type): 判斷該元素可播放type類型的音頻、視頻 下面是一個簡單的音樂…

在js中if條件為null/undefined/0/NaN/表達式時,統統被解釋為false,此外均為true

Boolean 表達式 一個值為 true 或者 false 的表達式。如果需要&#xff0c;非 Boolean 表達式也可以被轉換為 Boolean 值&#xff0c;但是要遵循下列規則&#xff1a; 所有的對象都被當作 true。當且僅當字符串為空時&#xff0c;該字符串被當作 false。null 和 undefined 被當…

ES6專題——整理自阮一峰老師的ECMAScript 6入門

這里我僅僅是記錄了那些我認為值得注意的ES6知識點&#xff0c;詳細版請挪步https://es6.ruanyifeng.com/#docs/let let和const命令 let聲明的變量只在它所在的代碼塊有效。 var a []; for (let i 0; i < 10; i) {a[i] function () {console.log(i);}; } a[6](); // 6 …

開發測試比

1.服務器已經開啟了CORS跨域支持 瀏覽器有同源策略限制&#xff1a;協議、域名、端口號其中無法向非同源地址發送ajax請求 跨域解決方法&#xff1a;JSONP&#xff08;只支持get不支持post&#xff09;&#xff0c;不是ajax 凡是有src屬性的標簽都有跨域能力 前端定義一個處理…

map函數用法詳解

map函數是Python內置的高階函數&#xff0c;它是一個典型的函數式編程例子。它的參數為: 一個函數function、一個或多個sequence。通過把函數function依次作用在sequence的每個元素上&#xff0c;得到一個新的sequence并返回。注意&#xff1a;map函數不改變原有的sequence&…

2018暑假集訓測試六總結

拿到試題沒幾分鐘&#xff0c;就有人說會做T1QAQ。第一題感覺似曾相識&#xff0c;其實不同。梳理出本質后發現有兩個限制&#xff0c;便想用枚舉遞推來快速求解&#xff0c;發現要么是不會推&#xff0c;要么是時空超限&#xff0c;不會優化。期間也想過通過離線做&#xff0c…

css3 --- 使用媒體查詢進行響應式布局

css3引入media,可以根據設備特性進行不同的布局, 本文展示的是根據不同屏幕的寬度進行不同的布局,代碼如下: <!DOCTYPE html> <html> <head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title> 針…