摘要:實(shí)例中的指針僅指向原型,而不指向構(gòu)造函數(shù)。調(diào)用構(gòu)造函數(shù)時(shí)會(huì)為實(shí)例添加一個(gè)指向最初原型的或者而把原型修改為另外一個(gè)對(duì)象就等于切斷了構(gòu)造函數(shù)與最初原型之間的聯(lián)系。
面向?qū)ο蟮某绦蛟O(shè)計(jì)
ECMA-262定義對(duì)象:無序?qū)傩缘募?,其屬性可以包含基本值,?duì)象或者函數(shù)。
普通理解:對(duì)象是一組沒有特定順序的值。
對(duì)象的每個(gè)屬性或方法都有一個(gè)名字,而每個(gè)名字都映射一個(gè)值。
每個(gè)對(duì)象都是基于一個(gè)引用類型創(chuàng)建的。
理解對(duì)象屬性類型
在定義只有內(nèi)部的特征(attribute)時(shí),描述了屬性(property)的各種特征。
是為了實(shí)現(xiàn)JavaScript引擎用的,在JavaScript中不能直接訪問他們。
為了表示特性是內(nèi)部值,把它們放在了兩對(duì)方括號(hào)中. 例如: [[Enumerable]]
ECMAScript中有兩種屬性:數(shù)據(jù)屬性和訪問器屬性。
數(shù)據(jù)屬性
數(shù)據(jù)屬性包含一個(gè)數(shù)據(jù)值的位置。在這個(gè)位置可以讀取和寫入值。數(shù)據(jù)屬性有4個(gè)描述行為的特性
[[Configurable]]: 能否通過delete刪除屬性從而重新定義屬性,能夠修改屬性的特性,或者能否把屬性修改為訪問屬性。 默認(rèn)值:false;(不可以重新定義或刪除)
[[Enmuerable]]: 能夠通過for-in循環(huán)返回屬性。(是否可以被枚舉).默認(rèn)值:false;(不可以被枚舉)
[[Writable]]: 能否修改屬性的值。默認(rèn)值:false,(不可以被修改)
[[Value]]:包含這個(gè)屬性的數(shù)據(jù)值,讀取屬性的時(shí)候,從這個(gè)位置讀;寫入屬性值的時(shí)候,把新值保存在這個(gè)位置。默認(rèn)值:undefiend.
var Person = { name: "Nicholas" } // 創(chuàng)建name屬性。為它置頂?shù)闹凳恰癗icholas”。也就是[[Value]]被設(shè)置了"Nicholas",而對(duì)這個(gè)值的任何修改都將反映在這個(gè)位置。
Object.defineOProperty();
作用:修改屬性默認(rèn)特性
參數(shù)1:屬性所在的對(duì)象
參數(shù)2:屬性的名字
參數(shù)3:一個(gè)描述符對(duì)象
描述符(descriptor)對(duì)象的屬性必須是:configurable,enumerable,writable,value.
設(shè)置其中一個(gè)或多個(gè)值,可以修改對(duì)應(yīng)的特性值。
var Person = {}; Object.defineProperty(Person, "name", { writable: false, value: "Nicholas" }); alert(Person.name); //"Nicholas" Person.name = "Greg"; // 設(shè)置成只讀的,屬性是不可修改的。 alert(Person.name); //"Nicholas"
constructor屬性,是無法被枚舉的. 正常的for-in循環(huán)是無法枚舉. [eable = false];
Object.getOwnPropertyNames(); //枚舉對(duì)象所有的屬性:不管該內(nèi)部屬性能夠被枚舉.
//3個(gè)參數(shù), 參數(shù)1:重新設(shè)置構(gòu)造的對(duì)象 (給什么對(duì)象設(shè)置) 參數(shù)2:設(shè)置什么屬性 參數(shù)3:options配置項(xiàng) (要怎么去設(shè)置) Object.defineProperty(Person.prototype,"constructor",{ enumerable: false, //是否是 能夠 被枚舉 value: Person //值 構(gòu)造器的 引用 });
訪問器屬性
訪問器屬性不包含數(shù)據(jù)值,包含一堆geter() 和setter(); 函數(shù) (這兩個(gè)函數(shù)都不是必須的)
在讀取訪問器屬性時(shí),會(huì)調(diào)用getter(); 這個(gè)函數(shù)負(fù)責(zé)返回有效值,在寫入訪問器屬性時(shí),會(huì)調(diào)用setter()函數(shù)并傳入新值,這個(gè)函數(shù)負(fù)責(zé)決定如何處理數(shù)據(jù)。
訪問器屬性的4個(gè)特性:
[[Configurable]]: 能夠通過delete刪除屬性從而定義新的屬性,能否修改屬性的特性,或者能否把屬性修改為數(shù)據(jù)屬性。默認(rèn)值:false; (不可重新定義,和刪除屬性)
[[Enmuerable]]:能否通過for-in循環(huán)返回屬性。默認(rèn)值:false;(不可被枚舉)
[[Get]]: 在讀取屬性時(shí)調(diào)用的函數(shù)。默認(rèn)值為:undefeind
[[Set]]: 在寫入屬性時(shí)調(diào)用的函數(shù)。默認(rèn)值為:undefiend
訪問器屬性不能直接定義,必須使用Object.defineProperty();來定義。
var book = { _year: 2016, edition: 1 }; Object.defineProperty(book, "year", { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2016) { this._year = newValue; this.edition += newValue - 2016; } } }); book.year = 2020; alert(book.edition); // 5 // _year前面的下劃線是一種常用的記號(hào),用于表示只能通過對(duì)象方法訪問的屬性。
定義多個(gè)屬性
Object.defineProperties();
定義多個(gè)屬性。
參數(shù)1:對(duì)象要添加和修改其屬性的對(duì)象
參數(shù)2:對(duì)象的屬性與第一個(gè)對(duì)象中要添加或修改的屬性一一對(duì)應(yīng).
var book = {}; Object.defineProperties(book, { _year: { value: 2016 }, edition: { value: 1 }, year: { get: function () { return this._year; }, set: function (newValue) { this._year = newValue; } } });
讀取屬性的特性
Object.getOwnPropertyDescriptor()
取得給定屬性的描述符.
參數(shù)1:屬性所在的對(duì)象
參數(shù)2:要讀取其描述符的屬性名稱
返回值:對(duì)象。如果是訪問器屬性,這個(gè)對(duì)象含有:configurable,enumerable,get和set
如果是數(shù)據(jù)屬性,這個(gè)對(duì)象含有:configureable,enumerbale,writeable,value
工廠模式
解決:創(chuàng)建多個(gè)相似對(duì)象。(未解決:對(duì)象識(shí)別的問題-怎么知道一個(gè)對(duì)象的類型)
function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson("Nicholas", 29, "Software Engineer"); var person2 = createPerson("Greg", 27, "Doctor");
構(gòu)造函數(shù)模式
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");
沒有顯示的創(chuàng)建對(duì)象
直接將屬性和方法賦給this對(duì)象
沒有reutrn語句
創(chuàng)建實(shí)例會(huì)經(jīng)過:
創(chuàng)建一個(gè)對(duì)象
將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此this就指向了這個(gè)新對(duì)象)
執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性)
返回新對(duì)象
對(duì)象的 constructor 屬性最初是用來表示對(duì)象類型。
提到檢測對(duì)象類型,還是使用instanceof操作符要更可靠。
將構(gòu)造函數(shù)當(dāng)作函數(shù)
構(gòu)造函數(shù)與其它函數(shù)的唯一區(qū)別,在于調(diào)用它們的方式不同。
構(gòu)造函數(shù)也是函數(shù),不存在定義構(gòu)造函數(shù)的語法。任何函數(shù),只要通過new操作來調(diào)用,就可以作為構(gòu)造函數(shù)。
任何函數(shù),如果不通過new操作符來調(diào)用,就跟普通函數(shù)沒什么不同。
構(gòu)造函數(shù)的問題
每個(gè)方法都要在每個(gè)實(shí)例上重新創(chuàng)建
通過原型模式來解決
原型模式
每個(gè)函數(shù)都有一個(gè) prototype (原型)屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象,
而這個(gè)對(duì)象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法
每個(gè)函數(shù)都有一個(gè)prototype(原型)屬性,這個(gè)屬性石一個(gè)指針,指向一個(gè)對(duì)象,而這個(gè)對(duì)象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法。
字面的理解:prototype就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型。
讓所有對(duì)象實(shí)例共享它所有包含的屬性和方法。不必在構(gòu)造函數(shù)中定義對(duì)象實(shí)例的信息,而是將這些信息直接添加到原型中。
理解原型對(duì)象
只要?jiǎng)?chuàng)建了一個(gè)函數(shù),就會(huì)根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個(gè)prototype屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。
默認(rèn)情況下:所有原型對(duì)象都會(huì)自動(dòng)獲得一個(gè)constructor(構(gòu)造函數(shù))屬性,這個(gè)屬性包含一個(gè)指向prototype屬性所在函數(shù)的指針。
創(chuàng)建了自定義的構(gòu)造函數(shù)之后,其原型對(duì)象默認(rèn)只會(huì)取得constructor屬性。
當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例后,該實(shí)例的內(nèi)部將包含一個(gè)指針(內(nèi)部屬性),指向構(gòu)造函數(shù)的原型對(duì)象。
原型鏈查找:
每當(dāng)代碼讀取某個(gè)對(duì)象的某個(gè)屬性時(shí),都會(huì)執(zhí)行一次搜索,目標(biāo)是具有給定名字的屬性。搜索首先從對(duì)象實(shí)例本身開始。如果在實(shí)例中找到了具有給定名字的屬性,則返回該屬性的值,如果沒有找到,則繼續(xù)搜索指針指向的原型對(duì)象,在原型對(duì)象中查找具有給定名字的屬性。如果在原型對(duì)戲那個(gè)中找到這屬性,則返回該屬性的值。
可以通過對(duì)象實(shí)例訪問保存在原型中的值,但卻不能通過對(duì)象實(shí)例重寫原型中的值,如果在實(shí)例中添加了一個(gè)屬性,而該屬性與實(shí)例原型中的一個(gè)屬性同名,那在實(shí)例中創(chuàng)建該屬性,該屬性將會(huì)屏蔽原型中的那個(gè)屬性。
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name = "Greg"; alert(person1.name); //"Greg" —— 來自實(shí)例的name alert(person2.name); //"Nicholas" -- 來自原型中的name
當(dāng)為對(duì)象實(shí)例添加一個(gè)屬性時(shí),這個(gè)屬性就會(huì)屏蔽原型對(duì)象中保存的同名屬性。添加這個(gè)屬性只會(huì)組織訪問原型中的那個(gè)屬性,但不會(huì)修改那個(gè)屬性。即使將這個(gè)屬性設(shè)置為null,也只會(huì)在實(shí)例中設(shè)置這個(gè)屬性,而不會(huì)恢復(fù)其指向原型的連接??梢允褂胐elete操作符可以完全刪除實(shí)例屬性。
hasOwnProperty() // 從Object繼承而來的方法
檢測一個(gè)屬性是否存在于實(shí)例中,還是存在于原型。
判斷一個(gè)對(duì)象屬性 是屬于 原型屬性 還是屬于 實(shí)例屬性
在實(shí)例中,返回true
在原型上,返回false
function Person() {} Person.prototype.name = "Nicholas"; var p1 = new Person(); console.log(p1.hasOwnProperty("name")); // false
原型與in操作符
in 操作符,通過對(duì)象能夠訪問給定屬性時(shí)返回true,無論是在實(shí)例中還是原型中。能夠訪問到,就返回true.
同時(shí)使用hasOwnProperty(); 和 in操作符 : 確定是屬性存在實(shí)例中,還是原型中。
// 判斷屬于原型上的屬性 function hasPrototypeProperty( obj, attr ) { return !obj.hasOwnProperty(attr) && attr in obj; }
Object.keys()
參數(shù):接收一個(gè)對(duì)象作為參數(shù),返回一個(gè)包含所有可枚舉的屬性的字符串?dāng)?shù)組。
function Person() {} Person.prototype.name = "Nicholas"; Person.prototype.age = 20; var p1 = new Person(); var keys = Object.keys(Person.prototype); console.log(keys); // ["name", "age"]
更簡單的原型方法
function Person() {} Person.prototype = {}
將Person.prototype設(shè)置為等于一個(gè)對(duì)象字面量形式創(chuàng)建的新對(duì)象。
會(huì)造成constructro屬性不再指向Person。
每創(chuàng)建一個(gè)函數(shù),就會(huì)同時(shí)創(chuàng)建它的peorotype,這個(gè)對(duì)象也會(huì)自動(dòng)獲得constructro屬性。直接賦值為一個(gè)字面量形式,本質(zhì)上是完全重寫了默認(rèn)的prottoype對(duì)象,因此constructor屬性也就變成新的對(duì)象的constructor屬性(指向Object構(gòu)造函數(shù)) 不再指向Person函數(shù)。
通過instanceof操作符能夠返回正確的結(jié)果,但是通過constructor已經(jīng)無法確定對(duì)象的類型了。
可以手動(dòng)設(shè)置回constructor屬性為當(dāng)前的類
function Person () {} Person.prototype = { constructor: Person, name: "Nicholas" }
這種方式重設(shè)constructor屬性會(huì)導(dǎo)致它的[[Enumerable]]特性被設(shè)置為true
constructor是不可被枚舉,可以通過Object.definePropert();修改特性,重置構(gòu)造函數(shù)。
Object.defineProperty(Person.protype, "constructor", function () { enmuerable: false, value: Person });
原型動(dòng)態(tài)
由于在原型中查找值的過程是一次搜索,對(duì)原型對(duì)象所做的任何修改都能夠立即從實(shí)例上反應(yīng)出來,即使是先創(chuàng)建了實(shí)例后修改原型也是一樣。
實(shí)例中的指針僅指向原型,而不指向構(gòu)造函數(shù)。
可以隨時(shí)為原型添加屬性和方法,并且修改能夠立即在所有對(duì)象實(shí)例中反映出來,但如果是重寫了這個(gè)原型對(duì)象,那么就不一樣。
調(diào)用構(gòu)造函數(shù)時(shí)會(huì)為實(shí)例添加一個(gè)指向最初原型的[[Prototype]] 或者_(dá)_proto__ .而把原型修改為另外一個(gè)對(duì)象就等于切斷了構(gòu)造函數(shù)與最初原型之間的聯(lián)系。
function Person () {} var firend = new Person(); Person.prototype = { constructor: Person, name: "Nicholas", sayName: function () { console.log(this.name); } } firend.sayName(); // error // friend 指向的原型中不包含以該名字命名的屬性
原生對(duì)象的原型
原型模式的體現(xiàn)在創(chuàng)建自定義類型方面,所有的原生的引用類型,都是采用這種模式創(chuàng)建的。
所有元素引用類型(Object,Array,String...)都在其構(gòu)造函數(shù)上定義了方法
通過原生對(duì)象的原型,不僅可以取得所有默認(rèn)方法的引用,而且也可以定義新的方法。
console.log( typeof Array.prototype.slice ); // function
不建議這樣使用,會(huì)導(dǎo)致命名沖突,也可能意外的重寫原生的方法。
原型對(duì)象的問題
原型模式省略了為構(gòu)造函數(shù)傳遞參數(shù)初始化的,造成所有實(shí)例默認(rèn)情況下都將取得相同的屬性值。
原型模式最大的問題是由其共享的本性所導(dǎo)致。
對(duì)于包含引用類型的原型對(duì)象,如果修改其值,那么另個(gè)實(shí)例也會(huì)修改。
function Person () {} Person.prototype = { constructor: Person, name: "Nicholas", friends: ["Shelby", "Court"] } var p1 = new Person(); var p2 = new Person(); p1.friends.push("Van"); console.log(p1.friends); // ["Shelby", "Court", "Van"] console.log(p1.friends); // ["Shelby", "Court", "Van"]
實(shí)例一般都要有屬性自己的全部屬性。這個(gè)問題造成很少會(huì)多帶帶使用原型模式。
組合使用構(gòu)造函數(shù)模式和原型模式
構(gòu)造函數(shù)模式:用于定義實(shí)例的屬性
原型模式:用于定義方法和共享的屬性。
結(jié)果:每個(gè)實(shí)例都會(huì)有自己的一份實(shí)例屬性的副本,但同時(shí)又共享這對(duì)方法的引用,最大限度的節(jié)省內(nèi)存,同時(shí)還支持向構(gòu)造函數(shù)傳遞參數(shù)。
是目前在ECMAScript中使用最廣泛,認(rèn)同度最高的一種創(chuàng)建自定義類型的方法。是用來定義引用類型的一種默認(rèn)模式。
動(dòng)態(tài)原型模式
把信息都封裝到函數(shù)中,這樣體現(xiàn)了封裝的概念。
通過在構(gòu)造函數(shù)中初始化原型(僅在必要情況下),同時(shí)保持了同時(shí)使用構(gòu)造函數(shù)和原型的優(yōu)點(diǎn)。
可以通過檢查默認(rèn)應(yīng)該存在的方法是否有效,來決定是否需要初始化運(yùn)原型。
//動(dòng)態(tài)原型模式:(讓你的代碼 都封裝到一起) function Person( name,age,firends ) { this.name = name; this.age = age; this.firends = firends; //動(dòng)態(tài)原型方法 if ( typeof this.sayName !== "function" ) { Person.prototype.sayName = function () { console.log(this.name); } } }
sayName()方法不存在的情況下,才會(huì)將它添加到原型中if語句中的代碼只會(huì)在初次調(diào)用構(gòu)造函數(shù)時(shí)才會(huì)執(zhí)行。此后,原型已經(jīng)完成初始化,不需要再做什么修改。這邊的原型所做的修改,能夠理解在所有實(shí)例中得到反映。
if語句的檢查可以是初始化之后應(yīng)該存在的任何屬性或方法---不必用一大堆if語句檢查每個(gè)屬性和每個(gè)方法。只要檢查其中一個(gè)即可。
采這種模式創(chuàng)建的對(duì)象,還可以使用instanceof操作符確定它的類型。
使用動(dòng)態(tài)原型模式時(shí),不能使用對(duì)象字面量重寫原型。如果在已經(jīng)創(chuàng)建了實(shí)例的情況下重寫原型,就會(huì)切斷現(xiàn)有實(shí)例與新原型之間的聯(lián)系。
寄生構(gòu)函數(shù)模式
創(chuàng)建一個(gè)函數(shù),該函數(shù)的作用僅僅是封裝創(chuàng)建對(duì)象的代碼,然后再返回新創(chuàng)建的對(duì)象。
在工廠模式,組合使用構(gòu)造函數(shù)模式和原型模式,都不能使用的情況下,使用。
這個(gè)模式與工廠模式是類似的,構(gòu)造函數(shù)在不返回值的情況下,默認(rèn)會(huì)返回新對(duì)象的實(shí)例。而在構(gòu)造函數(shù)末尾添加一個(gè)return語句,可以重寫調(diào)用構(gòu)造函數(shù)時(shí)返回出來的值。
function Person ( name ) { var o = new Object(); o.name = name; o.sayName = function () { console.log(this.name); } return o; } var friend = new Person("Van"); friend.sayName();
寄生構(gòu)造函數(shù)模式,首先,返回的對(duì)象與構(gòu)造函數(shù)或者與構(gòu)造函數(shù)的原型屬性之間沒有關(guān)系。
構(gòu)造函數(shù)返回的對(duì)象與在構(gòu)造函數(shù)外部創(chuàng)建的對(duì)象沒有什么不同,為此,不恩呢該依賴 instanceof操作符來確定對(duì)象類型。
一般來說,不可通過prototype修改原生對(duì)象的方法??梢允褂眉纳鷺?gòu)造函數(shù)模式,達(dá)到特殊需求。
穩(wěn)妥構(gòu)造函數(shù)模式
穩(wěn)妥模式就是沒有公共屬性,而且其他方法也不引用this對(duì)象,穩(wěn)妥模式最適合在安全的環(huán)境中使用。如果程序?qū)τ诎踩砸蠛芨?,那么非常適合這種模式。
也不能使用new關(guān)鍵字。
//穩(wěn)妥構(gòu)造函數(shù)式 durable object (穩(wěn)妥對(duì)象) //1,沒有公共的屬性 //2,不能使用this對(duì)象 function Person ( name,age ) { //創(chuàng)建一個(gè)要返回的對(duì)象。 利用工廠模式思維。 var obj = new Object(); //可以定義一下是有的變量和函數(shù) private var name = name || "zf"; // var sex = "女"; // var sayName = function () { // } //添加一個(gè)對(duì)外的方法 obj.sayName = function () { console.log(name); } return obj; } var p1 = Person("xixi",20); p1.sayName();繼承
許多OO語言橫縱都支持兩種繼承方式:接口繼承 和實(shí)現(xiàn)繼承。
接口繼承:只繼承方法簽名
實(shí)現(xiàn)繼承:繼承實(shí)際的方法。
由于函數(shù)中沒有簽名,在ECMAScript中無法實(shí)現(xiàn)接口繼承,ECAMScript 只支持實(shí)現(xiàn)繼承,而其實(shí)現(xiàn)繼承主要原型鏈來實(shí)現(xiàn)。
原型鏈
基本思想:讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。
讓原型對(duì)象等于另一個(gè)類型的實(shí)例,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)原型的指針,相應(yīng)的,另一個(gè)原型中也包含指向另一個(gè)構(gòu)造函數(shù)的指針。
實(shí)現(xiàn)的本質(zhì)是重寫原型對(duì)象,代之以一個(gè)新類型的實(shí)例
function SuperType () { this.property = true; } SuperType.prototype.getSuperValue = function () { return this.property; } function SubType () { this.subproperty = false; } // 繼承了SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function () { return this.subproperty; } var instance = new SubType(); console.log( instance.getSuperValue() ); // true
調(diào)用 instance.getSuperValue()會(huì)經(jīng)歷三個(gè)步驟:
1:搜索實(shí)例
2:搜索SubType.prototype
3:搜索SuperTpe.prototype
別忘記默認(rèn)的原型
所有函數(shù)的原型都是Object的實(shí)例,因此默認(rèn)原型都會(huì)包含一個(gè)內(nèi)部指針,指向Object.prototype確定原型和實(shí)例的關(guān)系
可以通過兩種方式來確定原型和實(shí)例之間的關(guān)系。第一種方式是使用 instanceof 操作符,只要用
這個(gè)操作符來測試實(shí)例與原型鏈中出現(xiàn)過的構(gòu)造函數(shù),結(jié)果就會(huì)返回 true 。
方式1:使用instanceof操作符。 測試實(shí)例與原型鏈中出現(xiàn)的構(gòu)造函數(shù),就會(huì)返回true。
alert(instance instanceof Object); //true alert(instance instanceof SuperType); //true alert(instance instanceof SubType); //true
方式2:使用isPrototypeOf(); 是原型鏈中出現(xiàn)過的原型,都可以說是該原型鏈所派生的實(shí)例的原型。就會(huì)返回true。
alert(Object.prototype.isPrototypeOf(instance)); //true alert(SuperType.prototype.isPrototypeOf(instance)); //true alert(SubType.prototype.isPrototypeOf(instance)); //true
謹(jǐn)慎地定義方法
子類型有時(shí)候需要重寫超類型中的某個(gè)方法,或者需要添加超類型中不存在的某個(gè)方法。
給原型添加方法的代碼一定要放在替換原型的語句之后。
即在通過原型鏈實(shí)現(xiàn)繼承時(shí),不能使用對(duì)象字面量創(chuàng)建原型方法。因?yàn)檫@
樣做就會(huì)重寫原型鏈,
即在通過原型鏈實(shí)現(xiàn)繼承時(shí),不能使用對(duì)象字面量創(chuàng)建原型方法。這樣會(huì)重寫原型鏈。導(dǎo)致替換原型無效。
原型鏈的問題
原型鏈可以實(shí)現(xiàn)繼承,但是存在一些問題:包含引用類型的原型。
通過原型來實(shí)現(xiàn)繼承時(shí),原型實(shí)際上會(huì)變成另一個(gè)類型的實(shí)例。于是,原先的實(shí)例屬性也就變成了現(xiàn)在的原型屬性了。
在構(gòu)造函數(shù)中,而不是原型對(duì)象中定義屬性的原因:包含引用類型的原型屬性會(huì)被實(shí)例所共享。
第二個(gè)問題:在創(chuàng)建子類型的實(shí)例時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。
原因:沒有辦法在不影響所有對(duì)象的實(shí)例情況下,給超類型的構(gòu)造函數(shù)傳遞參數(shù)。
實(shí)踐中很少多帶帶使用原型鏈。
借用構(gòu)造函數(shù)
在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)
函數(shù)只是在特定環(huán)境中執(zhí)行代碼的對(duì)象,因此通過使用apply()和call()方法可以在新創(chuàng)建的對(duì)象上執(zhí)行構(gòu)造函數(shù)
傳遞參數(shù)
在類型構(gòu)造函數(shù)中向超類型構(gòu)造函數(shù)傳遞參數(shù)
function SuperType ( name ) { this.name = name; } function SubType ( name ) { // 繼承了SuperType,同時(shí)傳遞參數(shù) SuperType.call(this,name) this.age = 21; } var instance = new SubType("cyan"); console.log( instance.name ); // cyan console.log( instance.age ); // 21
借用構(gòu)造函數(shù)的問題
無法避免構(gòu)造函數(shù)模式存在的問題--方法都定義構(gòu)造函數(shù)中定義。
超類型的原型中定義的方法,對(duì)子類型而言也是不可見的。
借用構(gòu)造函數(shù)很少多帶帶使用
組合繼承
將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一塊,發(fā)揮二者之長的一種繼承模式。
思路:使用原型鏈的實(shí)現(xiàn)對(duì)象原型屬性和方法的繼承,通過借用構(gòu)造函數(shù)實(shí)現(xiàn)的對(duì)象屬性的繼承。
結(jié)果:即通過在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,有能夠保證每個(gè)實(shí)例都有它自己的屬性。
instanceof 和isPrototypeOf(); 能夠用于識(shí)別基于組合創(chuàng)建的對(duì)象。 (JavaScript中最常用的繼承模式)
缺點(diǎn):會(huì)執(zhí)行構(gòu)造函數(shù)二次。
原型式繼承
借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)還不比因此創(chuàng)建自定義類型。
function object(o){ function F(){} F.prototype = o; return new F(); }
在 object(); 函數(shù)內(nèi)部,先創(chuàng)建了一個(gè)臨時(shí)性的構(gòu)造函數(shù),然后將傳入的對(duì)象作為這個(gè)構(gòu)造函數(shù)的原型,最后返回這個(gè)臨時(shí)類型的一個(gè)新實(shí)例。本質(zhì)上:boject()對(duì)傳入其中的對(duì)象執(zhí)行了一次淺復(fù)制
//2件事: 繼承了1次父類的模板,繼承了一次父類的原型對(duì)象 function Person ( name,age ) { this.name = name; this.age = age; } Person.prototype = { constructor: Person, sayHello: function () { console.log("hello world!"); } } function Boy ( name,age,sex ) { //call 綁定父類的模板函數(shù) 實(shí)現(xiàn) 借用構(gòu)造函數(shù)繼承 只復(fù)制了父類的模板 // Person.call(this,name,age); Boy.superClass.constructor.call(this,name,age); this.sex = sex; } //原型繼承的方式: 即繼承了父類的模板,又繼承了父類的原型對(duì)象。 // Boy.prototype = new Person(); //只繼承 父類的原型對(duì)象 extend(Boy,Person); // 目的 只繼承 父類的原型對(duì)象 , 需要那兩個(gè)類產(chǎn)生關(guān)聯(lián)關(guān)系. //給子類加了一個(gè)原型對(duì)象的方法。 Boy.prototype.sayHello = function () { console.log("hi,js"); } var b = new Boy("zf",20,"男"); console.log( b.name ); console.log( b.sex ); b.sayHello(); Boy.superClass.sayHello.call(b); //extend方法 //sub子類, sup 父類 function extend ( sub,sup ) { //目的, 實(shí)現(xiàn)只繼承 父類的原型對(duì)象。 從原型對(duì)象入手 //1,創(chuàng)建一個(gè)空函數(shù), 目的:空函數(shù)進(jìn)行中轉(zhuǎn) var F = new Function(); // 用一個(gè)空函數(shù)進(jìn)行中轉(zhuǎn)。 // 把父類的模板屏蔽掉, 父類的原型取到。 F.prototype = sup.prototype; // 2實(shí)現(xiàn)空函數(shù)的原型對(duì)象 和 超類的原型對(duì)象轉(zhuǎn)換 sub.prototype = new F(); // 3原型繼承 //做善后處理。 還原構(gòu)造器 , sub.prototype.constructor = sub; //4 ,還原子類的構(gòu)造器 //保存一下父類的原型對(duì)象 // 因?yàn)?①方便解耦, 減低耦合性 ② 可以方便獲得父類的原型對(duì)象 sub.superClass = sup.prototype; //5 ,保存父類的原型對(duì)象。 //自定義一個(gè)子類的靜態(tài)屬性 , 接受父類的原型對(duì)象。 //判斷父類的原型對(duì)象的構(gòu)造器, (防止簡單原型中給更改為 Object) if ( sup.prototype.constructor == Object.prototype.constructor ) { sup.prototype.constructor = sup; //還原父類原型對(duì)象的構(gòu)造器 } }
Object.create()
參數(shù)1:用作新對(duì)象原型的對(duì)象。
參數(shù)2(可選)一個(gè)為新對(duì)象額外屬性的對(duì)象. 配置參數(shù)(每個(gè)屬性都是通過高自己的描述符定義)
傳入一個(gè)參數(shù)的情況下:Object.create(); 與 object() 方法的行為相同.
注意:定義任何屬性都會(huì)覆蓋原型對(duì)象上同名屬性。
包含引用類型值的屬性始終都會(huì)共享相應(yīng)的值
var person = { name: "cyan", firends: ["tan", "kihaki", "van"] } var anotherPerson = Object.create(person, { name: { value: "red" } }); console.log( anotherPerson.name ); // red
寄生式繼承
創(chuàng)建一個(gè)僅用于封裝過程的函數(shù),該函數(shù)在內(nèi)部以某種方式來增強(qiáng)對(duì)象,最后返回對(duì)象。
function createAnother ( original ) { var cloen = Object.create(original); // 調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象 clone.sayHi = function () { // 以某種方式來增強(qiáng)這個(gè)對(duì)象 console.log("hi"); } return clone; // 返回這個(gè)對(duì)象 }
寄生組合式繼承
解決,構(gòu)造函數(shù)調(diào)用二次的問題。
通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈的混成形式來繼承方法。
基本思路:不必為了指定子類型的原型而調(diào)用超類型構(gòu)造函數(shù)。需要的是超類型的原型的一個(gè)副本。
本質(zhì):使用寄生式繼承來繼承超類型的原型,然后再將指定給子類型的原型。
沒有使用new關(guān)鍵字
function inheritProtoype ( subType, superType ) { var prototype = Object.create(superType.prototype); // 創(chuàng)建對(duì)象 prototype.constructor = subType; // 增強(qiáng)對(duì)象 subType.prototype = prototype; // 指定對(duì)象 } // 1: 創(chuàng)建超類型的原型的一個(gè)副本。 // 2:為創(chuàng)建的副本添加添加constructor屬性,從而彌補(bǔ)因?yàn)橹貙懺投袇^(qū)去的constructor屬性 // 3: 將新創(chuàng)建的對(duì)象,賦值給子類型的原型。函數(shù)表達(dá)式
通過name 可以訪問函數(shù)名(非標(biāo)準(zhǔn)屬性)
關(guān)于函數(shù)聲明,重要特征就是函數(shù)聲明提升:代碼執(zhí)行之前會(huì)先讀取函數(shù)聲明。
匿名函數(shù)(也叫拉姆達(dá)函數(shù)): function 關(guān)鍵字后面沒有標(biāo)識(shí)符
匿名函數(shù)的name屬性時(shí)空字符串
遞歸函數(shù): 一個(gè)函數(shù)通過名字調(diào)用自身的情況
function factorial (num) { if ( num <= 1 ) { // 遞歸出口 return 1; } else { return num * arguments.callee(num-1); // 遞歸點(diǎn) } }
命名函數(shù)表達(dá)式:
var factorial = (function f ( num ) { if ( num <= 1 ) { return 1; } else { return num * f(num-1); } });
創(chuàng)建了一個(gè)名為f() 的命名函數(shù)表達(dá)式,然后將它賦值給變量factorial。即使把函數(shù)賦值給另一個(gè)變量,函數(shù)的名字f仍然是有效的。
閉包閉包:指有權(quán)訪問另一個(gè)函數(shù)中作用域中的變量的函數(shù)。
表現(xiàn):在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)
當(dāng)某個(gè)函數(shù)被調(diào)用的時(shí)候,會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境(execution context)及相應(yīng)的作用域鏈。然后使用arguments和其它命名參數(shù)的值來初始化函數(shù)的活動(dòng)對(duì)象(activation object)。
在作用域鏈中,外部函數(shù)的活動(dòng)對(duì)象始終處于第二位,外部函數(shù)的外部函數(shù)的活動(dòng)對(duì)象處于第三位直至作用域鏈的終點(diǎn)的全局執(zhí)行環(huán)境。
后臺(tái)的每個(gè)執(zhí)行環(huán)境都有一個(gè)表示變量的對(duì)象---變量對(duì)象
作用域鏈中至少包含二個(gè)變量對(duì)象:本地活動(dòng)對(duì)象和全局變量對(duì)象。
作用域鏈本質(zhì):一個(gè)指向變量對(duì)象的指針列表,引用但不實(shí)際包含變量對(duì)象。
無論什么時(shí)候在函數(shù)中訪問一個(gè)變量時(shí),就會(huì)從作用域鏈中搜索具有相應(yīng)名字的變量。
一般來講,當(dāng)函數(shù)執(zhí)行完畢后,局部活動(dòng)對(duì)象就會(huì)被銷毀,內(nèi)容中近保存全局作用域(全局執(zhí)行環(huán)境的比變量對(duì)象)。
但是,閉包可以延長變量的生存周期
function createComparisonFunction( propertyName ) { return function ( object1, object2 ) { var val1 = object1[propertyName]; var val2 = object1[propertyName]; if ( val1 < val2 ) { return -1; } else if ( val1 > val2 ) { return 1; } else { return 0; } } } var compare = createComparisonFunction("name"); var reslut = compare({name: "cyan"}, {name: "tan"}); // 告知垃圾回收機(jī)制將其清除, // 隨著匿名函數(shù)的作用域鏈被銷毀,其它作用域(除了全局作用域)也都可以安全的銷毀。 compare = null; // 接觸對(duì)匿名函數(shù)的引用(以便釋放內(nèi)存)
createComparisonFunction()函數(shù)執(zhí)行完畢后,其活動(dòng)對(duì)象也不會(huì)被銷毀,因?yàn)槟涿瘮?shù)的作用域鏈仍然在引用這個(gè)活動(dòng)對(duì)象。
當(dāng)createComparisonFunction()函數(shù)執(zhí)行返回后,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀,但它的活動(dòng)對(duì)象仍會(huì)留在內(nèi)存中,直至匿名函數(shù)被銷毀。createComparisonFunction()的活動(dòng)對(duì)象才會(huì)被銷毀。
閉包的問題:
由于閉包會(huì)攜帶包含它的函數(shù)的作用域,因此會(huì)比其他函數(shù)占用過多的內(nèi)存。過度使用閉包可能會(huì)導(dǎo)致內(nèi)存占用過多,V8引擎優(yōu)化后,JavaScript引擎會(huì)嘗試回收被閉包占用的內(nèi)存。
閉包與變量
閉包只能取得包含函數(shù)中任何變量的最后一值。(循環(huán)嵌套函數(shù)的i問題)
閉包所保存的是整個(gè)變量對(duì)象,而不是某個(gè)特殊的變量。
function createFunctions () { var reslut = []; for ( var i=0; i<10; i++ ) { reslut[i] = function (num) { return function () { return num; } }(i); } return reslut; }
定義一個(gè)匿名函數(shù),并將立即執(zhí)行該匿名函數(shù)的結(jié)果賦給數(shù)組。由于函數(shù)參數(shù)是按值傳遞的,所以就會(huì)將變量i的當(dāng)前值復(fù)制給參數(shù)num。而在這個(gè)匿名函數(shù)內(nèi)部,有創(chuàng)建并返回了一個(gè)訪問num的閉包。這樣,reslut數(shù)組中的每個(gè)函數(shù)都有自己num變量的一個(gè)副本,因此可以返回各自不同的數(shù)值。
關(guān)于this對(duì)象
this對(duì)象是運(yùn)行時(shí)就函數(shù)執(zhí)行環(huán)境綁定的:在全局函數(shù)中,this等于window,而當(dāng)函數(shù)被作為某個(gè)對(duì)象的方法調(diào)用時(shí),this等于那個(gè)對(duì)象。
匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其this對(duì)象通常指向window。但有時(shí)候由于編寫閉包的方式不同,這一點(diǎn)不明顯。(在通過call()或apply()來改變函數(shù)執(zhí)行環(huán)境的情況下,this就會(huì)指向其它對(duì)象。)
var name = "window"; var object = { name: "object", getNameFunc: function () { return function () { return this.name; } } } console.log( object.getNameFunc()() );
先創(chuàng)建了一個(gè)全局變量name,有創(chuàng)建一個(gè)包含name屬性的對(duì)象。這個(gè)對(duì)象包含一個(gè)方法--getNameFunc(); 它返回一個(gè)匿名函數(shù),而匿名函數(shù)又返回this.name。由于getNameFunc();返回一個(gè)函數(shù),因此調(diào)用object.getNameFunc()(); 就立即調(diào)用它返回的函數(shù),結(jié)果返回一個(gè)字符串。 結(jié)果的name變量的值是全局的。為什么匿名函數(shù)沒有取得其包含作用域(或外部作用域)的this對(duì)象呢?
每個(gè)函數(shù)在被調(diào)用時(shí)都會(huì)自動(dòng)取得兩個(gè)特殊變量:this和arguments。內(nèi)部函數(shù)在搜索這兩個(gè)變量時(shí),只會(huì)搜索到其活動(dòng)對(duì)象為止,因此永遠(yuǎn)不可能直接訪問外部函數(shù)中的這個(gè)兩個(gè)變量。
可以通過保存this引用來訪問
var name = "window"; var object = { name: "object", getNameFunc: function () { var self = this; return function () { return self.name; } } } console.log( object.getNameFunc()() );
this 和arguments存在同樣的問題,如果想訪問作用域中的arguments對(duì)象,必須將對(duì)該對(duì)象的引用保存到另一個(gè)閉包能夠訪問的變量中。
內(nèi)存泄漏
如果閉包的作用域鏈保存著一個(gè)HTML元素,就意味著該元素將無法被銷毀
閉包會(huì)引用包含函數(shù)的整個(gè)活動(dòng)對(duì)象。
包含函數(shù)的活動(dòng)中也仍然會(huì)保存一個(gè)引用。因此,有必要把element變量設(shè)置null。這樣能夠接觸對(duì)DOM對(duì)戲那個(gè)的引用。順利地減少其引用數(shù)據(jù),確保正?;厥掌湔加玫膬?nèi)存。
模仿塊級(jí)作用域
JavaScript中沒有塊級(jí)作用域的概念
function outputNumbers ( count ) { for ( var i=0; i變量i是定義在outputNumbers()的活動(dòng)對(duì)象中,因此從它有定義開始,就可以在函數(shù)內(nèi)部隨處訪問它。
匿名函數(shù)用來模仿塊級(jí)作用域并避免這個(gè)問題。
塊級(jí)作用域:稱為私有作用域
(function () {})();將函數(shù)聲明包含在一堆圓括號(hào)中,表示它實(shí)際上是一個(gè)函數(shù)表達(dá)式,而緊隨其后的另一對(duì)圓括號(hào)會(huì)立即調(diào)用這個(gè)函數(shù)。
JavaScript將function 關(guān)鍵字作一個(gè)函數(shù)聲明的開始,而函數(shù)后聲明不能跟圓括號(hào)。然后函數(shù)表達(dá)式的后面可以跟圓括號(hào)。
將函數(shù)聲明轉(zhuǎn)換成表達(dá)式使用()
需求:只要臨時(shí)需要一些變量,就可以使用私有化作用域function outputNumbers ( count ) { (function () { for ( var i=0; i在匿名函數(shù)中的定義的任何變量,都會(huì)在執(zhí)行結(jié)束時(shí)被銷毀。
結(jié)果:減少閉包占用的內(nèi)存問題,因?yàn)闆]有指向匿名函數(shù)的引用。只要函數(shù)執(zhí)行完畢,就可以立即銷毀其作用域鏈了。
私有變量特權(quán)方法:有權(quán)訪問私有變量和私有方法的公有方法。
作用:封裝性,隱藏那些不應(yīng)該被被直接修改的屬性,方法。
缺點(diǎn):必須使用構(gòu)造函數(shù)模式來達(dá)到這個(gè)目的。
構(gòu)造函數(shù)本身是有缺點(diǎn):對(duì)每個(gè)實(shí)例都是創(chuàng)建同樣一組新方法。構(gòu)造函數(shù)中定義特權(quán)方法:
function MyObject () { // 私有變量和私有函數(shù) var privateVariable = 10; function prvateFunction () { return false; } // 特權(quán)方法 this.publicMethod = function () { privateVariable++; return prvateFunction(); } }靜態(tài)私有變量
目的:創(chuàng)建靜態(tài)變量會(huì)因?yàn)槭褂迷投鲞M(jìn)代碼的復(fù)用,但沒有實(shí)例對(duì)象都沒有自己的私有變量。使用閉包和私有變量缺點(diǎn):多查找作用域中的一個(gè)層次,就會(huì)在一定程度上影響查找速度。
模塊模式
目的:為單例創(chuàng)建私有變量和特權(quán)方法。
本質(zhì):對(duì)象字面量定義的是單例的公共接口單例:只有一個(gè)實(shí)例的對(duì)象。
慣例:JavaScript是以對(duì)象字面量的方式來創(chuàng)建單例對(duì)象。
作用:對(duì)單例進(jìn)行某些初始化,同時(shí)又需要維護(hù)其私有化變量。//通過 一個(gè)私有變量來控制是否 實(shí)例化對(duì)象, 初始化一個(gè) init。 var Ext = {}; Ext.Base = (function () { //私有變量 控制返回的單體對(duì)象 var uniqInstance; //需要一個(gè)構(gòu)造器 init 初始化單體對(duì)象的方法 function Init () { //私有成員 var a1 = 10; var a2 = true; var fun1 = function () { console.log( a1 ); } return { attr1: a1, attr2: a2, fun1: fun1 } } return { getInstance: function () { if ( !uniqInstance ) { //不存在 ,創(chuàng)建單體實(shí)例 uniqInstance = new Init(); } return uniqInstance; } } })() var init = Ext.Base.getInstance(); init.fun1(); //10使用需求:創(chuàng)建一個(gè)對(duì)象并以某些數(shù)據(jù)對(duì)齊初始化,同時(shí)還要公開一些能夠訪問這些私有數(shù)據(jù)方法。
每個(gè)單例都是Object的實(shí)例,因?yàn)橥ㄟ^一個(gè)對(duì)象字面量表示單例通常都是 全局對(duì)象存在,不會(huì)將它傳遞給一個(gè)函數(shù)。增強(qiáng)的模塊模式
在返回對(duì)象之前假如對(duì)其增強(qiáng)的代碼。var application = function(){ //私有變量和函數(shù) var components = new Array(); //初始化 components.push(new BaseComponent()); //創(chuàng)建 application 的一個(gè)局部副本 var app = new BaseComponent(); //公共接口 app.getComponentCount = function(){ return components.length; } app.registerComponent = function(component){ if (typeof component == "object"){ components.push(component); } } //返回這個(gè)副本 return app; }();BOM window對(duì)象BOM的核心對(duì)象是window,表示瀏覽器的一個(gè)實(shí)例。
在瀏覽器中,window對(duì)象有雙重角色:
1:JavaScript訪問瀏覽器窗口的一個(gè)接口
2: ECMAScript規(guī)定的Global對(duì)象。
在網(wǎng)頁中定義的任何一個(gè)對(duì)象,變量,函數(shù),都已window作為其Global對(duì)象。因此有權(quán)訪問parseInt()等方法。窗口與框架
使用框架時(shí),每個(gè)框架都有自己的window對(duì)象以及所有原生構(gòu)造函數(shù)及其它函數(shù)的副本。每個(gè)框架都保存在frames集合中,可以通過位置或通過名稱來訪問。
top對(duì)象始終指向最外圍的框架,也就是整個(gè)瀏覽器窗口。
parent 對(duì)象表示包含當(dāng)前框架的框架,而 self 對(duì)象則回指 window 。全局作用域
定義全局變量與在window對(duì)象上直接定義屬性差別:
全局變量不能通過delete操作刪除,直接定義window對(duì)象上的定義屬性可以刪除。var age = 22; window.color = "red"; //在 IE < 9 時(shí)拋出錯(cuò)誤,在其他所有瀏覽器中都返回 false delete window.age; //在 IE < 9 時(shí)拋出錯(cuò)誤,在其他所有瀏覽器中都返回 true delete window.color; // returns true console.log(window.age); //22 29 console.log(window.color); // undefinedvar 語句添加的window屬性[Configurable]的特性,這個(gè)特性的值被設(shè)置為false。所以定義的不可delete操作符刪除。
嘗試訪問未聲明的變量會(huì)拋出錯(cuò)誤,但是通過window對(duì)象,可以知道某個(gè)可能未聲明的變量是否存在。
var newValue = oldValue; // 報(bào)錯(cuò),未定義 var newValue = window.oldValue; // 屬性查詢,不會(huì)拋出錯(cuò)誤location對(duì)象提供了與當(dāng)前窗口中加載的文檔有關(guān)的信息,提供一些導(dǎo)航功能。
location對(duì)象很特別,即是window對(duì)象的屬性,也是document對(duì)象的屬性,window.location 和 document.location引用的是同一個(gè)對(duì)象。作用:保存著當(dāng)前文檔的信息,還表現(xiàn)將URL解析為獨(dú)立的片段。
屬性 例子 說明 hash "#contents" 返回URL中的hash(#號(hào)后跟零或多個(gè)字符),如果URL中不包含散列,則返回空字符串 host "www.aa.com:80" 返回服務(wù)器名稱和端口號(hào)(如果有) hostname "www.aa.com" 返回不帶端口號(hào)的服務(wù)器名稱 href "http:/www.aa.com" 返回當(dāng)前加載頁面的完整URL。而location對(duì)象的toString()方法也返回這個(gè)值 pathname "/WileyCDA/" 返回URL中的目錄和(或)文件名 port "8080" 返回URL中指定的端口號(hào)。如果URL中不包含端口號(hào),則這個(gè)屬性返回空字符串 protocol "http:" 返回頁面使用的協(xié)議。通常是http:或https: search "?q=javascript" 返回URL的查詢字符串。這個(gè)字符串以問號(hào)開頭 位置操作
location對(duì)象改變?yōu)g覽器位置location.assign("http://segmentfault.com"); // 打開新的URL并在瀏覽器的歷史記錄中生成一條記錄。如果將location.href 或window.location設(shè)置為一個(gè)URL,會(huì)以該值調(diào)用assign()方法。
window.location = "http://www.segmentfault.com"; location.;最常用的方式:location.;
禁止用戶使用‘后退’按鈕 使用location.replace();
參數(shù):需要導(dǎo)航的URL
location.relaod(); 作用:重新加載當(dāng)前顯示的頁面location.reload(); //重新加載(有可能從瀏覽器緩存中加載) location.reload(true); //重新加載(從服務(wù)器重新加載)location.reload();調(diào)用之后的代碼可能會(huì)也可能不會(huì)執(zhí)行,取決于網(wǎng)絡(luò)延遲或系統(tǒng)資源等因素。如果使用location.relaod();最好放在代碼最后一行。
navigator對(duì)象作用:識(shí)別客戶端瀏覽器
navigator.userAgent // 瀏覽器的用戶代理字符串檢測插件
非IE下使用:navigator.plugins數(shù)組function hasPlugin(name){ name = name.toLowerCase(); for (var i=0; i < navigator.plugins.length; i++){ if (navigator. plugins [i].name.toLowerCase().indexOf(name) > -1){ return true; } } return false;注冊(cè)處理程序
registerContentHandler() 和 registerProtocolHandler()
作用:讓一個(gè)站點(diǎn)指明它可以處理特定類型的信息。(使用范圍:RSS 閱讀器和在線電子郵件程序)registerContentHandler();
參數(shù)1:要處理的MIME類型
參數(shù)2:可以處理該MIME類型的頁面URL
參數(shù)3:應(yīng)用程序的名稱// 站點(diǎn)注冊(cè)為處理 RSS 源的處理程序 navigator.registerContentHandler("application/rss+xml","http://www.somereader.com?feed=%s", "Some Reader"); // 參數(shù)1:RSS源 的MIME類型參數(shù) 2:應(yīng)該接收 RSS源 URL的 URL,其中的%s 表示RSS 源 URL,由瀏覽器自動(dòng)插入。 // 作用:當(dāng)下一次請(qǐng)求 RSS 源時(shí),瀏覽器就會(huì)打開指定的 URL,而相應(yīng)的Web 應(yīng)用程序?qū)⒁赃m當(dāng)方式來處理該請(qǐng)求。screen對(duì)象表明客戶端能力:瀏覽器窗口外部的顯示器信息,如:像素寬度和高度。
window.screen.height // 屏幕的像素高度
window.screen.windth // 屏幕的像素寬度window.resizeTo(); // 調(diào)整瀏覽器窗口大小
history對(duì)象history 對(duì)象:保存用戶上網(wǎng)的歷史記錄。充窗口被打開的那一刻算起。
history是window對(duì)象的屬性,因此每個(gè)瀏覽器串窗口,每個(gè)標(biāo)簽頁乃至每個(gè)框架,都有自己的history對(duì)象與特定的window對(duì)象關(guān)聯(lián)。history.go(); 在用戶的歷史記錄中任意跳轉(zhuǎn)。
//后退一頁 history.go(-1); //前進(jìn)一頁 history.go(1); //前進(jìn)兩頁 history.go(2); // go()參數(shù)是字符串 // 可能后退,也可能前進(jìn),具體要看哪個(gè)位置最近 //跳轉(zhuǎn)到最近的 wrox.com 頁面 history.go("segmentfault.com");history.length; 保存著歷史記錄的數(shù)量
高級(jí)技巧 高級(jí)函數(shù)
包括所有歷史記錄,即所有向后向前的記錄。對(duì)于加載到窗口,標(biāo)簽頁或框架中的第一個(gè)頁面而言。安全的類型檢測
JavaScript 中內(nèi)置的類型檢測機(jī)制并非完全可靠
typeof操作符,由于它有一些無法預(yù)知的行為,導(dǎo)致檢測數(shù)據(jù)類型時(shí)得到不靠譜的結(jié)果。(Safari直至第四版,對(duì)正則表達(dá)式 typeof 檢測 會(huì)返回 "function")
instanceof操作符,存在多個(gè)全局作用域(像一個(gè)頁面中包含多個(gè)frame)的情況下。
var isArray = valeu instaceof Array; // 返回true 條件:value 必須是數(shù)組, 必須與Array構(gòu)造函數(shù)在同個(gè)全局作用域中。(Array 是 window的屬性)。在任何值上調(diào)用Object原生的toString();方法。
返回 [object NativeConstructorName]格式的字符串。每個(gè)類在內(nèi)部都有一個(gè)[[Class]]屬性,這個(gè)屬性中指定了這個(gè)字符串中的構(gòu)造函數(shù)名.應(yīng)用:
檢測原生JSON對(duì)象。var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON) === "[object JSON]";作用域安全的構(gòu)造函數(shù)
作用:自定義對(duì)象和構(gòu)造函數(shù)的定義和用法。
構(gòu)造函數(shù)就是一個(gè)使用new操作符調(diào)用的函數(shù)。當(dāng)使用new調(diào)用時(shí),構(gòu)造函數(shù)內(nèi)用到的this對(duì)象會(huì)指向新創(chuàng)建的對(duì)象實(shí)例。問題:當(dāng)沒有使用new操作符來調(diào)用該構(gòu)造函數(shù)的情況下。this對(duì)象是在運(yùn)行時(shí)綁定的,所以直接調(diào)用 類名 ,this會(huì)映射到全局對(duì)象window上,導(dǎo)致錯(cuò)誤對(duì)象屬性的以外增加。
function Person ( name, age ) { this.name = name; this.age = age; } var p1 = Person("cyan", 22); console.log(window.name); console.log(window.age); // Person實(shí)例的屬性被加到window對(duì)象上,因?yàn)闃?gòu)造函數(shù)時(shí)作為普通函數(shù)調(diào)用,忽略了new操作符。由this對(duì)象的晚綁定造成的,在這里this被解析成了window對(duì)象。// 在類中添加判斷: function Person ( name, age ) { if ( this instanceof Person ) { this.name = name; this.age = age; } else { return new Person(name, age); } } var p1 = Person("cyan", 22); console.log(window.name); console.log(window.age); // 添加一個(gè)檢查,并確保this對(duì)象是Person實(shí)例。 // 要么使用new操作符,要么使用現(xiàn)有的Person實(shí)例環(huán)境中調(diào)用構(gòu)造函數(shù)。函數(shù)綁定
函數(shù)綁定要?jiǎng)?chuàng)建一個(gè)函數(shù),可以在待定的this環(huán)境中指定參數(shù)調(diào)用另一個(gè)函數(shù)。
使用范圍:回調(diào)函數(shù)與事件處理程序一起使用,(在將函數(shù)作為變量傳遞的同時(shí)保留代碼執(zhí)行環(huán)境)// bind(); 函數(shù) function bind ( fn, context ) { return function () { return fn.apply(context, arguments); } }將某個(gè)函數(shù)以值的形式進(jìn)行傳遞,同時(shí)該函數(shù)必須在特定環(huán)境中執(zhí)行,被綁定的函數(shù)的效果。
主要用于事件處理程序以及setTimeout() 和 setInterval();
被綁定函數(shù)與普通函數(shù)相比有更多開銷,需要更多內(nèi)存支持,同時(shí)也因?yàn)槎嘀睾瘮?shù)調(diào)用調(diào)用比較慢。最好只在必要時(shí)使用。函數(shù)柯里化
函數(shù)柯里化( function currying ): 把接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)(最初函數(shù)的第一個(gè)參數(shù))的函數(shù),并返回接受余下的參數(shù)且返回結(jié)果的新函數(shù)
作用:創(chuàng)建已經(jīng)設(shè)置好的一個(gè)或多個(gè)參數(shù)的函數(shù)。
函數(shù)柯里化的基本方法:使用一個(gè)閉包返回一個(gè)函數(shù)。
函數(shù)柯里化和函數(shù)綁定區(qū)別:當(dāng)函數(shù)被調(diào)用時(shí),返回的函數(shù)還需要設(shè)置一些傳入的參數(shù)。
函數(shù)柯里化的動(dòng)態(tài)創(chuàng)建:調(diào)用另一個(gè)函數(shù)并為它傳入要柯里化的函數(shù)和必要的參數(shù)。
用處:
作為函數(shù)綁定的一部分包含在其中,構(gòu)造出更為復(fù)雜函數(shù)function bind ( fn, context ) { let args = Array.prototype.slice.call(arguments, 2); return { let innerArgs = Array.prototype.slice.call(arguments); let fianlArgs = args.concat(innerArgs); return fn.apply(context, fianlArgs); } }缺點(diǎn):
每個(gè)函數(shù)都會(huì)帶來額外的開銷.不能夠?yàn)E用。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/86424.html
showImg(http://img3.douban.com/lpic/s8958650.jpg); 0x00 javascript組成 ECMAScript(-265)核心語言部分 DOM文檔對(duì)象模型(DOM1、2、3) BOM瀏覽器對(duì)象模型(提供與瀏覽器交互的接口和方法) 0x01 async 異步加載 執(zhí)行順序不定 charset defer 延遲加載,立即下載腳本但不執(zhí)行 src ...
摘要:客戶端檢測方式能力檢測怪癖檢測用戶代理檢測能力檢測最常用也是最為人們廣泛接受的客戶端檢測形式是能力檢測又稱特性檢測。在可能的情況下,盡量使用進(jìn)行能力檢測。 客戶端檢測方式 能力檢測 怪癖檢測 用戶代理檢測 能力檢測 最常用也是最為人們廣泛接受的客戶端檢測形式是能力檢測(又稱特性檢測)。能力檢測的目標(biāo)不是識(shí)別特定的瀏覽器,而是識(shí)別瀏覽器的能力。采用這種方式不必顧及特定的瀏覽器如何...
摘要:由構(gòu)造函數(shù)返回的對(duì)象就是表達(dá)式的結(jié)果。如果構(gòu)造函數(shù)沒有顯式返回一個(gè)對(duì)象,則使用步驟創(chuàng)建的對(duì)象。運(yùn)算符返回一個(gè)布爾值,表示對(duì)象是否為某個(gè)構(gòu)造函數(shù)的實(shí)例。 面向?qū)ο?本人能力有限,有誤請(qǐng)斧正 本文旨在復(fù)習(xí)面向?qū)ο?不包含es6) 本文學(xué)習(xí)思維 創(chuàng)建對(duì)象的方式,獲取對(duì)象屬性 構(gòu)造函數(shù),構(gòu)造函數(shù)的new 做了什么 原型與原型對(duì)象 原型鏈 繼承(借用構(gòu)造繼承、原型繼承、組合繼承、寄生組合繼承)...
摘要:事情是如何發(fā)生的最近干了件事情,發(fā)現(xiàn)了源碼的一個(gè)。樓主找到的關(guān)于和區(qū)別的資料如下關(guān)于拿來主義為什么這么多文章里會(huì)出現(xiàn)澤卡斯的錯(cuò)誤代碼樓主想到了一個(gè)詞,叫做拿來主義。的文章,就深刻抨擊了拿來主義這一現(xiàn)象。 事情是如何發(fā)生的 最近干了件事情,發(fā)現(xiàn)了 underscore 源碼的一個(gè) bug。這件事本身并沒有什么可說的,但是過程值得我們深思,記錄如下,各位看官仁者見仁智者見智。 平時(shí)有瀏覽別...
閱讀 3085·2021-11-24 10:32
閱讀 753·2021-11-24 10:19
閱讀 5527·2021-08-11 11:17
閱讀 1529·2019-08-26 13:31
閱讀 1318·2019-08-23 15:15
閱讀 2338·2019-08-23 14:46
閱讀 2350·2019-08-23 14:07
閱讀 1190·2019-08-23 14:03