JavaScript極簡(jiǎn)入門(mén)教程(二):對(duì)象和函數(shù)
閱讀本文需要有其他語(yǔ)言的編程經(jīng)驗(yàn)。
JavaScript 中的簡(jiǎn)單類型包括:
1.數(shù)字
2.字符串
3.布爾(true 和 false)
4.null
5.undefined
此外的其他類型均是對(duì)象(我們不要被 typeof 操作符的返回值所迷惑),例如:
1.函數(shù)
2.數(shù)組
3.正則表達(dá)式
4.對(duì)象(對(duì)象自然也是對(duì)象)
對(duì)象基礎(chǔ)
在 JavaScript 中,對(duì)象是屬性的集合(對(duì)象為關(guān)聯(lián)數(shù)組),每個(gè)屬性包括:
1.屬性名,必須為字符串
2.屬性值,可以為除了 undefined 之外的任何值
通過(guò)對(duì)象 literal 創(chuàng)建對(duì)象:
// 通過(guò)對(duì)象 literal {} 創(chuàng)建空對(duì)象
var empty_object = {};
對(duì)象的屬性名和屬性值:
var stooge = {
// "first-name" 為屬性名,"Jerome" 為屬性值
"first-name": "Jerome",
// "last-name" 為屬性名,"Howard" 為屬性值
"last-name": "Howard"
};
如果屬性名是合法的標(biāo)識(shí)符,那么可以省略引號(hào):
var flight = {
airline: "Oceanic",
number: 815,
departure: {
IATA: "SYD",
time: "2004-09-22 14:55",
city: "Sydney"
},
arrival: {
IATA: "LAX",
time: "2004-09-23 10:42",
city: "Los Angeles"
}
};
我們看一下屬性訪問(wèn)的例子:
var owner = { name: "Name5566" };
owner.name; // "Name5566"
owner["name"]; // "Name5566"
owner.job; // undefined
owner.job = "coder"; // 或者 owner["job"] = "coder";
如果屬性名不是合法標(biāo)識(shí)符,那么需要用引號(hào)包裹。不存在的屬性值為 undefined。對(duì)象是通過(guò)引用而非按值傳遞:
var x = {};
var owner = x;
owner.name = "Name5566";
x.name; // x.name === "Name5566"
這里 x 和 owner 引用同一個(gè)對(duì)象。
對(duì)象的屬性可以使用 delete 操作符刪除:
delete obj.x; // 刪除對(duì)象 obj 的 x 屬性
對(duì)象的原型(prototype)
每一個(gè)對(duì)象都被鏈接了一個(gè)原型對(duì)象(prototype object),對(duì)象能夠從原型對(duì)象中繼承屬性。我們通過(guò)對(duì)象 literal 創(chuàng)建一個(gè)對(duì)象,它的原型對(duì)象為 Object.prototype 對(duì)象(Object.prototype 對(duì)象本身沒(méi)有原型對(duì)象)。我們?cè)趧?chuàng)建對(duì)象的時(shí)候,可以設(shè)置對(duì)象的原型對(duì)象(之后再討論具體的設(shè)置方法)。在嘗試獲?。ǘ切薷模?duì)象的某個(gè)屬性時(shí),如果該對(duì)象不存在此屬性,那么 JavaScript 會(huì)嘗試從此對(duì)象的原型對(duì)象中獲取此屬性,如果原型對(duì)象中沒(méi)有該屬性,那么再?gòu)拇嗽蛯?duì)象的原型對(duì)象中查找,以此類推,直到 Object.prototype 原型對(duì)象。相比獲取屬性而言,我們修改對(duì)象的某個(gè)屬性時(shí),不會(huì)影響原型對(duì)象。
函數(shù)基礎(chǔ)
在 JavaScript 中函數(shù)也是對(duì)象,其鏈接到 Function.prototype 原型對(duì)象(Function.prototype 鏈接到 Object.prototype)。函數(shù)存在一個(gè)名為 prototype 的屬性,其值的類型為對(duì)象,此對(duì)象存在一個(gè)屬性 constructor,constructor 的值為此函數(shù):
var f = function() {}
typeof f.prototype; // 'object'
typeof f.prototype.constructor; // 'function'
f === f.prototype.constructor; // true
函數(shù)是對(duì)象,你可以像使用對(duì)象一樣使用函數(shù),也就是說(shuō),函數(shù)可以保存在變量、數(shù)組中,可以作為參數(shù)傳遞給函數(shù),函數(shù)內(nèi)部可以定義函數(shù)。附帶提及一下,函數(shù)有兩個(gè)被隱藏的屬性:
1.函數(shù)的上下文
2.函數(shù)的代碼
函數(shù)的創(chuàng)建如下:
var f = function add(a, b) {
return a + b;
}
console.log(f); // 輸出 [Function: add]
關(guān)鍵字 function 后的函數(shù)名是可選的,我們制定函數(shù)名主要出于幾個(gè)目的:
1.為了遞歸調(diào)用
2.被調(diào)試器、開(kāi)發(fā)工具等用來(lái)標(biāo)識(shí)函數(shù)
很多時(shí)候我們并不需要函數(shù)名,沒(méi)有函數(shù)名的函數(shù)被叫做匿名函數(shù)。有括號(hào)包裹的為參數(shù)列表。JavaScript 不要求實(shí)參和形參匹配,例如:
var add = function(a, b) {
return a + b;
}
add(1, 2, 3); // 實(shí)參和形參不匹配
如果實(shí)參過(guò)多,那么多余的實(shí)參會(huì)被忽略,如果實(shí)參過(guò)少,那么未被賦值的形參的值為 undefined。函數(shù)一定有一個(gè)返回值,如果沒(méi)有通過(guò) return 語(yǔ)句指定返回值,那么函數(shù)返回值為 undefined。
一個(gè)函數(shù)和其訪問(wèn)的外部變量組成一個(gè)閉包。這是 JavaScript 的關(guān)鍵魅力所在。
函數(shù)調(diào)用
每個(gè)函數(shù)被調(diào)用時(shí),會(huì)接收到兩個(gè)額外的參數(shù):
1.this
2.arguments
this 的值和具體調(diào)用的模式有關(guān),在 JavaScript 中有四種調(diào)用模式:
1.方法調(diào)用模式。對(duì)象的屬性如果是函數(shù),則稱其為方法。如果一個(gè)方法通過(guò) o.m(args) 被調(diào)用,this 為對(duì)象 o(由此可見(jiàn),在調(diào)用時(shí),this 和 o 才進(jìn)行綁定),例如:
var obj = {
value: 0,
increment: function(v) {
this.value += (typeof v === 'number' ? v : 1);
}
};
obj.increment(); // this === obj
2.函數(shù)調(diào)用模式。如果一個(gè)函數(shù)不是一個(gè)對(duì)象的屬性,那么它將作為一個(gè)函數(shù)被調(diào)用,這時(shí)候 this 被綁定到全局對(duì)象上,例如:
message = 'Hello World';
var p = function() {
console.log(this.message);
}
p(); // 輸出 'Hello World'
這種行為有時(shí)候讓人疑惑,看一個(gè)例子:
obj = {
value: 0,
increment: function() {
var helper = function() {
// 對(duì)全局對(duì)象中的 value 加 1
this.value += 1;
}
// helper 被作為一個(gè)函數(shù)來(lái)調(diào)用
// 因此 this 為全局對(duì)象
helper();
}
};
obj.increment(); // obj.value === 0
我們期望的結(jié)果應(yīng)該是:
obj = {
value: 0,
increment: function() {
var that = this;
var helper = function() {
that.value += 1;
}
helper();
}
};
obj.increment(); // obj.value === 1
3.構(gòu)造函數(shù)調(diào)用模式。意圖使用 new 前綴的函數(shù)被叫做構(gòu)造函數(shù),例如:
// Test 被叫做構(gòu)造函數(shù)
var Test = function(string) {
this.message = string;
}
var myTest = new Test("Hello World");
一個(gè)函數(shù)前面可以加上 new 來(lái)調(diào)用(這樣的函數(shù)通常大寫(xiě)開(kāi)頭),加上 new 之后將創(chuàng)建一個(gè)鏈接到此函數(shù)的 prototype 屬性的對(duì)象,且構(gòu)造函數(shù)中 this 為此對(duì)象。
4.apply 調(diào)用模式。函數(shù)的 apply 方法被用于調(diào)用函數(shù),其有兩個(gè)參數(shù),第一個(gè)為 this,第二個(gè)為參數(shù)數(shù)組,例如:
var add = function(a, b) {
return a + b;
}
var ret = add.apply(null, [3, 4]); // ret === 7
函數(shù)調(diào)用時(shí),我們能夠訪問(wèn)一個(gè)名為 arguments 的類數(shù)組(非真正的 JavaScript 數(shù)組),其包含了所有的實(shí)參,這樣我們就能實(shí)現(xiàn)變長(zhǎng)參數(shù):
var add = function() {
var sum = 0;
for (var i=0; i<arguments.length; ++i) {
sum += arguments[i];
}
return sum;
}
add(1, 2, 3, 4);
異常
現(xiàn)在來(lái)說(shuō)說(shuō) JavaScript 的異常處理機(jī)制。我們使用 throw 語(yǔ)句來(lái)拋出異常,try-cache 語(yǔ)句來(lái)捕獲并處理異常:
var add = function (a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
// 拋出異常
throw {
name: 'TypeError',
message: 'add needs numbers'
};
}
return a + b;
}
// 捕獲并處理異常
try {
add("seven");
// e 為拋出的異常對(duì)象
} catch (e) {
console.log(e.name + ': ' + e.message);
}
為JavaScript 類型添加屬性
JavaScript 中大多數(shù)類型存在構(gòu)造函數(shù):
1.對(duì)象的構(gòu)造函數(shù)為 Object
2.數(shù)組的構(gòu)造函數(shù)為 Array
3.函數(shù)的構(gòu)造函數(shù)為 Function
4.字符串的構(gòu)造函數(shù)為 String
5.數(shù)字的構(gòu)造函數(shù)為 Number
6.布爾的構(gòu)造函數(shù)為 Boolean
7.正則表達(dá)式的構(gòu)造函數(shù)為 RegExp
我們可以向構(gòu)造函數(shù)的 prototype 添加屬性(常添加方法),使得此屬性對(duì)相關(guān)變量可用:
Number.prototype.integer = function() {
return Math[this < 0 ? 'ceil' : 'floor'](this);
}
(1.1).integer(); // 1
作用域
JavaScript 需要通過(guò)函數(shù)來(lái)構(gòu)建作用域:
function() {
// ...
}();
這里創(chuàng)建并執(zhí)行了一個(gè)匿名函數(shù)。通過(guò)作用域能夠隱藏不希望暴露的變量:
var obj = function() {
// 隱藏 value,外部無(wú)法訪問(wèn)
var value = 0;
return {
// 僅此方法可以修改 value
increment: function() {
value += 1;
},
// 僅此方法可以讀取 value
getValue: function() {
return value;
}
};
}();
obj.increment();
obj.getValue() === 1;
繼承
JavaScript 實(shí)現(xiàn)繼承的方式很多。
在創(chuàng)建對(duì)象時(shí),我們可以設(shè)置對(duì)象關(guān)聯(lián)的原型對(duì)象,我們這樣做:
// 創(chuàng)建一個(gè)對(duì)象 o,其原型對(duì)象為 {x:1, y:2}
var o = Object.create({x:1, y:2});
Object.create 方法被定義在 ECMAScript 5 中,如果你使用 ECMAScript 3 時(shí)可以自己實(shí)現(xiàn)一個(gè) create 方法:
// 如果未定義 Object.create 方法
if (typeof Object.create !== 'function') {
// 創(chuàng)建 Object.create 方法
Object.create = function (o) {
var F = function () {};
F.prototype = o;
// 創(chuàng)建一個(gè)新對(duì)象,此對(duì)象的原型對(duì)象為 o
return new F();
};
}
通過(guò) Object.create 方法我們進(jìn)行基于原型繼承:一個(gè)新對(duì)象直接繼承一個(gè)舊對(duì)象的屬性(相對(duì)于基于類的繼承,這里無(wú)需類的存在,對(duì)象直接繼承對(duì)象)。范例:
var myMammal = {
name: 'Herb the Mammal',
get_name: function() {
return this.name;
},
says: function() {
return this.saying || '';
}
};
// 繼承 myMammal
var myCat = Object.create(myMammal);
myCat.name = 'Henrietta';
myCat.saying = 'meow';
myCat.purr = function(n) {
var i, s = '';
for (i = 0; i < n; i += 1) {
if (s) {
s += '-';
}
s += 'r';
}
return s;
};
myCat.get_name = function() {
return this.says() + ' ' + this.name + ' ' + this.says();
};
上面的代碼很簡(jiǎn)單,但是沒(méi)法保護(hù)私有成員。我們可以使用模塊模式。在模塊模式中,某類對(duì)象由一個(gè)函數(shù)產(chǎn)生,并利用函數(shù)作用域保護(hù)私有成員不被外部訪問(wèn):
// mammal 函數(shù),用于構(gòu)造 mammal 對(duì)象
var mammal = function(spec) {
// that 為構(gòu)造的對(duì)象
var that = {};
// 公有方法 get_name 可被外部訪問(wèn)
that.get_name = function() {
// spec.name 外部無(wú)法直接訪問(wèn)
return spec.name;
};
// 公有方法 says 可被外部訪問(wèn)
that.says = function() {
// spec.saying 外部無(wú)法直接訪問(wèn)
return spec.saying || '';
};
return that;
};
// 創(chuàng)建 mammal 對(duì)象
var myMammal = mammal({name: 'Herb'});
// cat 函數(shù),用于構(gòu)造 cat 對(duì)象
var cat = function(spec) {
spec.saying = spec.saying || 'meow';
// cat 繼承自 mammal,因此先構(gòu)造出 mammal 對(duì)象
var that = mammal(spec);
// 添加公有方法 purr
that.purr = function(n) {
var i, s = '';
for (i = 0; i < n; i += 1) {
if (s) {
s += '-';
}
s += 'r';
}
return s;
};
// 修改公有方法 get_name
that.get_name = function() {
return that.says() + ' ' + spec.name +
' ' + that.says();
return that;
};
};
// 創(chuàng)建 cat 對(duì)象
var myCat = cat({name: 'Henrietta'});
在模塊模式中,繼承是通過(guò)調(diào)用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)的。另外,我們還可以在子類中訪問(wèn)父類的方法:
Object.prototype.superior = function(name) {
var that = this, method = that[name];
return function() {
return method.apply(that, arguments);
};
};
var coolcat = function (spec) {
// 獲取子類的 get_name 方法
var that = cat(spec), super_get_name = that.superior('get_name');
that.get_name = function(n) {
return 'like ' + super_get_name() + ' baby';
};
return that;
};
相關(guān)文章
JavaScript字符串String和Array操作的有趣方法
字符串和數(shù)組在程序編寫(xiě)過(guò)程中是十分常用的類型,因此程序語(yǔ)言都會(huì)將String和Array作為基本類型,并提供許多字符串和數(shù)組的方法來(lái)簡(jiǎn)化對(duì)字符串的操作2012-12-12
JavaScript 計(jì)算笛卡爾積實(shí)例詳解
這篇文章主要介紹了JavaScript 計(jì)算笛卡爾積實(shí)例詳解的相關(guān)資料,這里附有實(shí)例代碼,需要的朋友可以參考下2016-12-12
JavaScript中Object和Function的關(guān)系小結(jié)
JavaScript 中 Object 和 Function 的關(guān)系是微妙的,他們互為對(duì)方的一個(gè)實(shí)例。2009-09-09
Javascript 鼠標(biāo)移動(dòng)上去 滑塊跟隨效果代碼分享
這篇文章主要介紹了Javascript 鼠標(biāo)移動(dòng)上去 滑塊跟隨效果代碼,有需要的朋友可以參考一下2013-11-11
vant uploader實(shí)現(xiàn)上傳圖片拖拽功能(設(shè)為封面)
這篇文章主要介紹了vant uploader實(shí)現(xiàn)上傳圖片拖拽功能(設(shè)為封面),這個(gè)功能在日常生活中經(jīng)常會(huì)用到,操作非常方便,今天通過(guò)實(shí)例代碼介紹實(shí)現(xiàn)過(guò)程,需要的朋友可以參考下2021-10-10
如何在uni-app使用微軟的文字轉(zhuǎn)語(yǔ)音服務(wù)
有了語(yǔ)音識(shí)別,交流就會(huì)變得很簡(jiǎn)單,下面這篇文章主要給大家介紹了關(guān)于如何在uni-app使用微軟的文字轉(zhuǎn)語(yǔ)音服務(wù)的相關(guān)資料,需要的朋友可以參考下2022-06-06
使用plupload自定義參數(shù)實(shí)現(xiàn)多文件上傳
這篇文章主要介紹了使用plupload自定義參數(shù)實(shí)現(xiàn)多文件上傳的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07

