script閉合標(biāo)簽
在使用<script>嵌入 JavaScript 代碼時,當(dāng)瀏覽器遇到字符串"</script>"時黄痪,就會認(rèn)為那是結(jié)束的</script>標(biāo)簽紧帕。而通過轉(zhuǎn)義字符“/”可以解決這個問題,例如:
<script type="text/javascript">
function sayScript(){
alert("<\/script>");
}
</script>
標(biāo)識符
所謂標(biāo)識符满力,就是指變量焕参、函數(shù)、屬性的名字油额,或者函數(shù)的參數(shù)叠纷。標(biāo)識符可以是字母、下劃線(_)潦嘶、美元符號($)或數(shù)字組合起來的一或多個字符涩嚣,其中數(shù)字不能放首位。
null 和 undefined
- null == undefined
- typeof null === "object"
- 無論在什么情況下都沒有必要把一個變量的值顯式地設(shè)置為 undefined
- 只要意在保存對象的變量還沒有真正保存對象掂僵,就應(yīng)該明確地讓該變量保存 null 值航厚。
這樣做不僅可以體現(xiàn) null 作為空對象指針的慣例,而且也有助于進(jìn)一步區(qū)分 null 和 undefined锰蓬。
字符串
- 對非字符串執(zhí)行字符串操作幔睬,目標(biāo)為其
toString()
方法返回值
數(shù)字
- 對對象執(zhí)行的數(shù)字操作,目標(biāo)為其
valueOf()
方法返回值
浮點數(shù)
- 浮點數(shù)值的最高精度是 17 位小數(shù)芹扭,但在進(jìn)行算術(shù)計算時其精確度遠(yuǎn)遠(yuǎn)不如整數(shù)麻顶。例如, 0.1+0.2和0.1*3的結(jié)果不是 0.3舱卡,而是 0.30000000000000004辅肾。
因此,永遠(yuǎn)不要測試某個特定的浮點數(shù)值轮锥。
關(guān)于浮點數(shù)值計算會產(chǎn)生舍入誤差的問題:這是使用基于IEEE754 數(shù)值的浮點計算的通病矫钓, ECMAScript 并非獨此一家;其他使用相同數(shù)值格式的語言也存在這個問題
大小限制
- 由于內(nèi)存的限制, ECMAScript 并不能保存世界上所有的數(shù)值新娜。 ECMAScript 能夠表示的最小數(shù)值保存在 Number.MIN_VALUE 中——在大多數(shù)瀏覽器中赵辕,這個值是 5e-324;能夠表示的最大數(shù)值保存在Number.MAX_VALUE 中——在大多數(shù)瀏覽器中杯活,這個值是1.7976931348623157e+308匆帚。
如果某次計算的結(jié)果得到了一個超出 JavaScript 數(shù)值范圍的值,那么這個數(shù)值將被自動轉(zhuǎn)換成特殊的 Infinity 值旁钧。具體來說吸重,如果這個數(shù)值是負(fù)數(shù),則會被轉(zhuǎn)換成-Infinity(負(fù)無窮)歪今,如果這個數(shù)值是正數(shù)嚎幸,則會被轉(zhuǎn)換成 Infinity(正無窮)。
Infinity 不是能夠參與計算的數(shù)值嫉晶。要想確定一個數(shù)值是不是有窮的(換句話說,是不是位于最小和最大的數(shù)值之間)田篇,可以使用 isFinite()函數(shù)替废。這個函數(shù)在參數(shù)位于最小與最大數(shù)值之間時會返回 true,如下面的例子所示:
var result = Number.MAX_VALUE + Number.MAX_VALUE;
alert(isFinite(result)); //false
盡管在計算中很少出現(xiàn)某些值超出表示范圍的情況泊柬,但在執(zhí)行極小或極大數(shù)值的計算時椎镣,檢測監(jiān)控這些值是可能的,也是必需的兽赁。 - 訪問 Number.NEGATIVE_INFINITY 和 Number.POSITIVE_INFINITY 也可以得到負(fù)和正 Infinity 的值状答。可以想見刀崖,這兩個屬性中分別保存著-Infinity 和Infinity惊科。
NaN
- 任何數(shù)字除以0變?yōu)镹aN,無法轉(zhuǎn)換為數(shù)字的強(qiáng)制轉(zhuǎn)化時也會變成NaN
- NaN==NaN為false,因此需要判斷目標(biāo)是否為NaN時采用isNaN(NaN)
alert(isNaN(NaN)); //true
alert(isNaN(10)); //false( 10 是一個數(shù)值)
alert(isNaN("10")); //false(可以被轉(zhuǎn)換成數(shù)值 10)
alert(isNaN("blue")); //true(不能轉(zhuǎn)換成數(shù)值)
alert(isNaN(true)); //false(可以被轉(zhuǎn)換成數(shù)值 1)
Object
ECMA本地對象(宿主對象不一定)中Object 的每個實例都具有下列屬性和方法:
- constructor:保存著用于創(chuàng)建當(dāng)前對象的函數(shù)。
- hasOwnProperty(propertyName):用于檢查給定的屬性在當(dāng)前對象實例中(而不是在實例的原型中)是否存在亮钦。其中馆截,作為參數(shù)的屬性名(propertyName)必須以字符串形式指定(例如: o.hasOwnProperty("name"))。
- isPrototypeOf(object):用于檢查傳入的對象是否是傳入對象的原型蜂莉。
- propertyIsEnumerable(propertyName):用于檢查給定的屬性是否能夠使用 for-in 語句
來枚舉孙咪。與 hasOwnProperty()方法一樣,作為參數(shù)的屬性名必須以字符串形式指定巡语。 - toLocaleString():返回對象的字符串表示,該字符串與執(zhí)行環(huán)境的地區(qū)對應(yīng)淮菠。
- toString():返回對象的字符串表示男公。
- valueOf():返回對象的字符串、數(shù)值或布爾值表示。通常與 toString()方法的返回值
相同枢赔。
布爾操作符
- 邏輯非 ! 邏輯非操作符首先會將它的操作數(shù)轉(zhuǎn)換為一個布爾值澄阳,然后再
對其求反。- 因此!!等價于Boolean()
- 邏輯與 &&
- 依次判斷直到為false,并返回最后一個值
- 邏輯或 ||
- 依次判斷直到為true,并返回最后一個值
對象的類型 基本類型值和引用類型值
- 基本類型值:五大基本類型
- 引用類型值:對象 數(shù)組 RegExp Date Function
- 無法給基本類型值添加自定義屬性,如var str='some text';
- 但如var str = new String("some text");則可添加自定義屬性
- 事實上每當(dāng)如1中聲明一個基本類型值的時候踏拜,后臺就會如2中創(chuàng)建一個對應(yīng)的基本包裝類型的對象
var str1 = "Nicholas";
str1.age = 27;
alert(str1.age); //undefined
var str2 = new String("Nicholas");
str2.age = 27;
alert(str2.age); //27
- 復(fù)制引用類型時,復(fù)制的其實是指針而非對象本身,因此兩變量指向同一對象
- 注意函數(shù)參數(shù)的傳遞方式
function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"
- 確定一個值是哪種基本類型可以使用 typeof 操作符碎赢,而確定一個值是哪種引用類型可以使用instanceof 操作符。
數(shù)組的迭代和歸并
迭代
- every():對數(shù)組中的每一項運行給定函數(shù)速梗,如果該函數(shù)對每一項都返回 true肮塞,則返回 true。
- filter():對數(shù)組中的每一項運行給定函數(shù)姻锁,返回該函數(shù)會返回 true 的項組成的數(shù)組枕赵。
- forEach():對數(shù)組中的每一項運行給定函數(shù)。這個方法沒有返回值位隶。
- map():對數(shù)組中的每一項運行給定函數(shù)拷窜,返回每次函數(shù)調(diào)用的結(jié)果組成的數(shù)組。
- some():對數(shù)組中的每一項運行給定函數(shù)涧黄,如果該函數(shù)對任一項返回 true篮昧,則返回 true。
歸并
- reduce()
- reduceRight():類似reduce笋妥,但順序相反
以上方法都不會修改數(shù)組中的包含的值懊昨。
函數(shù)
- 函數(shù)是對象,函數(shù)名是指針
- 對指針的改動(如添加屬性)會反應(yīng)到對象上,但是對指針的重新賦值會解除綁定,不會對對象產(chǎn)生影響
- caller和callee
基本包裝類型
- 創(chuàng)建實例時均優(yōu)先用直接方式創(chuàng)建,因采用對象方式新建會有些反常理的因素
Boolean
Number
String
eval方法
- 嚴(yán)格模式下無法使用
- eval()會將字符串參數(shù)插入到所在位置并當(dāng)做代碼執(zhí)行
- 該功能過于強(qiáng)大,因此尤其在涉及用戶輸入內(nèi)容時,應(yīng)該謹(jǐn)慎使用,防止被代碼注入
var a='alert ("hello world")';
eval(a);
對象
兩種屬性
在ES5中,我們?yōu)榱嗣枋鰧傩?property)的各種特征挽鞠,定義了特性(attribute)疚颊。在JavaScript中不能直接訪問特性,我們把它放在兩對方括號中信认,例如[[Enumerable]]材义。
-
數(shù)據(jù)屬性
- 數(shù)據(jù)屬性一般用于存儲數(shù)據(jù)數(shù)值
- [[Configurable]]:默認(rèn)為true。表示能否通過delete刪除屬性從而重新定義屬性嫁赏,能否修改屬性特性(除了writable)其掂,或者能否把屬性修改為訪問器屬性;
- [[Enumerable]]:默認(rèn)為true潦蝇。表示能否通過for-in循環(huán)返回屬性款熬;
- [[Writable]]:默認(rèn)為true。表示能否修改屬性的值攘乒。
- [[Value]]:默認(rèn)值為undefined贤牛。表示包含屬性的數(shù)據(jù)值。讀寫屬性值都從這個位置進(jìn)行则酝。
- 數(shù)據(jù)屬性一般用于存儲數(shù)據(jù)數(shù)值
var person = {
name: "Scott"
}
Object.defineProperty(person,"name",{
writable:false;
})
console.log(person.name); //"Scott"
person.name = "Evan";
console.log(person.name); //"Scott"
- 訪問器屬性
-
訪問器屬性不包含數(shù)據(jù)值殉簸。它包含一對getter和setter函數(shù)。當(dāng)讀取訪問器屬性時,會調(diào)用getter函數(shù)并返回有效值般卑;當(dāng)寫入訪問器屬性時武鲁,會調(diào)用setter函數(shù)并傳入新值,setter函數(shù)負(fù)責(zé)處理數(shù)據(jù)蝠检。該屬性有四個特性:
- [[Configurable]]:默認(rèn)為true沐鼠。表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性特性叹谁,或者能否把屬性修改為訪問器屬性饲梭;
- [[Enumerable]]:默認(rèn)為true。表示能否通過for-in循環(huán)返回屬性本慕;
- [[Get]]:讀取屬性時調(diào)用的函數(shù)排拷,默認(rèn)為undefined;
- [[Set]]:寫入屬性時調(diào)用的函數(shù)锅尘,默認(rèn)為undefined监氢。
訪問器屬性不能直接定義,必須通過Object.defineProperty()函數(shù)定義藤违,例如:
-
var person = {
_name: "Scott",
_age: 24,
_tel: 86247
};
//name屬性為只讀的
Object.defineProperty(person,"name",{
get: function(){
return this._name;
}
});
//age屬性為只寫不可讀的
Object.defineProperty(person,"age",{
set: function(p){
this._age = p;
}
});
//tel屬性為可讀可寫的
Object.defineProperty(person,"tel",{
get:function(){
return this._tel;
},
set: function(p){
this._tel = p;
}
});
console.log(person.name); //"Scott"
person.name = "Evan";
console.log(person.name); //"Scott"浪腐,對name屬性的修改無效
console.log(person.age); //undefined,不可讀屬性
person.age = 25;
console.log(person._age); //25顿乒,已經(jīng)修改
console.log(person.tel); //"86247"议街,可讀屬性
person.tel = "13975";
console.log(person.tel); //"13975",可以修改
屬性前面的下劃線表示只能通過對象方法訪問的屬性璧榄。當(dāng)我們使用person.name時實際上調(diào)用的是name屬性的getter函數(shù)特漩,為person.name賦值時調(diào)用的是name屬性的setter函數(shù),這樣屬性和訪問器之間的關(guān)系就很清晰了骨杂。
讀取屬性的特性
- Object.getOwnPropertyDescriptor()涂身,兩個參數(shù):屬性所在的對象和要讀取其描述符的屬性名稱。返回值是一個對象搓蚪,如果是訪問器屬性蛤售,這個對象的屬性有 configurable、 enumerable妒潭、 get 和 set悴能;如果是數(shù)據(jù)屬性,這個對象的屬性有 configurable雳灾、 enumerable漠酿、 writable 和 value。
var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
alert(descriptor.value); //2004
alert(descriptor.configurable); //false
工廠模式
- 可以無數(shù)次地調(diào)用函數(shù)構(gòu)建對象
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ù)模式
- 除了使用 new 操作符并把使用的包裝函數(shù)叫做構(gòu)造函數(shù)之外谎亩,這個模式跟工廠模式其實是一模一樣的
function Person(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 friend = new Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas"
構(gòu)造函數(shù)模式
- 使用new之后this指向新對象而非window,且自帶隱式返回語句 : return this
- alert(person1 instanceof Object); //true
- alert(person1 instanceof Person); //true
- alert(person1.constructor == Person); //true
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");
- 幾種調(diào)用構(gòu)造函數(shù)方法
// 當(dāng)作構(gòu)造函數(shù)使用
var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName(); //"Nicholas"
// 作為普通函數(shù)調(diào)用
Person("Greg", 27, "Doctor"); // 添加到 window
window.sayName(); //"Greg"
// 在另一個對象的作用域中調(diào)用 **(偽造對象經(jīng)典繼承)**
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"
原型鏈
- 幾種基本數(shù)據(jù)類型的對象方法,其實處于構(gòu)造函數(shù)的prototype中
判斷原型鏈屬性還是自身屬性
- hasOwnProperty()方法,只在給定屬性存在于對象實例中時记靡,才會返回 true谈竿。
alert(person1.hasOwnProperty("name")); //false
person1.name = "Greg";
alert(person1.name); //"Greg"—— 來自實例
alert(person1.hasOwnProperty("name")); //true
delete person1.name;
alert(person1.name); //"Nicholas"—— 來自原型
alert(person1.hasOwnProperty("name")); //false
判斷屬性是否存在于自身或原型鏈
- in方法 只要存在該屬性即為true
delete person1.name;
alert(person1.name); //"Nicholas" —— 來自原型
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true
更方便的原型封裝方式:令原型=對象
- 前面例子中每添加一個屬性和方法就要敲一遍 Person.prototype。為減少不必要的輸入摸吠,也為了從視覺上更好地封裝原型的功能,更常見的做法是用一個包含所有屬性和方法的對象字面量來重寫整個原型對象嚎花,如下面的例子所示寸痢。
function Person(){}
Person.prototype = {
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};
- 代價是 constructor 屬性不再指向 Person 了。
- 每創(chuàng)建一個函數(shù)紊选,就會同時創(chuàng)建它的 prototype 對象啼止,這個對象也會自動獲得 constructor 屬性(即constructor 屬性位于原型上而非實例上)。而我們在這里使用的語法兵罢,本質(zhì)上完全重寫了默認(rèn)的 prototype 對象献烦,因此 constructor 屬性也就變成了新對象的 constructor 屬性(指向 Object 構(gòu)造函數(shù)),不再指向 Person 函數(shù)卖词。
- 此時可以像下面這樣特意將它設(shè)置回適當(dāng)?shù)闹怠?/li>
function Person(){}
Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};
原型的動態(tài)性
- 實例與原型間為松散連接,只是指針而非副本;
- 也因此,修改實例從原型繼承的屬性會導(dǎo)致,原型中對應(yīng)屬性也發(fā)生變化
- 因此只要在調(diào)用時,原型中有該屬性即可,而非實例創(chuàng)建時需要該屬性;若原型被重新定義,則與原指針斷開連接(類似module.exports和exports)
function Person(){
}
var friend = new Person();
Person.prototype.hello='nihao';
Person.prototype = {
constructor: Person,
name : "Nicholas",
sayName : function () {
alert(this.name);
}
};
console.log(friend.hello); //nihao
var friend1 = new Person();
friend1.sayName(); //error
console.log(friend1.hello); //undefined
原型鏈的問題解決
借用構(gòu)造函數(shù)
- 缺點:方法都在構(gòu)造函數(shù)中定義巩那,未用到原型鏈,函數(shù)復(fù)用無從談起
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){
//繼承了 SuperType
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"
組合繼承
- 組合繼承此蜈,有時候也叫做偽經(jīng)典繼承即横,指的是將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一塊,從而發(fā)揮二者之長的一種繼承模式裆赵。其背后的思路是使用原型鏈實現(xiàn)對原型屬性和方法的繼承东囚,而通過借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承。
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
//繼承屬性
SuperType.call(this, name);//第二次調(diào)用,用自身屬性覆蓋原型鏈的屬性,不怕聯(lián)動
this.age = age;
}
//繼承方法
SubType.prototype = new SuperType();//第一次調(diào)用,為獲取方法,卻也獲取了屬性
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27
原型式繼承
寄生式繼承
- 即如下的object()
組合寄生式繼承
- 彌補(bǔ)組合繼承需要調(diào)用兩次的缺陷
- 把超類的原型作為形參(不再聯(lián)動)給予新對象,對象再給予子類的原型,最終完成原型===>原型的步驟,卻只調(diào)用超類一次