Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
全
市
第
一
javascript是一種腳本語言只要有javascript引擎即可(Mozilla,Google,微軟,其它宿主環境)
? javascript是基于對象的語言1)可以創建對象
2)可以使用內置對象3)沒有類的概念,沒有方法的重載
? 與java無任何關系,除了名字和部分語法
? javascript不能打開、讀、寫、保存計算機上的文件
? javascript不能編寫破壞計算機上任何資源的病毒
? javascript在不同瀏覽器的差異性
? JS是弱類型的,內置類型簡單且清晰
? number : 數字
? boolean : 布爾值
? string : 字符串
? undefined : 未定義
? null :空值
? function : 函數
? object : 對象
? 代表一切未知的事物,js引擎不能理解的東西,如 :
1) 對象沒有的屬性
2) 未傳入的參數
3) 函數未返回值
例:var a=b+1;
例:var a=1;.? Number.MAX_VALUE : 返回 JScript 能表達的最大的數
。約等于 1.79E+308。? Number.MIN_VALUE : 返回 JScript 最接近0的數。約等
于 5E-324。全局對象(Gobal)中還有兩個屬性與number類型的運
算有關:? NaN : 算術表達式的運算結果不是數字,則返回NaN
值。例: var v1=10 * 'a';
isNaN(v1);
? Infinity : 比MAX_VALUE更大的數。
? 例:var a=true,b=false;
? javascript中的if語句中的條件
1) boolean
2) string 空字符串返回的結果是false,其他是true
3)object類型,null是false,其他是true
4)function類型,都輸true
5)number,0,0.00為false,其他為true
6)undefined, 都是false
? 例:var a="hello world!";
? concat
? indexof
? charAt
? lastIndexOf
? 在javascript中,很多功能、靈活性以及表達能力都來自函數,包括實現面向對象語法。
? function定義有2種
函數function
? 第一種(聲明式)
function myfunc()
{
alert("hello");
};
print(typeof(myfunc));
? 第二種(變量式)
var myfunc=function ()
{
alert("hello");
};
print(typeof(myfunc));
JavaScript 函數只是一個命了名的變量而已,其變量類型即為function,變量的值就是我
們編寫的函數代碼體。
問題:既然函數只是變量,那么變量就可以被隨意賦值并用到任意地方?
var myfunc=function ()
{
alert("hello");
};
myfunc(); //第一次調用myfunc,輸出hello
myfunc=function ()
{
alert("yeah");
};
myfunc(); //第二次調用myfunc,將輸出yeah
答案是肯定的!在第一次調用函數之后,函數變量又被賦予了新的函數
代碼體,使得第二次調用該函數時,出現了不同的輸出。
function myfunc ()
{
print("hello");
};
myfunc(); //這里調用myfunc,輸出yeah 而不是hello
function myfunc ()
{
print("yeah");
};
myfunc(); //這里調用myfunc,當然輸出yeahJavaScript 執行引擎并非一行一行地分析和執行程序,而是一段一段地分析執行的。而且,在
同一段程序的分析執行中,定義式的函數語句會被提取出來優先執行。函數定義執行完之后,才會按順序
執行其他語句代碼。也就是說,在第一次調用myfunc 之前,第一個函數語句定義的代碼邏輯,已被第二
個函數定義語句覆蓋了。所以,兩次都調用都是執行最后一個函數邏輯了。
函數function
? 函數也可以有自己的成員,函數。如:function myfun(){};
myfun.name='123';
myfun.yourfun=function(){}
? 任何一個函數都可以為其動態地添加或去除屬性,這些屬性可以是簡單類型,可以是對象,也可以是其他函數。也就是說,函數具有對象的全部特征,你完全可以把函數當對象來用。其實,函數就是對象,只不過比一般的對象多了一個括號"()"操作符,這個操作符用來執行函數的邏輯。即,函數本身還可以被調用,一般對象卻不可以被調用,除此之外完全相同
? javascript中的方法沒有重載,同名函數將被覆蓋。
每個函數都有一個prototype屬性,該屬性儲存的就是原型對象
function foo(a,b){ return a*b;}
typeof(foo.prototype) // object
foo.prototype={
x : 111,
y:222,
fn : function(){this.x+this.y}
}
? JavaScript 中不管多么復雜的數據和代碼,都可以組織成object 形式的
? 定義方式:
方式1:var obj=new Object();
方式2:var obj={};
從方式2可以看出,javascript的對象并不需要類就能產生,其實javascript沒有類的概念
? Javascript是一種基于對象(object-based)的語言,你遇到的所有東西幾乎都是對象。但是,它又不是一種真正的面向對象編程(OOP)語言,因為它的語法中沒有class(類)。
? 那么,如果我們要把"屬性"(property)和"方法"(method),封裝成一個對象,甚至要從原型對象生成一個實例對象,我們應該怎么做呢?
? 假定我們把貓看成一個對象,它有"名字"和"顏色"兩個屬性。
var Cat={
name : '',
color : ''
}
? 現在,我們需要根據這個原型對象的規格(schema),生成兩個實例對象。
var cat1={}; // 創建一個空對象cat1.name="大毛"; // 按照原型對象的屬性賦值cat1.color="黃色";
var cat2={};
cat2.name="二毛";cat2.color="黑色";
? 好了,這就是最簡單的封裝了,把兩個屬性封裝在一個對象里面。但是,這樣的寫法有兩個缺點,一是如果多生成幾個實例,寫起來就非常麻煩;二是實例與原型之間,沒有任何辦法,可以看出有什么聯系。
原始模式的改進? 我們可以寫一個函數,解決代碼重復的問題。
function Cat(name,color){
return {
name:name,
color:color
}
}
? 然后生成實例對象,就等于是在調用函數:
? var cat1=Cat("大毛","黃色");
? var cat2=Cat("二毛","黑色");
? 這種方法的問題依然是,cat1和cat2之間沒有內
在的聯系,不能反映出它們是同一個原型對象的實例。
? 為了解決從原型對象生成實例的問題,Javascript提供了一個構造函數(Constructor)模式。
? 所謂"構造函數",其實就是一個普通函數,但是內部使用了this變量。對構造函數使用new運算符,就能生成實例,并且this變量會綁定在實例對象上。
? 比如,貓的原型對象現在可以這樣寫,function Cat(name,color){
this.name=name;
this.color=color;
}
? 我們現在就可以生成實例對象了。var cat1=new Cat("大毛","黃色");var cat2=new Cat("二毛","黑色");alert(cat1.name); // 大毛alert(cat1.color); // 黃色
? 這時cat1和cat2會自動含有一個constructor屬性,指向它們的構造函數。
? alert(cat1.constructor==Cat); //true
? alert(cat2.constructor==Cat); //true
? Javascript還提供了一個instanceof運算符,驗證原型對象與實例對象之間的關系。
? alert(cat1 instanceof Cat); //true
? alert(cat2 instanceof Cat); //true
? 對象的成員名稱可以為任意字符串
? 訪問方式
1)obj.成員名
2)obj['成員名']
? 遍歷一個對象所有成員的方式 for(var item in obj){obj[item]}
構造函數方法很好用,但是存在一個浪費內存的問題。
? 請看,我們現在為Cat對象添加一個不變的屬性"type"(種類),再添加一個方法eat(吃老鼠)。那么,原型對象Cat就變成了下面這樣:
function Cat(name,color){
this.name=name;
this.color=color;
this.type="貓科動物";
this.eat=function(){alert("吃老鼠");};
}
? 還是采用同樣的方法,生成實例:
? var cat1=new Cat("大毛","黃色");
? var cat2=new Cat ("二毛","黑色");
? alert(cat1.type); // 貓科動物
? cat1.eat(); // 吃老鼠
? 表面上好像沒什么問題,但是實際上這樣做,有一個很大的弊端。那就是對于每一個實例對象,type屬性和eat()方法都是一模一樣的內容,每一次生成一個實例,都必須為重復的內容,多占用一些內存。這樣既不環保,也缺乏效率。
? alert(cat1.eat==cat2.eat); //false
? 能不能讓type屬性和eat()方法在內存中只生成一次,然后所有實例都指向那個內存地址呢?回答是可以的。
? Javascript規定,每一個構造函數都有一個prototype屬性,指向另一個對象。這個對象的所有屬性和方法,都會被構造函數的實例繼承。
? 這意味著,我們可以把那些不變的屬性和方法,直接定義在prototype對象上。
function Cat(name,color){
this.name=name;
this.color=color;
}
Cat.prototype.type="貓科動物";
Cat.prototype.eat=function(){alert("吃老鼠")};
? 然后,生成實例。
? var cat1=new Cat("大毛","黃色");
? var cat2=new Cat("二毛","黑色");
? alert(cat1.type); // 貓科動物
? cat1.eat(); // 吃老鼠
? 這時所有實例的type屬性和eat()方法,其實都是同一個內存地址,指向prototype對象,因此就提高了運行效率。
? alert(cat1.eat==cat2.eat); //true
? 搞了this是誰,記住一句話就行:方法是誰的this就是誰,方法誰也不是,this就是window,請看例子:
function WhoAmI() //定義一個函數WhoAmI{
alert("I'm " + this.name + " of " + typeof(this));
};
function 中的this關鍵字
var BillGates={name: "Bill Gates"};
BillGates.WhoAmI=WhoAmI;
BillGates.WhoAmI();//I'm Bill Gates of object
var SteveJobs={name: "Steve Jobs"};
SteveJobs.WhoAmI=WhoAmI;
SteveJobs.WhoAmI();//I'm Steve Jobs of object
? 要理解閉包,首先必須理解Javascript特殊的變量作用域
? 變量的作用域無非就是兩種:全局變量和局部變量。
? Javascript語言的特殊之處,就在于函數內部可以直接讀取全局變量。
? 例:
var n=999;
function f1(){
alert(n);
}
f1(); // 999
? 另一方面,在函數外部自然無法讀取函數內的局部變量。
? 例:function f1(){
var n=999;
}
alert(n); // error
? 這里有一個地方需要注意,函數內部聲明變量的時候,一定要使用var命令。如果不用的話,你實際上聲明了一個全局變量!
例:function f1(){
n=999;
}
f1();
alert(n); // 999
二、如何從外部讀取局部變量?
? 出于種種原因,我們有時候需要得到函數內的局部變量。但是,前面已經說過了,正常情況下,這是辦不到的,只有通過變通方法才能實現。
? 例:function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
在函數的內部,再定義一個函數。f2可以讀取f1中的局部變量,那么只要把f2作為返回值,我們不就可以在f1外部讀取它的內部變量了
? 上一節代碼中的f2函數,就是閉包。
? 各種專業文獻上的"閉包"(closure)定義非常抽象,很難看懂。我的理解是,閉包就是能夠讀取其他函數內部變量的函數。
? 由于在Javascript語言中,只有函數內部的子函數才能讀取局部變量,因此可以把閉包簡單理解成"定義在一個函數內部的函數"。
? 所以,在本質上,閉包就是將函數內部和函數外部連接起來的一座橋梁。
? 閉包可以用在許多地方。它的最大用處有兩個,一個是前面提到的可以讀取函數內部的變量,另一個就是讓這些變量的值始終保持在內存中。
例:function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
? 1)由于閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
? 2)閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。
繼承? 構造函數的繼承
一、 構造函數綁定
二、 prototype模式
三、 直接繼承prototype
四、 利用空對象作為中介
五、 拷貝繼承
? 非構造函數的繼承
一、object()方法
二、淺拷貝
三、深拷貝
構造函數的繼承? 比如,現在有一個"動物"對象的構造函數。
function Animal(){
this.species="動物";}
? 還有一個"貓"對象的構造函數。function Cat(name,color){
this.name=name;
this.color=color;
}
怎樣才能使"貓"繼承"動物"呢?
構造函數綁定? 第一種方法也是最簡單的方法,使用call或apply方法,將
父對象的構造函數綁定在子對象上,即在子對象構造函數中加一行:
function Cat(name,color){
Animal.apply(this, arguments);
this.name=name;
this.color=color;
}
var cat1=new Cat("大毛","黃色");alert(cat1.species); // 動物
prototype模式? 第二種方法更常見,使用prototype屬性。
? 如果"貓"的prototype對象,指向一個Animal的實例,那么所有"貓"的實例,就能繼承Animal了。
Cat.prototype=new Animal();
Cat.prototype.constructor=Cat; // 重置構造函數
var cat1=new Cat("大毛","黃色");
alert(cat1.species); // 動物
直接繼承prototype? 第三種方法是對第二種方法的改進。由于Animal對象中,不變的屬性
都可以直接寫入Animal.prototype。所以,我們也可以讓Cat()跳過Animal(),直接繼承Animal.prototype。
? Animal對象改寫function Animal(){ }
Animal.prototype.species="動物";
? 然后,將Cat的prototype對象,然后指向Animal的prototype對象,這樣就完成了繼承。
Cat.prototype=Animal.prototype;
Cat.prototype.constructor=Cat; // 重置構造函數var cat1=new Cat("大毛","黃色");alert(cat1.species); // 動物
? 與前一種方法相比,這樣做的優點是效率比較高(不用執行和建立Animal的實例了),比較省內存。缺點是 Cat.prototype和Animal.prototype現在指向了同一個對象,那么任何對Cat.prototype的修改,都會反映到Animal.prototype。
? 所以,上面這一段代碼其實是有問題的。請看第二行
? Cat.prototype.constructor=Cat;
? 這一句實際上把Animal.prototype對象的constructor屬性也改掉了!
? alert(Animal.prototype.constructor); // Cat
利用空對象作為中介? 由于"直接繼承prototype"存在上述的缺點,所以就有第四種方法,利用一個空對象作為中介。
var F=function(){};
F.prototype=Animal.prototype;
Cat.prototype=new F();
Cat.prototype.constructor=Cat;
? 我們將上面的方法,封裝成一個函數,便于使用。
function extend(Child, Parent) {
var F=function(){};
F.prototype=Parent.prototype;
Child.prototype=new F();
Child.prototype.constructor=Child;
Child.uber=Parent.prototype; // 子對象訪問父對象通道}
extend(Cat,Animal);
var cat1=new Cat("大毛","黃色");alert(cat1.species); // 動物
這個extend函數,就是YUI庫如何實現繼承的方法。
拷貝繼承
? 上面是采用prototype對象,實現繼承。我們也可以換一種思路,純粹采用"拷貝"方法實現繼承。簡單說,如果把父對象的所有屬性和方法,拷貝進子對象,不也能夠實現繼承嗎?這樣我們就有了第五種方法。
? 首先,還是把Animal的所有不變屬性,都放到它的prototype對象上。function Animal(){}
Animal.prototype.species="動物";
? 然后,再寫一個函數,實現屬性拷貝的目的。
function extend2(Child, Parent) {
var p=Parent.prototype;
var c=Child.prototype;
for (var i in p) {
c[i]=p[i];
}
c.uber=p;
}
? 這個函數的作用,就是將父對象的prototype對象中的屬性,一一拷貝給Child對象的prototype對象。
? 使用的時候,這樣寫:
extend2(Cat, Animal);
var cat1=new Cat("大毛","黃色");
alert(cat1.species); // 動物
非構造函數的繼承? 比如,現在有一個對象,叫做"中國人"。
var Chinese={
nation:'中國'};
? 還有一個對象,叫做"醫生"。var Doctor={
career:'醫生'}
請問怎樣才能讓"醫生"去繼承"中國人",也就是說,我怎樣才能生成一個"中國醫生"的對象?
這里要注意,這兩個對象都是普通對象,不是構造函數,無法使用構造函數方法實現"繼承"。
object()方法? json格式的發明人Douglas Crockford,提出了一個
object()函數,可以做到這一點。
function object(o) {
function F() {}
F.prototype=o;
return new F();
}
? 這個object()函數,其實只做一件事,就是把子對象的prototype屬性,指向父對象,從而使得子對象與父對象連在一起。
? 使用的時候,第一步先在父對象的基礎上,生成子對象:
? var Doctor=object(Chinese);
? 然后,再加上子對象本身的屬性:
? Doctor.career='醫生';
? 這時,子對象已經繼承了父對象的屬性了。
? alert(Doctor.nation); //中國
淺拷貝? 除了使用"prototype鏈"以外,還有另一種思路:把父對象的屬性,全部拷貝給子對象,
也能實現繼承。? 下面這個函數,就是在做拷貝
function extendCopy(p) {
var c={};
for (var i in p) {
c[i]=p[i];
}
c.uber=p;
return c;
}
? 使用的時候,這樣寫:
var Doctor=extendCopy(Chinese);
Doctor.career='醫生';
alert(Doctor.nation); // 中國
? 但是,這樣的拷貝有一個問題。那就是,如果父對象的屬性等于數組或另一個對象,那么實際上,子對象獲得的只是一個內存地址,而不是真正拷貝,因此存在父對象被篡改的可能。
? 請看,現在給Chinese添加一個"出生地"屬性,它的值是一個數組。? Chinese.birthPlaces=['北京','上海','香港'];? 通過extendCopy()函數,Doctor繼承了Chinese。
? var Doctor=extendCopy(Chinese);
? 然后,我們為Doctor的"出生地"添加一個城市:
? Doctor.birthPlaces.push('廈門');
? 發生了什么事?Chinese的"出生地"也被改掉了!
? alert(Doctor.birthPlaces); //北京, 上海, 香港, 廈門
? alert(Chinese.birthPlaces); //北京, 上海, 香港, 廈門
? 所以,extendCopy()只是拷貝基本類型的數據,我們把這種拷貝叫做"淺拷貝"。這是早期jQuery實現繼承的方式。
深拷貝? 所謂"深拷貝",就是能夠實現真正意義上的數組和對象的拷貝。它的實現并不難,只要
遞歸調用"淺拷貝"就行了。
function deepCopy(p, c) {
var c=c || {};
for (var i in p) {
if (typeof p[i]==='object') {
c[i]=(p[i].constructor===Array) ? [] : {};
deepCopy(p[i], c[i]);
} else {
c[i]=p[i];
}
}
return c;
}
? 使用的時候這樣寫:
? var Doctor=deepCopy(Chinese);
? 現在,給父對象加一個屬性,值為數組。然后,在子對象上修改這個屬性:
? Chinese.birthPlaces=['北京','上海','香港'];
? Doctor.birthPlaces.push('廈門');
? 這時,父對象就不會受到影響了。
? alert(Doctor.birthPlaces); //北京, 上海, 香港, 廈門
? alert(Chinese.birthPlaces); //北京, 上海, 香港
? 目前,jQuery庫使用的就是這種繼承方法。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。