JavaScript 學(xué)習(xí) - 提高篇
JavaScript 學(xué)習(xí) - 提高篇
一. JavaScript中的對象.
JavaScript中的Object是一組數(shù)據(jù)的key-value的集合, 有點(diǎn)類似于Java中的HashMap, 所有這些數(shù)據(jù)都是Object里的property. 通常情況下, JavaScript中建立一個(gè)對象用"new"加上constructor function來實(shí)現(xiàn). 如new Date(), new Object()等.
var book = new Object();
book.name = "JavaScript is Cool";
book.author = "tom";
book.pages = 514;
上面例子中的name和page就是名為book的對象中的property. 我們可以用delete來刪除Object中的property: "delete book.name;". 除了Object, Date等buildin的對象外, 我們可以寫自己的constructor function, 然后使用new就可以建立自己的對象. 如上面的book可以寫成:
function Book (name, author, page) {
this.name = name;
this.author = author;
this.page = page;
}
var abook = new Book("JavaScript is Cool", "tom", 514);
二. function的用法
在JavaScript中, function是一種數(shù)據(jù)類型, 所有的function都是從buildin的Function object 衍生的對象. 所以在JavaScript 中function可以作為參數(shù)傳遞, 可以作為Object的property, 也可以當(dāng)作函數(shù)返回值. function在JavaScript中有兩種用法, 一種是當(dāng)作constructor, 前面加上new keyword用來建立對象. 一種是當(dāng)作method, 為其他對象調(diào)用.
注意function和method在中文里的意思相當(dāng), 在有些語言里也可以通用. 但是在JavaScript中, 它們還是有所區(qū)別的. function本身是是一個(gè)對象, 而當(dāng)作為一個(gè)方法他屬于一個(gè)對象時(shí), 就成為了一個(gè)這個(gè)對象的method, 相當(dāng)于一個(gè)對象種的屬性. 也就是說method是相對于一個(gè)對象而言的, function在某些情況下成為了一個(gè)對象的method.
function Book(name, author, page) {
this.name = name;
this.author = author;
this.page = page;
this.getReader = Book_getReader;
}
function Book_getReader() {
//....
}
上面的例子種, function Book_getReader()就成為了Book的一個(gè)名為getReader的method. call()和apply()是Function object 的兩個(gè)方法, 它們也可以使一個(gè)function作為另一個(gè)對象的method來調(diào)用用. call()和apply()都需要參數(shù), 而第一個(gè)參數(shù)就是調(diào)用對象, 也就是當(dāng)function內(nèi)部出現(xiàn)this時(shí), this所指的對象. call()和apply()的區(qū)別在于call()可以傳遞任意長度參數(shù), 只要第一個(gè)參數(shù)時(shí)調(diào)用對象. 而apply只接受兩個(gè)參數(shù), 需要將除調(diào)用對象外的所有參數(shù)放入一個(gè)數(shù)組中. 即:
function getBooksWithSameAuthor(form, to) {
var name = this.author;
var books = ...
//get books written by name and from year "from" to year "to"
return books;
}
var abook = new Book("JavaScript is Cool", "tom", 514);
var books = getBooksWithSameAuthor.call(abook, 1990, 2005);
或
var books = getBooksWithSameAuthor.apply(abook, [1990, 2005]);
當(dāng)一個(gè)function不作為一個(gè)對象的method時(shí), JavaScript會(huì)認(rèn)為它是屬于一個(gè)Globle Object對象的method, 這個(gè)Globle Object在Browser中就是window類. 所以從這個(gè)角度來說, function和method又可以統(tǒng)一起來了.
Function object 還有一個(gè)非常重要的property: prototype. 它是一個(gè)predefined的prototype object. 當(dāng)一個(gè)Function用作對象的constructor時(shí), protptype property將發(fā)揮作用,中文翻譯叫原型. JavaScript的新對象就是通過function的原型來建立的. 同時(shí)我們還可以利用prototype來動(dòng)態(tài)的向?qū)ο笾刑砑訉傩? 如:
function Book (name, author, page) {
this.name = name;
this.author = author;
this.page = page;
}
var abook = new Book("JavaScript is Cool", "tom", 514);
Book.prototype.getInfo = getInfo;
function getInfo() {
return this.name + " written by " + this.author + " with " + this.page + " pages";
}
alert(abook.getInfo());
這里有一個(gè)例子, 用prototype方法來實(shí)現(xiàn)callback:
Function.prototype.andThen=function(g) {
var f=this;
return function() {
f();g();
}
};
function Manager() {
this.callback=function () {}; // do nothing
this.registerCallback=function(callbackFunction) {
this.callback=(this.callback).andThen(callbackFunction);
}
}
var manager=new Manager();
manager.registerCallback(sayHi);
manager.registerCallback(sayBye);
manager.callback();
三. JavaScript中的OO
JavaScript中的對象是一個(gè)屬性和方法的集合. JavaScript也有對應(yīng)于Java的Class和Instance的概念.我們可以把JavaScript中定義的
function(Function類的子類)看作是Class, 而利用這個(gè)function構(gòu)造的對象看是Instance. 對應(yīng)于Java的Instance Property, Instance
Method, Class(static) property, Class Method, JavaScript都可以實(shí)現(xiàn).
1. Instance Property
Instance Property就是cuntructor function中定義的property, 對于每一個(gè)instance都會(huì)有一份copy.
2. Class property
Class Property其實(shí)是cunstructor function作為對象本身所具有的屬性(和Java不一樣, Java中method不是數(shù)據(jù), 更不是對象).
3. Instance Method
Instance Method是指屬于某一對象的method, 方法內(nèi)的this代表這個(gè)method從屬的對象, 注意雖然是Instance Method, 并不是每一個(gè)Instance都有一個(gè)此方法的copy, 所有Instance 共享一個(gè)method.
4. Class Method
Class Method同樣可以理解為constructor function作為對象自己具有的方法, 和由這個(gè)constructor建立的對象沒有直接聯(lián)系. 所以Class Method方法里使用this會(huì)產(chǎn)生混淆. 因?yàn)檫@個(gè)this指的不是期望操作的對象, 而是一個(gè)Function Object(constructor).
下面的例子定義了一個(gè)復(fù)數(shù)的對象, 包含有上述四種域, 值得仔細(xì)看看:
/*
* Complex.js:
* This file defines a Complex class to represent complex numbers.
* Recall that a complex number is the sum of a real number and an
* imaginary number and that the imaginary number i is the
* square root of -1.
*/
/*
* The first step in defining a class is defining the constructor
* function of the class. This constructor should initialize any
* instance properties of the object. These are the essential
* "state variables" that make each instance of the class different.
*/
function Complex(real, imaginary) {
this.x = real; // The real part of the number
this.y = imaginary; // The imaginary part of the number
}
/*
* The second step in defining a class is defining its instance
* methods (and possibly other properties) in the prototype object
* of the constructor. Any properties defined in this object will
* be inherited by all instances of the class. Note that instance
* methods operate implicitly on the this keyword. For many methods,
* no other arguments are needed.
*/
// Return the magnitude of a complex number. This is defined
// as its distance from the origin (0,0) of the complex plane.
Complex.prototype.magnitude = function( ) {
return Math.sqrt(this.x*this.x + this.y*this.y);
};
// Return a complex number that is the negative of this one.
Complex.prototype.negative = function( ) {
return new Complex(-this.x, -this.y);
};
// Convert a Complex object to a string in a useful way.
// This is invoked when a Complex object is used as a string.
Complex.prototype.toString = function( ) {
return "{" + this.x + "," + this.y + "}";
};
// Return the real portion of a complex number. This function
// is invoked when a Complex object is treated as a primitive value.
Complex.prototype.valueOf = function( ) { return this.x; }
/*
* The third step in defining a class is to define class methods,
* constants, and any needed class properties as properties of the
* constructor function itself (instead of as properties of the
* prototype object of the constructor). Note that class methods
* do not use the this keyword: they operate only on their arguments.
*/
// Add two complex numbers and return the result.
Complex.add = function (a, b) {
return new Complex(a.x + b.x, a.y + b.y);
};
// Subtract one complex number from another.
Complex.subtract = function (a, b) {
return new Complex(a.x - b.x, a.y - b.y);
};
// Multiply two complex numbers and return the product.
Complex.multiply = function(a, b) {
return new Complex(a.x * b.x - a.y * b.y,
a.x * b.y + a.y * b.x);
};
// Here are some useful predefined complex numbers.
// They are defined as class properties, where they can be used as
// "constants." (Note, though, that they are not actually read-only.)
Complex.zero = new Complex(0,0);
Complex.one = new Complex(1,0);
Complex.i = new Complex(0,1);
四. 對象的繼承
JavaScript有多種方式模擬繼承.
1. 利用function:
function superClass() {
this.bye = superBye;
this.hello = superHello;
}
function subClass() {
this.inheritFrom = superClass;
this.inheritFrom();
this.bye = subBye;
}
或者:
function subClass() {
superClass.call(this);
}
先定義subClass的inheritFrom方法, 再調(diào)用這個(gè)方法(方法名稱并不重要), 或者直接使用Function Object 的call 方法將this做參數(shù), 都可以模擬實(shí)現(xiàn)從superClass的繼承. 注意調(diào)用superClass時(shí)的this指向. 這個(gè)方法就是在執(zhí)行subClass的cunstructor function時(shí), 先執(zhí)行supperClass的cunstructor function.這個(gè)方法的缺點(diǎn)在于子類僅僅是在自己的構(gòu)造函數(shù)中, 將this作為參數(shù)調(diào)用了父類的構(gòu)造函數(shù), 將構(gòu)造函數(shù)賦予父類的所有域賦予子類. 所以, 任何父類在構(gòu)造函數(shù)之外(通過prototype)定義的域, 子類都無法繼承. 而且子類的構(gòu)造函數(shù)一定要在定義自己的域之前調(diào)用父類的構(gòu)造函數(shù), 免得子類的定義被父類覆蓋. 使用這種方法子類也盡量不要使用prototype來定義子類的域, 因?yàn)閜rototype的定義在子類new的之后就執(zhí)行, 所以它一定會(huì)在調(diào)用父類構(gòu)造函數(shù)前, 同樣會(huì)有被父類的定義覆蓋的危險(xiǎn).
2. 利用prototype:
function superClass() {
this.bye = superBye;
this.hello = superHello;
}
function subClass() {
this.bye = subBye;
}
subClass.prototype = new superClass();
subClass.prototype.constructor = superClass;
這里將一個(gè)superClass的實(shí)例設(shè)置成subclass的原型:protytype, 由于new superClass實(shí)例一定會(huì)調(diào)用父類prototype定義的所有域, 所以這種方法避免了上一種方法的一個(gè)問題, 父類可以通過prototype來描述域. 可以實(shí)現(xiàn)從superClass的繼承. 而這個(gè)方法也有缺點(diǎn), 由于子類的peototype已經(jīng)是父類的實(shí)例(Object實(shí)例), 不能再被實(shí)例化, 所以new子類實(shí)例的時(shí)候, 父類的所有非基本數(shù)據(jù)類型(見JavaScript數(shù)據(jù)類型)都將是reference copy而非數(shù)據(jù)copy. 簡單說就是所有的父類域在子類中雖然存在, 但看起來就像Java中的static域一樣在子類間share.被一個(gè)子類改變, 所有子類都會(huì)改變.
注意這里的最后一句, 改變了子類prototype中的constructor屬性. 它對子類使用沒有影響, 僅僅是為了在調(diào)用instanceOf方法時(shí)它使得子類實(shí)例返回subClass.
3. Parasitic Inheritance (寄生繼承)
function superClass() {
this.bye = superBye;
this.hello = superHello;
}
function subClass() {
this.base = new supperClass();
base.sayBye = subBye;
return base;
}
這種繼承其實(shí)是一種擴(kuò)展, 因?yàn)樵谡{(diào)用instanceOf時(shí), 子類會(huì)返回父類名稱, 它的好處在于在構(gòu)造函數(shù)繼承的基礎(chǔ)上解放了父類, 父類可以使用prototype定義自己的域, 但是子類仍然不建議使用prototype, 以免被父類覆蓋. 為了可以使子類的instanceof返回正確類型, 我們可以再改進(jìn)一下:
function subClass() {
this.base = new supperClass();
for ( var key in this.base ) {
if ( !this[key] ) {
this[key] = this.base[key];
}
}
this.sayBye = subBye;
}
將所有的父類域拷貝給子類一份, 不再返回父類, instanceof子類實(shí)例時(shí)就可以返回正確類型.
五. this的用法
通常情況下, this代表的是前面提到的Globle Object.也就是Browser環(huán)境時(shí)的window Object. 當(dāng)function作為某一對象的 method 時(shí), this 代表這個(gè) function 所屬的 object. 下面這段代碼有格錯(cuò)誤, 涉及到this的使用:
function Employee(a) {
this.name = a;
}
function init(){
John = Employee("Johnson");
alert(John.name);
}
在init()中我們少了一個(gè)new keyword. 于是這個(gè)代碼就會(huì)報(bào)錯(cuò), 因?yàn)锽rowser把Employee當(dāng)作是window obect的一個(gè)method, 里面的this指的就是window object. init()應(yīng)該改為:
function init(){
John = new Employee("Johnson");
alert(John.name);
}
同時(shí)我們也可以將Employee的constructor函數(shù)修改, 防止類似的錯(cuò)誤:
function Employee(a) {
if (!(this instanceof Employee)) return new Employee(a);
this.name = a;
}
這樣,我們即使使用原來的init()方法, 也不會(huì)報(bào)錯(cuò)了.
六. Array in JavaScript
Array和Object本質(zhì)上是一樣的, 只是Array需要由index來索引它其中的屬性. index為>=0的整數(shù).
Array有一系列buildin的方法:
1. jion() 將array中的所有element以string的形式連在一起:
var a = [1,2,3];
s = a.join(); // s == "1,2,3"
s = a.join(": "); // s == "1: 2: 3"
2. reverse() 將Array的element順數(shù)顛倒
var a = [1,2,3];
a.reverse();
s = a.join(); // s == "3,2,1"
3. sort() 排序, 默認(rèn)按字母順序排序case sensitive, 可以自定義排序方式.
var a = [111,4,33,2];
a.sort(); // a == [111,2,33,4]
a.sort(function(a,b) { // a == [2,4,33,111]
return a-b; // Returns < 0, 0, or > 0
});
4. concat()連接多個(gè)Array
var a = [1,2,3];
a.concat(4,5); // return [1,2,3,4,5]
a.concat([4,5]); // return [1,2,3,4,5]
a.concat([4,5], [6,7]) // return [1,2,3,4,5,6,7]
a.concat(4,[5,[6,7]]); // return [1,2,3,4,5,6,7]
5. slice() 返回Array的切片, 原Array不變.
var a = [1,2,3,4,5];
a.slice(0,3); // Returns [1,2,3]
a.slice(3); // Returns [4,5]
a.slice(1,-1); // Returns [2,3,4], -1 means the last index of the array
a.slice(-3,-2); // Returns [3], from the third last index to the second last index
6. splice 向一個(gè)Array中添加或刪除element. 第一個(gè)參數(shù)表示位置, 第二個(gè)參數(shù)表示刪除長度, 后面任意長的參數(shù)表示在1刪除位置添加的elements.
var a = [1,2,3,4,5,6,7,8];
a.splice(4); // Returns [5,6,7,8]; a is [1,2,3,4]
a.splice(1,2); // Returns [2,3]; a is [1,4]
a.splice(1,1); // Returns [4]; a is [1]
var a = [1,2,3,4,5];
a.splice(2,0,'a','b'); // Returns []; a is [1,2,'a','b',3,4,5]
a.splice(2,2,[1,2],3); // Returns ['a','b']; a is [1,2,[1,2],3,3,4,5]
7. push() and pop() 向Array末尾添加或刪除element
8. unshift() and shift() 向Array的開頭添加或刪除element
相關(guān)文章
JavaScript利用el-table實(shí)現(xiàn)繪制熱度表
這篇文章主要為大家詳細(xì)介紹了JavaScript如何利用el-table實(shí)現(xiàn)繪制熱度表,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03深入了解JavaScript中邏輯賦值運(yùn)算符的應(yīng)用
邏輯賦值是對現(xiàn)有數(shù)學(xué)和二進(jìn)制邏輯運(yùn)算符的擴(kuò)展。我們先復(fù)習(xí)一下,然后看看把它們結(jié)合在一起能得到什么,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-11-11