摘要:但采用構造器調用模式,即是使用了前綴去調用一個函數時,函數執行的方式會改變。對象包含構造器需要構造一個新的實例的所有信息。構造器的變量和內部函數變成了該實例的私有成員。
</>復制代碼
JavaScript 是一門弱類型語言,從不需要類型轉換。對象繼承關系變得無關緊要。對于一個對象來說重要的時它能夠做什么,而不是它從哪里來。
閱讀《javascript語言精粹》筆記!
偽類js的原型存在許多的矛盾,它不能直接讓對象從另外一個對象繼承,反而出現了一個多余的簡介曾:通過構造函數來產生對象。
當函數對象創建的時候,function構造器產生的函數對象會運行類似這樣的代碼:
</>復制代碼
function Person() {};
Person.prototype = {
constructor: this;
};
新的函數匯賦予一個prototype的值,因為js語言沒有提供一個方法去確定哪個函數式打算來做構造器的,所以每個函數都會有一個prototype的對象。而關心的是prototype對象,而不是constructor。
但采用構造器調用模式,即是使用了new前綴去調用一個函數時,函數執行的方式會改變。
</>復制代碼
Function.method("new", function(){
var that = Object.create(this.prototype),
other = this.apply(this, arguments);
return (typeof other === "object" && other) || that;
});
先創建一個新的對象,它繼承自構造器函數的原型對象
調用構造器函數,綁定this到新的對象上面
如果它的放回值不是一個對象的話,就放回哪個新對象
來定義兩個構造器并擴展它的原型:
</>復制代碼
function Person(name) {
this.name = name;
};
Person.prototype.sayName = function(){
alert(this.name);
};
function Cat(name) {
this.name = name;
};
可以讓另一個偽類去繼承Person,通過定義它的constructor函數并且替換了它prototype為一個Person的實例來實現:
</>復制代碼
Cat.prototype = new Person;
然后來給Cat的prototype上添加一個方法:
</>復制代碼
Cat.prototype.sayHello = function(){
alert("Hello");
};
最后實例化Cat并且調用它的方法:
</>復制代碼
var cat = new Cat("john");
cat.sayName(); // john
cat.sayHello(); // Hello
最后還有修改Cat的construction指向:
</>復制代碼
Cat.prototype.constructor = Cat;
可以通過使用method方法來定義一個inherits方法來實現偽類的繼承:
</>復制代碼
Function.method("inherits", function(Parent){
this.prototype = new Parent;
return this;
});
偽類模式繼承的問題:
沒有私有環境,所有屬性都是公開的。無法訪問super(父類)方法。
如果在調用構造器函數時候忘記調用new操作符,那么this將不會綁定到新的對象上,而是全局window上。
“偽類”的形式可以給不收悉js的程序員便利,但它也隱藏了該語言的真實本質。借鑒類的表示法可能誤導程序員去編寫過于深入與復雜的層次結構。
construction的指向錯誤。
對象說明符有的時候,構造器可能要接受一大串的參數,而且還要記住參數的順序是很困難滴,在這種情況下,編寫構造器的時候讓它接受一個對象說明符,可能會更加的方便。
</>復制代碼
function Person(name, age, sex, scholl, add) {};
參數改成對象說明符的形式:
</>復制代碼
function Person({
name: "john",
age: 16,
sex: "man",
scholl: "zhyz",
add: "zhuhai"
});
好處:現在能夠多個參數按照任意順序去排列,如果構造器會聰明的使用默認值,一些參數可以被忽略掉,并且代碼更加容易的閱讀。
原型</>復制代碼
在一個純粹的原型繼模式中,我們會摒棄類,轉而專注于對象。
基于原型的繼承先對基于類的繼承在概念上更加簡單:一個對象可以繼承以舊的對象。
用對象字面量來創建一個對象:
</>復制代碼
var Person = {
name: "john",
sayName: function(){
alert(this.name);
},
sayHello: function(){
alert("Hello");
}
};
有了想要的對象后,就可以利用Object.create方法來構造出更多的實例:
</>復制代碼
var nPerson = Object.create(Person);
nPerson.sayName(); // john
</>復制代碼
這是一種差異化繼承。通過定制一個新的對象,我們指明它與所基于的基本對象的區別。
下面的例子演示了如何使用Object.create來實現類式繼承。這是一個單繼承。(來自MDN)
</>復制代碼
//Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); //call super constructor.
}
Rectangle.prototype = Object.create(Shape.prototype);
var rect = new Rectangle();
rect instanceof Rectangle //true.
rect instanceof Shape //true.
rect.move(1, 1); //Outputs, "Shape moved."
函數化
大部分所看到的繼承模式的一個弱點就是沒辦法去保護隱私。對象的屬性都是可見的。沒有辦法得到私有的變量和函數。
</>復制代碼
var consturctor = function(spec, my){
var that, // 其他的私有實例變量
my = my || {};
// 把共享的變量和函數添加到 my 中
// 給 that = 一個新的對象
// 添加給 that 的特權方法
// 最后把 that 對象返回
return that;
};
創建一個對象。
定義私有實例的變量和方法。
給這個新的對象擴充方法,這些方法擁有特權去訪問參數。
返回那個對象。
spec對象包含構造器需要構造一個新的實例的所有信息。spec的可能會被復制到私有變量中,或者被其他函數改變,或者方法可以在需要的時候訪問spec的信息。
聲明該對象私有的實例變量的方法。通過簡單地聲明變量就可以做到了。構造器的變量和內部函數變成了該實例的私有成員。
my對象是一個為繼承鏈中的構構造器提供的秘密共享的容器。通過給my對象添加共享秘密成員:
</>復制代碼
my.member = value;
然后構造一個新的對象并且把它賦值給that。接著擴充that,加入組成該對象接口的特權方法??梢苑峙湟粋€新函數成為that的成員方法,然后再把它分配給that:
</>復制代碼
var methodical = function(){ ... };
that.methodical = methodical;
分兩步去定義methodical的好處就是,如果其他方法想要調用methodical,它們可以直接調用methodical()而是不是that.methodical()。如果實例遭到破壞或修改,調用methodical照樣會繼續工作,因為它們私有的methodical不會該實例被修改的影響。
最后把that返回。
函數化模式有很大的靈活性。它相比偽類模式不僅帶來的工作更少,還讓我們得到更好的封裝和信息隱藏,以及訪問父類方法的能力。
如果對象的所有狀態都是私有的,那么該對象就成為一個“防偽”對象。該對象的屬性可以被替換或刪除,但該對象的完整性不會受到傷害。
部件從一套部件中吧對象組裝出來。例如,構造一個給任何對象添加簡單事件處理特性的函數。他會給對象添加一個on方法、一個fire方法和一個私有的事件注冊表對象。
用這種方法,一個構造器函數可以從一套部件中把對象組裝出來。js的弱類型在這里就是一個巨大的優勢,因為無需花費精力去了解對象在類型系統中的集成關系。
</>復制代碼
var eventuality = function(that){
var registry = {};
that.fire = function(e){
var arry, func, handler, i,
type = typeof e === "string" ? e : e.type;
if (registry.hasOwnProperty(type)) {
array = registry[type];
for (i = 0; i < array.length; i += 1) {
handler = array[i];
func = handler.method;
if (typeof func === "string") {
func = this[func];
}
func.apply(this, handler.parameters || [e]);
}
}
return this;
};
that.on = function(type, method, parameters){
var handler = {
method;: method,
parameters: parameters
};
if (registry.hasOwnProperty(type)) {
registry[type].push(handler);
} else {
registry[type] = [handler];
}
return that;
};
return that;
};
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/85566.html
摘要:前言由于最近的項目用到了一些的代碼,所以我帶著好奇心,認真閱讀了這本書,粗略地了解語言的基本結構和特性,對于一些不熟悉的新概念,以記錄的形式加強印象,也是對學習的反思總結。 前言 由于最近的項目用到了一些js的代碼,所以我帶著好奇心,認真閱讀了這本書,粗略地了解js語言的基本結構和特性,對于一些不熟悉的新概念,以記錄的形式加強印象,也是對學習的反思總結。 一、字面量(literals...
摘要:使用構造器有個嚴重的危害,如果在調用構造器函數的時候忘記使用前綴,不僅不會綁定到新對象,還會污染全局變量原型模式原型模式中,我們采用對象來繼承。 構造器調用模式 當一個函數對象被創建時,Function構造器會運行類似這樣的代碼: this.prototype = {constructor: this} new一個函數事會發生: Function.method(new, functio...
摘要:語言精粹讀書筆記第四章函數函數字面量函數字面量包含個部分第一部分,保留字第二部分,函數名,它可以被忽略。這個超級延遲綁定使得函數對高度復用。構造器調用模式一個函數,如果創建的目的就是希望結合的前綴來調用,那它就被稱為構造器構造。 《JavaScript 語言精粹》 讀書筆記 第四章 函數 Functions 函數字面量 函數字面量包含4個部分: 第一部分, 保留字 function...
摘要:對象適用于匯集和管理數據。一個對象字面量就是包圍在一對花括號的多個名值對。嘗試從對象里取值將會導致異常。亦不會觸及原型鏈中的任何對象。嚴格模式下,不能用刪除顯式聲明的標識符,名稱或具名函數。 Javascirpt里的對象是無類型的。它對新屬性的名字和屬性的值沒有任何的限制。對象適用于匯集和管理數據。對象可以包括其他對象,所以它們可以容易地表示成樹狀或者圖形結構。 對象字面量 ...
摘要:在中數組是經常被使用到的,我們除了要學習數組的方法,還需要了解誒一下某一些方法是如何來實現的。然而我看了語言精粹中方法的一章,想記錄下書上的代碼,以便加深印象。方法移除數組中的第一個元素并且放回該元素。 在js中數組是經常被使用到的,我們除了要學習數組的方法,還需要了解誒一下某一些方法是如何來實現的。然而我看了《javascript語言精粹》中方法的一章,想記錄下書上的代碼,以便加深印...
閱讀 1695·2019-08-30 15:54
閱讀 3347·2019-08-26 17:15
閱讀 3540·2019-08-26 13:49
閱讀 2590·2019-08-26 13:38
閱讀 2302·2019-08-26 12:08
閱讀 3065·2019-08-26 10:41
閱讀 1380·2019-08-26 10:24
閱讀 3389·2019-08-23 18:35