ECMAScript
- NaN與任何運算元進行比較,都返回false
NaN < 3 // false
NaN >= 3 // false
NaN === NaN // false
NaN === 1 // false
"a" < 3 // false
"a" >=3 // false
複製程式碼
2.邏輯與操作
- 如果有任何一個運算元是null,則返回null
- 如果有任何一個運算元是undefined,則返回undefined
- 如果有任何一個運算元是NaN,則返回NaN
null && true // null
true && null // null
undefined && true // undefined
true && undefined // undefined
NaN && true // NaN
true && NaN // NaN
複製程式碼
3.邏輯或操作
- 如果兩個運算元都為null,則返回null
- 如果兩個運算元都為undefined,則返回undefined
- 如果兩個運算元都為NaN,則返回NaN
null || null // null
undefined || undefined // undefined
NaN || NaN // NaN
false || null // null
false || undefined // undefined
false || NaN // NaN
true || null // true
true || undefined // true
true || NaN // true
複製程式碼
4.null與undefined相等但不全等
null == undefined // true
null === undefined // false
複製程式碼
5.label語句
var num = 0;
outermost:
for (var i=0; i < 10; i++) {
for (var j=0; j < 10; j++) {
if (i == 5 && j == 5) {
break outermost;
}
num++;
}
}
alert(num); //55
var num = 0;
outermost:
for (var i=0; i < 10; i++) {
for (var j=0; j < 10; j++) {
if (i == 5 && j == 5) {
continue outermost;
}
num++;
}
}
alert(num); //95
複製程式碼
- 函式引數按值傳遞。 但當引數是一個物件時,即 使這個引數是按值傳遞的,引數也會按引用來訪問同一個物件。
function addTen(num) {
num += 10;
return num;
}
var num=1;
addTen(num);
console.log(num); // 1
function setName(obj) {
obj.name = "Nicholas";
}
var person = new Object();
setName(person);
console.log(person.name); //"Nicholas"
複製程式碼
實際上,當在函式內部重寫 obj 時,這 個變數引用的就是一個區域性物件了。而這個區域性物件會在函式執行完畢後立即被銷燬。
function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"
複製程式碼
6.sort方法預設按升序排列,會呼叫每個陣列項的toString()方法,然後比較字串。 也可以給sort傳遞一個比較函式,比較函式接收兩個引數,如果第一個引數應該位於第二個之前則返回一個負數,如果兩個引數相等 則返回 0,如果第一個引數應該位於第二個之後則返回一個正數
var values = [0, 1, 5, 10, 15];
values.sort();
console.log(values); // [0,1,10,15,5]
values.sort(function(a,b){
return a-b
})
console.log(values); // [0,1,5,10,15]
複製程式碼
- Date
- Date.now() 返回當前時間的毫秒數
- new Date() 返回當前時間物件
- +new Date() 返回當前時間的毫秒數,相當於Date.now()
Date.now() // 1519698546791
+new Date() // 1519698742356
複製程式碼
8.RegExp 建構函式的屬性
長屬性名 | 短屬性名 | 說明 |
---|---|---|
input | $_ | 最近一次要匹配的字串。Opera未實現此屬性 |
lastMatch | $& | 最近一次的匹配項。Opera未實現此屬性 |
lastParen | $+ | 最近一次匹配的捕獲組。Opera未實現此屬性 |
leftContext | $` | input字串中lastMatch之前的文字 |
multiline | $* | 布林值,表示是否所有表示式都使用多行模式。IE和Opera未實現此屬性 |
rightContext | $' | Input字串中lastMatch之後的文字 |
$1 | 儲存第一個匹配的捕獲組 | |
$2 | 儲存第二個匹配的捕獲組 | |
··· | ··· | |
$9 | 儲存第九個匹配的捕獲組 |
var text = "this has been a short summer";
var pattern = /(.)hort/g;
/*
* 注意:Opera 不支援 input、lastMatch、lastParen 和 multiline 屬性
* Internet Explorer 不支援 multiline 屬性
*/
if (pattern.test(text)){
console.log(RegExp.input); // this has been a short summer
console.log(RegExp.leftContext); // this has been a
console.log(RegExp.rightContext); // summer
console.log(RegExp.lastMatch); // short
console.log(RegExp.lastParen); // s
console.log(RegExp.multiline); // false
}
複製程式碼
var text = "this has been a short summer";
var pattern = /(.)hort/g;
if (pattern.test(text)){
console.log(RegExp.$_); // this has been a short summer
console.log(RegExp["$`"]); // this has been a
console.log(RegExp["$'"]); // summer
console.log(RegExp["$&"]); // short
console.log(RegExp["$+"]); // s
console.log(RegExp["$*"]); // false
}
複製程式碼
var text = "this has been a short summer";
var pattern = /(..)or(.)/g;
if (pattern.test(text)){
console.log(RegExp.$1); //sh
console.log(RegExp.$2); //t
}
複製程式碼
9.函式內部屬性
- arguments,一個類陣列物件,包含著傳入函式中的所有引數。雖然 arguments 的主要用途是儲存函式引數, 但這個物件還有一個名叫 callee 的屬性,該屬性是一個指標,指向擁有這個 arguments 物件的函式。
function a(){
console.log(arguments.callee)
}
a() // ƒ a(){
// console.log(arguments.callee)
// }
複製程式碼
- this 引用的是函式據以執行的環境物件——或者也可以說是 this 值(當在網頁的全域性作用域中呼叫函式時, this 物件引用的就是 window)
window.color = "red";
var o = { color: "blue" };
function sayColor(){
console.log(this.color);
}
sayColor(); //"red",全域性呼叫函式,this指向全域性window
o.sayColor = sayColor;
o.sayColor(); //"blue", 物件中呼叫函式,this指向該物件
var test=o.sayColor;
a(); // "red", 全域性中呼叫,this指向全域性
複製程式碼
- caller這個屬性中儲存著呼叫當前函式的==函式==引用, 如果是在全域性作用域中呼叫當前函式,它的值為 null.
function outer(){
inner();
}
function inner(){
console.log(inner.caller);
}
outer(); // ƒ outer(){
// inner();
// }
// 更鬆散的耦合
function outer(){
inner();
}
function inner(){
console.log(arguments.callee.caller);
}
outer(); // ƒ outer(){
// inner();
// }
inner(); // null,如果是在全域性作用域中呼叫當前函式,caller它的值為 null
複製程式碼
10.encodeURI,encodeURIComponent
- encodeURI() 主要用於整個URI,encodeURI()==不會==對本身屬於 URI 的特殊字元進行編碼,例如冒號、正斜槓、 問號和井字號
- encodeURIComponent(),主要用於對 URI 中的某一段, encodeURIComponent()會對它發現的任何非標準字元進行編碼
var uri = "http://www.wrox.com/illegal value.htm#start";
encodeURI(uri) // "http://www.wrox.com/illegal%20value.htm#start"
encodeURIComponent(uri) // "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"
複製程式碼
11、最快捷的陣列求最大值,陣列去重
Math.max(...[1,2,3,4,5])
Math.max.apply(Math,[1,2,3,4,5])
//陣列去重
[...new Set([2,3,4,2,6])]
Array.from(new Set([2,3,4,2,6]))
複製程式碼
12、判斷訪問一個物件的屬性是訪問的是否是原型上的屬性
function hasPrototypeProperty(obj,name){
/* in 操作符在單獨使用時,會在通過物件能夠訪問給定屬性時返回 true,無論該屬性存在於例項中還是原型中;
* 而hasOwnProperty()只在屬性存在於例項中時才返回 true
*/
return !obj.hasOwnProperty(name) && (name in obj);
}
// 例子
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person = new Person();
console.log(hasPrototypeProperty(person, "name")); //true
person.name = "Greg";
console.log(hasPrototypeProperty(person, "name")); //false
複製程式碼
13、for-in
- 在使用 for-in 迴圈時,返回的是所有能夠通過物件訪問的、可列舉的(enumerated)屬性,其中 既包括存在於例項中的屬性,也包括存在於原型中的屬性。遮蔽了原型中不可列舉屬性(即將 [[Enumerable]]標記為 false 的屬性),例項屬性也會在 for-in 迴圈中返回,因為根據規定,所有開發人員定義的屬性都是可列舉的
- 避免for-in在物件中使用
// 例子
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person = new Person();
for(var i in person){
console.log(i,person[i])
}
// name Nicholas
// age 29
// job Software Engineer
// sayName ƒ (){
// alert(this.name);
// }
複製程式碼
14.Objct.keys(),取得物件上所有==可列舉==的==例項屬性==(==不包括原型屬性==)
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var keys = Object.keys(Person);
console.log(keys); //[]
keys = Object.keys(Person.prototype);
console.log(keys); //["name", "age", "job", "sayName"]
var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var p1keys = Object.keys(p1);
console.log(p1keys); // ["name", "age"]
複製程式碼
15、組合繼承
- 組合繼承避免了原型鏈和借用建構函式的缺陷,融合了它們的優點,成為 JavaScript 中最常用的繼 承模式。而且,instanceof 和 isPrototypeOf()也能夠用於識別基於組合繼承建立的物件。
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);
this.age = age;
}
//繼承方法
SubType.prototype = new SuperType();
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
複製程式碼
16、原型式繼承
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
var a=Object.create(person);
// 相當於
var a=new Object();
a.__proto__=person;
// Object.create()方法的第二個引數與Object.defineProperties()方法的第二個引數格式相同:每個屬性都是通過自己的描述符定義的。
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person, {
name: {
value: "Greg"
}
});
alert(anotherPerson.name); //"Greg"
複製程式碼
node.js事件
// 也可以通原型的方式非常容易的將其新增到自己的建構函式中
var EventEmitter=require('events').EventEmitter,
A=function(){};
// 原型
A.prototype.__proto__ = EventEmitter.prototype;
// 或使用比較新的寫法
// A.prototype=Object.create(EventEmitter.prototype);
//所有A的例項都具備了事件功能
var a=new A();
a.on('eventName',function(arg1,arg2){
// do something
console.log('事件回撥,接受到引數:'+arg1+" "+arg2);
})
// 分發事件,並傳入引數
a.emit('eventName','引數1','引數2');
console.log(Object.getPrototypeOf(a));
複製程式碼
17、寄生組合式繼承:是引用型別最理想的繼承正規化
function inheritPrototype(subType,superType){
var prototype=superType.prototype;
prototype.constructor = subType;
subType.prototype = prototype;
}
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);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
};
instance=new SubType('xiaoming',18)
複製程式碼
18、閉包:指有權訪問另一個函式作用域中的變數的函式
- 建立閉包的常見方式,就是在一個函式內部建立另一個函式
- 閉包中,外部函式中的活動物件(定義的變數等)在函式執行完畢後不會銷燬,因為內部函式的作用域鏈仍然在引用外部函式的變數
- 副作用:記憶體洩漏;外部函式中的活動物件在函式執行完畢後不會銷燬,因此會導致記憶體洩漏,可以手動解除變數引用來確保正常回收其佔用的記憶體,從而解決記憶體洩漏
- 副作用:即閉包只能取得包含函式中任何變數的最後一個值
- this 物件是在執行時基於函式的執行環境繫結的:在全域性函式中,this 等於window,而當函式被作為某個物件的方法呼叫時,this 等於那個物件。不過,匿名函式的執行環境具有全域性性,因此其 this 物件通常指向 window。
// 外部函式
function createComparisonFunction(propertyName) {
/*
* 內部函式(一個匿名函式),訪問了外部函式中的變數propertyName
* 之所以還能夠訪問這個變數,是因為內部函式的作用域鏈中包含createComparisonFunction()的作用域
* 函式執行完畢後,外部函式的活動物件(變數propertyName等)不會被銷燬,因為內部函式作用域鏈仍然在引用這個變數;除非內部函式被銷燬,propertyName才會被銷燬
*/
return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
};
}
// 副作用:閉包只能取得包含函式中任何變數的最後一個值
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){ // 內部函式(一個匿名函式)
return i; // i只取最後一個值10
};
}
return result;
}
// 解決這一副作用:再建立另一個匿名函式包裹內部函式
function createFunction(){
var result=new Array();
for(var i=0;i<10;i++){
result[i]=function(num){ // 匿名函式1
return function(){ // 匿名函式2
return num;
}
}(i) // 立即執行,函式引數是按值傳遞的(引用型別傳的是指標)
}
return result;
}
// this
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name; // this指向全域性作用域,即window
};
}
};
alert(object.getNameFunc()()); //"The Window"
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that=this;//this指向物件object。 函式執行完後,變數that不會被銷燬(不管變數that變有沒有被使用過)
return function(){
// this指向全域性作用域window,變數that指向物件object。
return that.name
}
}
}
alert(object.getNameFunc()()); //"My Object"
// 解決閉包導致的記憶體洩漏
function assignHandler(){
var element = document.getElementById("someElement");
// 只要匿名函式存在,element的引用數至少也是1,因此它所佔用的記憶體就永遠不會被回收,導致記憶體洩漏
element.onclick = function(){
alert(element.id);
};
}
function assignHandler(){
var element = document.getElementById("someElement"),
id = element.id;
element.onclick = function(){
alert(id);
};
element = null; // 解除對element的引用,確保正常回收element佔用的記憶體 (id仍然不會被銷燬)
}
function F1() {
var a = 100
return function () {
console.log(a)
}
}
function F2(f1) {
var a = 200
console.log(f1())
}
var f1 = F1()
F2(f1) // 輸出: 100
複製程式碼
19、重新申明變數
- js重新申明變數,只會對後續的宣告視而不見(不過,它會執行後續宣告中的變數初始化,變數宣告提升)
var a=1;
var a;
console.log(a); // 1
var b=1;
var b=2;
console.log(b); // 2
複製程式碼
20、特權方法:有權訪問私有變數的公有方法
- 使用建構函式模式實現自定義型別的特權方法
- 使用原型模式來實現自定義型別的特權方法
// 建構函式模式
function MyObject(){
//私有變數和私有函式
//privateVariable由所有例項共享。
var privateVariable = 10;
function privateFunction(){
return false;
}
//特權方法
//閉包,有權訪問私有變數privateVariable;在MyObject建構函式外部,沒有任何方法能訪問到privateVariable
this.publicMethod = function (){
privateVariable++;
console.log(privateVariable)
return privateFunction();
};
}
var t=new MyObject();
t.publicMethod(); // 11 false
var h=new MyObject();
t.publicMethod(); // 12 false
function Person(name){
this.getName = function(){
return name;
};
//閉包,有權訪問私有變數name;在Person建構函式外部,沒有任何方法能訪問到name
this.setName = function (value) {
name = value;
};
}
var person = new Person("Nicholas");
alert(person.getName()); //"Nicholas"
person.setName("Greg");
alert(person.getName()); //"Greg"
// 原型模式
(function(){
//私有變數和私有函式
//privateVariable由所有例項共享。
var privateVariable = 10;
function privateFunction(){
return false;
}
//建構函式
//沒有使用 var 關鍵字,總是會建立一個全域性變數
MyObject = function(){
};
//公有/特權方法
MyObject.prototype.publicMethod = function(){
privateVariable++
console.log(privateVariable);
return privateFunction();
};
})(); // 立即執行
var t=new MyObject();
t.publicMethod(); // 11 false
var h=new MyObject();
t.publicMethod(); // 12 false
複製程式碼
BOM
1、跨瀏覽器取得頁面視口VIEW大小(瀏覽器去掉工具欄的可見大小)
var pageHeight=window.innerHeight,
pageWidth=window.innerWidth;
if(typeof pageHeight !== "number"){
if(document.compatMode === 'CSS1Compat'){
pageHeight=document.documentElement.clientHeight;
pageWidth=document.documentElement.clientWidth;
}else{
pageHeight=document.body.clientHeight;
pageWidth==docuemnt.body.clientWidth;
}
}
複製程式碼
DOM
2、偏移量offsetLeft、offsetTop、offsetHeight、offsetWidth
- offsetLeft(包含marginLeft)和offsetTop(包含marginTop)是相對於offsetParent的
- offsetParent不一定是parentNode,例如<td>的offsetParent是<table>,因為<table>是DOM中距離<td>最近的一個有大小的元素
- offsetHeight = height+ paddingTop + paddingBottom + borderTop + borderBottom
- offsetWith = width + paddingLeft + paddingRight + borderLeft + borderRight
// 取得某個元素在頁面上的偏移量:將這個元素的offsetLeft和offsetTop與其offsetParent的相同屬性相加,如此迴圈至根元素,就可以得到一個基本的值
function getElementLeft(element){
var actualLeft=element.offsetLeft,
current=element.offsetParent;
while (current !=null){
actualLeft += current.offsetLeft;
current = current.offsetParent;
}
return actualLeft;
}
function getElementTop(element){
var actualTop = element.offsetTop,
current = element.offsetParent;
while (current !== null){
actualTop += current. offsetTop;
current = current.offsetParent;
}
return actualTop;
}
複製程式碼
3、客戶區大小clientHeight、clientWidht,客戶區大小就是元素內部的空間大小,因此滾動條佔用的空間不計算在內。 參見瀏覽器視口大小
- clienHeight = height + paddingTop + paddingBottom
- clientWidth = width + paddingLeft + paddingRight
- 如果有滾動條,要去掉滾動條佔用的空間
- 對於不包含滾動條的頁面而言, scrollWidth 和 scrollHeight 與 clientWidth 和 clientHeight 之間的關係並不十分清晰
4、滾動大小
- scrollHeight:在沒有滾動條的情況下,元素內容的總高度(margin+border+padding+height)。
- scrollWidth:在沒有滾動條的情況下,元素內容的總寬度(margin+border+padding+width)。
- scrollWidth 和 scrollHeight 主要用於確定元素內容的實際大小
- scrollLeft:被隱藏在內容區域左側的畫素數。通過設定這個屬性可以改變元素的滾動位置。
- scrollTop:被隱藏在內容區域上方的畫素數。通過設定這個屬性可以改變元素的滾動位置
- 確定==文件的總高度==時(包括基於視口的最小高度時),必須取得 scrollWidth/clientWidth 和 scrollHeight/clientHeight 中 的最大值,才能保證在跨瀏覽器的環境下得到精確的結果
var docHeight = Math.max(document.documentElement.scrollHeight,document.documentElement.clientHeight);
var docWidth = Math.max(document.documentElement.scrollWidth,document.documentElement.clientWidth);
複製程式碼
3、onload事件
- window的onload事件會在文件載入完畢(文件的css、img、JavaScript下載並執行完畢)後才會觸發
// index.js
console.log('語句 1', new Date().getTime())
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="http://localhost:3000/index.js"></script>
<script>
console.log('語句 2', new Date().getTime())
</script>
<script>
console.log('語句 3', new Date().getTime())
/*
* window的onload事件會在文件載入完畢(文件的css、img、JavaScript下載並執行完畢)後才會觸發
* 故該事件中的語句會最後執行
*/
window.onload = function() {
console.log('語句 4:window.onload事件中的語句', new Date().getTime())
}
console.log('語句 5', new Date().getTime())
</script>
<script>
console.log('語句 6', new Date().getTime())
</script>
</body>
</html>
// 控制檯輸出
語句 1 1520994942124
語句 2 1520994942127
語句 3 1520994942127
語句 5 1520994942127
語句 6 1520994942128
語句 4:window.onload事件中的語句 1520994942128
複製程式碼
- Image物件的onload事件:新影象元素不一定要從新增到文件後才開始 下載,只要設定了 src 屬性就會開始下載
var image = new Image();
// 事件處理程式必須放在src屬性新增之前
image.onload = function(event){
console.log("Image loaded!");
};
// image新增了src屬性之後檔案就開始下載
image.src = "smile.gif";
複製程式碼