主流瀏覽器的內核
IE:trident
Chrome:webkit/blink
firefox:Gecko
Opera:presto
Safari:webkit
引入JS的方式
頁面內嵌標簽(可在head內或body內)
外部引入(常用方法)
JS基本語法
變數:
變數宣告:宣告,賦值分解,單一var, (var a=100)
命名規則:變數名必須以英文字母,*,$開頭*
變數名可以包括英文字母,,$,數字
不可以用系統的關鍵字,保留字作為變數名
值型別(資料型別):
不可改變的原始值(堆疊資料):Number,Boolean,String,undefined,null
堆疊記憶體和堆疊記憶體之間賦值是拷貝(互不影響)
參考值(堆資料):array,Object,function,..data,RegExp
typeof()可查看資料型別(回傳number,string,boolean,object,undefined,function)
型別轉換:顯式型別轉換:Number(mix) 轉換不了的就顯示為NaN
parseInt(string,radix) string以radix進制為基底轉換為10進制
parseFloat(string)
num.toString(radix) num轉為radix進制
String(mix)
Boolean()
隱式型別轉換:isNaN() 先轉為number,再與NaN比較
++/-- +/-(正負)轉為數字型別
+ 轉為字串
- * / % 轉為數字型別 '1'*1=1
&& || !
< > <= >= 字串與數字比較,轉為數字再比較,字串與字串比較,比較ascii碼
== != 轉為數字再比較
不發生型別轉換:===,!==
陳述句的基本規則:
每一句后面要以分號結束(除函式,for陳述句,if陳述句...)
js語法錯誤(低級錯誤,邏輯錯誤)會引發后續代碼終止,但不會影響其他js代碼塊
書寫格式要規范,'=+/-'兩邊要有空格
運算運算子:
'+':數學運算,字串連接,
任何資料型別加字串都等于字串
'-','*','/','%','=','()':'()'優先級最高,'='優先級最低
'++','--','+=','-=','/=','*=','%='
e.g. var a = 10 ; var b = ++a - 1 + a++ (此時b等于21,a等于12)
var a = 1 ; var b = a-- + --a (此時b等于0(先算--a,然后b=0+0=0),a等于-1)
比較運算子:'>','<','==','>=','<=','!='(比較結果為boolean值) NaN!=NaN
邏輯運算子:'&&'(碰到假就停),'||'(碰到真就停),'!'(運算結果為真實的值)
e.g. var a = 1 && 2+2 (a為4)
var a = 0 && 2+2 (a為0)
var a = 2+1 && 0 (a為0)
var a = 1 || 3 (a為1)
var a = 0 || 2 (a為2)
(window.foo || (window.foo='bar')) (window.foo的值為bar(先看括號的))
被認定為false的值:undefined,null,NaN,'',0,false
條件陳述句:if,if else if,switch case,break,continue
回圈陳述句:for,while,do while
函式
定義:函式宣告(function xxx(){})
函式運算式(命名函式運算式:var test=function xxx(){}, 匿名函式運算式(常用):var test=function (){})
組成形式:函式名稱(小駝峰原則 如theFirstName)
引數:形參(獲取形參長度:函式名.length),實參(arguments表示的是實參串列,獲取實參長度:arguments.length)
回傳值
e.g.1 求5的階乘(遞回)
function mul(n){
if(n==1 || n==0)
{
return 1
}
return n*mul(n-1);
}
mul(5);
作用域
作用域定義:變數和函式生效的區域(存盤了運行期背景關系的集合)
作用域的訪問順序:函式里面的可以訪問外面的值(里面的可以訪問外面的,外面的不能訪問里面的)
函式被定義時,會在作用域鏈中生成一個GO物件
函式被執行時,會在作用域鏈中多生成一個AO物件,此時0號位置是AO,1號位置是GO
當多個函式為包含關系時,各函式作用域鏈的變化:
e.g. function a(){
function b(){
function c(){
}
c();
}
b();
}
a();
a defined a.[[scope]] --> 0:GO
a doing a.[[scope]] --> 0:aAO 1:GO
b defined b.[[scope]] --> 0:aAO 1:GO
b doing b.[[scope]] --> 0:bAO 1:aAO 2:GO
c defined c.[[scope]] --> 0:bAO 1:aAO 2:GO
c doing c.[[scope]] --> 0:cAO 1:bAO 2:aAO 3:GO
with會改變作用域鏈:with(訪問的物件){執行的代碼}
若訪問的物件沒有對應的變數,則在原本執行的這個函式體中找變數,
e.g.
var obj={name:'obj'};
function test(){
var age=123;
var name='scope';
with(obj){
console.log(name); //輸出obj
console.log(age); //輸出123
}
}
JS三部曲(預編譯重點)
語法分析
預編譯(發生在函式執行的前一刻)
解釋執行
預編譯:函式宣告整體提升
變數宣告提升
預編譯前奏:imply global暗示全域變數:即任何變數,如果變數未經宣告就賦值,此變數為全域物件(window)所有(var a=b=123(b為經宣告就賦值,歸window所有,所以window.a為undefined,window.b為123))
一切宣告的全域變數,全是window的屬性(var a=123 => window.a=123)
預編譯程序四部曲:創建AO物件
找形參和變數宣告,將變數和形參名作為AO屬性名,值為undefined
將實參值和形參統一
在函式體里面找函式宣告,值賦予函式體
e.g. function fn(a){ 1.創建AO物件(執行期背景關系)
console.log(a); 2.找形參和變數宣告
var a=123; AO{a:undefined,b:undefined}
console.log(a); 3.將實參和形參統一
function a(){}; AO{a:1,b:undefined}
console.log(a); 4. 找函式宣告
var b=function(){} AO{a:function a(){},b:undefined,d:function d(){}}
console.log(b);
function d(){}
}
fn(1)
所以第一個console.log(a)列印的是function a(){}
此時執行var a=123,所以此時AO{a:123,b:undefined,d:function d(){}}
第二個console.log(a)列印的是123
此時不用再看function a(){}(因為預編譯已經看過了)
第三個console.log(a)列印的是123
此時執行var b=function (){},所以此時AO{a:123,b:function (){},d:function d(){}}
第四個console.log(b)列印的是function (){}
若一個變數未經宣告就賦值,會把此變數放到GO物件(window)中
e.g.1 console.log(test);
function test(test){
console.log(test);
var test=234;
console.log(test);
function test(){};
}
test(1);
var test=123;
先創建GO物件:GO{test:function (){...}}
再創建AO物件:AO{test:function (){}}
所以第一個console.log(test)為function(){}
第二個為function(){}
執行var test=234,所以AO{test:234}
第三個為234
e.g.2 global=100;
function fn(){
console.log(global);
global=200;
console.log(global);
var global=300;
}
fn();
var global;
先創建GO:{global:100}
再創建AO:{global:undefined}
此時第一個輸出為undefined(AO中有的就先從AO中找)
再執行global=200;此時AO:{global:200}
所以第二個輸出為200
e.g.3 function test(){
console.log(b);
if(a){
var b=100;
}
console.log(b);
c=234;
console.log(c);
}
var a;
test();
a=10;
console.log(c);
先創建GO:{a:undefined}
再創建AO:{b:undefined}
第一個輸出為undefined
此時a為undefined,不能執行var b=100
所以第二個輸出為undefined
執行c=234,AO里沒有c,則把變數c添加到GO中,此時GO{a:undefined,c:234}
第三個輸出為234
再執行a=10,此時GO{a:10,c:234}
第四個輸出為234
e.g.4 var x=1;
if(function f(){}){
x+=typeof f;
}
console.log(x);
因為(function f(){})為運算式,所以f是undefined
所以x輸出為1undefined
(未經宣告的變數放在typeof中不會報錯,為undefined)
關于GO和AO物件,若AO上沒有相應變數,則再去GO上找
預編譯時會忽略掉判斷的陳述句
GO和AO物件實則是執行期背景關系
立即執行函式
立即執行函式主要針對初始化功能的函式(執行完就被銷毀)
(function (形參(可有可無)){}(實參(可有可無)))
只有運算式才能被執行符號執行
如:var test=function (){}();
+function test(){}();
(function test(){})();
閉包(重點)
閉包的生成:當內部函式被保存到外部的時候
閉包的防范:閉包會導致多個執行函式共用一個公有變數,如果不是特殊需要,應盡量防止這種情況發生
閉包的作用:實作公有變數(函式累加器)
可以做快取(存盤結構)
可以實作封裝,屬性私有化
模塊化開發,防止污染全域變數
可用立即執行函式解決閉包
e.g. 給4個li系結點擊事件
var li=document.getElementByTagName('li');
for(var i=0;i<li.length;i++){
(function (j){
li[j].onclick=function(){
console.log(j)
}(i))
}
物件
屬性的增,刪,改,查:
增:物件名.屬性名=屬性值
刪:delete 物件名.要洗掉的屬性名
改:物件名.要修改的屬性名=新的屬性值
查:物件名.要查看的屬性名
物件的創建方法:
1. 物件字面量/物件直接量 var obj={}
2. 建構式(大駝峰命名規則:如TheFirstName):系統自帶的建構式Object():var obj=new Object()
自定義:function 函式名(){this.屬性名=屬性值...}
var 物件名= new 函式名()
3. var obj=Object.create(原型/null)(創建物件的同時可自定義原型)
改造函式的內部原理:1.在函式體最前面隱式的加上this={}(AO:{this:{xxx}})
2.執行this.xxx=xxx
3.隱式的回傳this(建構式中回傳值不能回傳原始值,會忽略掉,自動回傳this)
包裝類:new String()
new Boolean()
new Number()
e.g. var str='abc';
str+=1;
var test=typeof(str);
if(test.length==6){
test.sign='typeof的回傳結果可能為String';
(原始值賦屬性值要呼叫包裝類,賦和沒賦一樣)
//new String(test).sign='xxx' 隨后delete
}
//new String(test).sign(為undefined)
cosnole.log(test.sign);
輸出的結果為undefined
原型
原型是function物件的一個屬性,它定義了建構式制造出來的物件的公共祖先
通過該建構式產生的物件,可以繼承該原型的屬性和方法
原型也是物件
利用原型可以提取公有的屬性
物件查看原型:隱式屬性__proto__ (函式名.prototype)
物件查看物件的建構式:constructor
判斷是否為自身的屬性:物件名.hasOwnProperty(屬性值)
e.g. Person.prototype.name='sunny'
function Preson(){}
var person=new Preson();
Preson.prototype.name='cherry';
此時 person.name='cherry'
Person.prototype.name='sunny'
function Preson(){}
var person=new Preson();
Preson.prototype.name={name:'cherry'}
類似于
var obj={name:'a'};
var obj1=obj;
obj={name:'b'};(新開的空間)
所以此時 person.name還是等于'sunny'(此時的__proto__還是指向原來的Person.prototype)
原型鏈中絕大多數物件最終都會繼承自Object.prototype
undefined和null沒有原型
改變this指向:call,apply
call:原來的函式名.call(this要指向的函式名,引數)
apply:原來的函式名.apply(this要指向的函式名,[引數])
call和apply的區別:傳引數的形式不同
call是要把實參按照形參的個數傳進去
apply是傳一個arguments
繼承模式
1. 傳統形式(原型鏈):過多的繼承了沒用的屬性
2. 借用建構式:不能繼承借用建構式的原型
每次建構式都要多走一個函式
3. 共享原型:不能隨便改動自己的原型
4. 圣杯模式
第一種寫法:
function inherit(Target,Origin){
function F(){};
F.prototype=Origin.prototype;
Target.prototype=F.prototype;
Target.prototype.constructor=Target;
Target.prototype.uber=Origin.prototype;
}
第二種寫法:
var inherit=(function (){
var F=function (){};
return function(Target,Origin){
F.prototype=Origin.prototype;
Target.prototype=F.prototype;
Target.prototype.constructor=Target;
Target.prototype.uber=Origin.prototype;
}
}())
命名空間
管理變數,防止污染全域,適用于模塊化開發
可使用閉包的方法實作變數私有化,從而防止變數污染
var name='bcd';
var init=(function (){
var name='abc';
function callName(){
console.log(name);
}
return function(){
callName();
}
}())
init();
此時列印出來的name還是abc
還可使用Webpack等
JS實作鏈式呼叫模式(仿JQ)
如:obj.eat().smoke().drink()
在每個方法后面return this
物件列舉
陣列遍歷:for回圈陣列長度
物件遍歷:for in回圈
for(var xxx(自定義) in 物件名){console.log(物件名[xxx])}
區分陣列,物件的三種方法
方法一:instanceof
判斷A物件是不是B建構式構造出來的(判斷A物件的原型鏈上有沒有B的原型):A instanceof B
陣列:[] instanceof Array --> true
物件:{} instanceof Object --> true
方法二:constructor
物件:obj={},obj.constructor --> function Object()
陣列:arr=[],arr.constructor --> function Array()
方法三:toString()
陣列:Object.prototype.toString.call([]) --> [object Array]
物件:Object.prototype.toString.call([]) --> [object Object]
關于this
函式預編譯程序 this -> window
全域作用域里 this -> window
call/apply可改變函式運行時的指向
obj.func(); func()里面的this指向obj(誰呼叫this指向誰)
e.g.1 var name='222';
var a={
name:'111',
say:function(){
console.log(this.name);
}
}
var fun=a.say;
fun(); //全域呼叫
a.say(); //a呼叫
var b={
name:'333',
say:function(fun){
fun();
}
}
b.say(a.say); //沒有說明是this呼叫,只是把a.say這個方法傳進來執行(相當于借用這個方法在b里面執行),此時還是全域呼叫
b.say=a.say;
b.say(); //此時為b呼叫
依次的輸出結果為:222,111,222,333
e.g.2 var foo=123;
function print(){
this.foo=234;
console.log(foo);
}
print();
執行this.foo=234時,此時this指向window,改變GO中foo的值為234
所以輸出結果為234
若把上題的print()改為new print():由于此時的this=Object.create(print.prototype),this不指向window了
所以此時輸出結果為123
e.g.3 var a=5;
function test(){
a=0;
alert(a);
alert(this.a);
var a;
alert(a);
}
test(); 依次輸出0 5 0
new test(); 依次輸出0 undefined(this上面沒有a) 0
e.g.4 var bar={a:'002'};
function print(){
bar.a='a';
Object.prototype.b='b';
return function inner(){
console.log(bar.a);
console.log(bar.b);
}
}
print()();(相當于先回傳一個函式,再進行函式執行) 依次輸出為a,b
arguments.callee:會指向自己的參考,參考該函式的函式體內的當前正在執行的函式,當函式名稱未知時,例如在沒有名稱的函式運算式中(也稱為“匿名函式”),此功能很有用,
e.g. var num=(function(n){
if(n==1){
return 1
}
return n * arguments.callee(n-1)
}(100))
func.caller:回傳呼叫指定函式的函式
注意:arguments.callee和func.caller在嚴格模式下都不能使用
克隆
淺層克隆和深層克隆的區別:
淺層克隆:當克隆參考值時,兩個物件會共用一個參考地址,造成相互的干擾,即我改,它也改
深層克隆:克隆出來的物件和原來的物件是相互獨立的,互不影響,也就是對新物件的修改都不會反映到原物件中
淺層克隆:
function clone(origin,target){
var target=target || {};
for(var prop in origin){
target[prop]=origin[prop];
}
return target;
}
深層克隆:
實作步驟:
1. 判斷是不是原始值 (typeof)
2. 判斷是陣列還是物件(instanceof,toString(推薦使用),constructor)
3. 建立相應的陣列或物件
4. 遞回
function deepClone(origin,target){
var target=target || {};
var toStr=Object.prototype.toString;
var arrStr="[object Array]";
for(var prop in origin){
if(origin.hasOwnProperty(prop)){ //要克隆自身的屬性
if(origin[prop] !== "null" && typeof(origin[prop])=='object'){
if(toStr.call(origin[prop])==arrStr){ //克隆的屬性是個陣列
target[prop]=[]; //新建一個陣列
}
else{ //克隆的屬性是個物件
target[prop]={}; //新建一個物件
}
deepClone(origin[prop],target[prop])
}
else{ //原始值直接拷貝
target[prop]=origin[prop];
}
}
}
陣列和類陣列
創建陣列的方法:
var arr=[];
var arr=new Array(1,2,3,4);
var arr=new Array(10);
new Array():當為一個引數n時表示新開一個長度為n的陣列空間
當為多個引數時表示陣列里的值
陣列的讀和寫:
arr[n]:讀,但不可以溢位讀,要不然結果為undefined
arr[n]=xxx:寫,可以溢位寫
陣列常用的方法:
會改變原陣列的:push(在陣列末尾添加資料)
pop(剪切陣列末尾的資料)
shift(剪切陣列前面的資料)
unshift(在陣列前面添加資料)
sort(資料排序,默認升序):arr.sort(function(a,b){return x(若x為負數時,那么前面的數放在前面,若x為正數,那么后面的數放在前面,若x為0,則不動,可直接利用return a-b進行升序,return b-a進行降序)})
可利用sort生成一個亂序陣列:xxx.sort(function(){ return Math.random()-0.5 })
reverse(資料反轉倒序)
splice(切片):splice(從第幾位開始,截取多少長度,在切口處添加新的資料)
不會改變原陣列的:concat(陣列拼接)
join(連接):join('x')按照'x'來連接陣列里的資料
split(拆分):solit('x')按照'x'來拆分陣列里的資料,拆分為字串
toString(變成字串)
slice(截取):slice(從該位開始截取,截取到該位)
類陣列:
可以利用屬性名模擬陣列的特性
可以動態的增長length屬性
如果強行讓類陣列呼叫push方法,則會根據length屬性值的位置進行屬性的擴充
屬性要為索引(數字)屬性,必須有length屬性,最好加上push
e.g. var obj={
"2" : "a",
"3" : "b",
"length" : 2,
"push" : Array.prototype.push
}
obj.push('c');
obj.push('d');
輸出結果obj
push的原理是:
Array.prototype.push=function(target){
this[this.length]=target;
this.length++;
}
所以obj.push('c'),在這個obj中相當于obj[obj.length(即為2)]='c',然后再length++
隨后obj.push('d'),相當于obj[3]='d'
所以輸出的obj為{
"2" : "c",
"3" : "d",
"length" : 2,
"push" : Array.prototype.push
}
實作陣列的去重(在原型鏈上實作):
Array.prototype.unique=function(){
var temp={};
var arr=[]; //放置去重完后的陣列
var len=this.length;
for(var i=0;i<len;i++){
if(!temp[this[i]]){ //若沒有對應的屬性值
temp[this[i]]='abc';
arr.push(this[i]);
}
}
return arr;
}
Try…catch
在try里面的發生錯誤,不會執行錯誤后的try里面的代碼,但還會依然執行外面的代碼
try{
}catch(e){
}
常見的錯誤資訊(error.name的六種對應資訊):
1. EvalError:eval()的使用與定義不一致
2. RangeError:數值越界
3. ReferenceError:非法或不能識別的參考數值
4. SyntaxError:發生語法決議錯誤
5. TypeError:運算元型別錯誤
6. URLError:URL處理函式使用不當
es5嚴格模式
"use strict"(要寫在頁面邏輯的最頂端)
不再兼容es3的一些不規則語法,使用全新的es5規范,
兩種用法:全域嚴格模式
區域函式內嚴格模式(推薦)
"use strict"就是一行字串,不會對不兼容嚴格模式的瀏覽器產生影響,
不支持with,arguments,callee,func,caller,變數賦值前必須宣告,區域this必須被賦值(Person.call(null/undefined)賦值什么就是什么),拒絕重復屬性和引數
DOM操作
DOM定義了表示和修改檔案所需的方法,DOM物件即為宿主物件,由瀏覽器廠商定義,用來操作html和xml功能的一類物件的集合,
對節點的增刪改查
查: (除了getElementsById匹配出來是一個,其他匹配出來都是類陣列(要在末尾加上[n(0,1,2,...)]))
document.getElementById('id名') 根據元素id匹配相應的元素(在IE8以下的瀏覽器不區分id名大小寫)
document.getElementsByTagName('標簽名') 根據元素標簽名匹配相應的元素
document.getElementsByName('name名') 根據元素的標簽name匹配相應的元素
document.getElementsByClassName('類名') 根據元素標簽名匹配相應的元素(在IE8和IE8以下的瀏覽器沒有,可以多個class一起)
document.querySelector('CSS選擇器字串') 匹配指定 CSS 選擇器的一個元素(在IE7和IE7以下的版本沒有)不能實時更新
document.querySelectorAll('CSS選擇器字串') 匹配指定 CSS 選擇器的一組元素(在IE7和IE7以下的版本沒有)不能實時更新
增:
document.createElement():創建元素節點
document.createTextNode():創建文本節點
document.createComment():創建注釋節點
document.createDocumentFragment():創建虛擬的節點物件(可在其中添加DOM節點以構建螢屏外DOM樹)
插:
要添加到的區域.appendChild(要添加的節點):從后面添加一個子節點到頁面(是一種剪切操作)
要添加到的區域.insertBefore(要添加的節點,要在此節點前添加的節點):從前面添加一個子節點到頁面
封裝函式insertAfter():
Element.prototype.insertAfter(targetNode,afterNode){
var beforeNode=afterNode.nextElementSibling;
if(beforeNode==null){ //若是最后一個節點,則直接在其后面插入
this.appendChild(targetNode);
}
else{ //在要插的下一個節點前插入(相當于插在要插節點的后面)
this.insertBefort(targetNode,beforeNode);
}
}
刪:
父節點.removeChild():父節點移除子節點(剪切操作)
節點.remove():節點自己移除自己(洗掉操作)
替換:
父節點.replaceChild(new,origin):替換子節點
遍歷節點樹:
parentNode:父節點(最頂端的parentNode為#document)
childNodes:子節點們
firstChild:第一個子節點
lastChild:最后一個子節點
nextSibling:后一個兄弟節點
previousSibling:前一個兄弟節點
節點的型別:元素節點(1)
屬性節點(2)
文本節點(3)
注釋節點(8)
document(9)
DocumentFragment(11)
基于元素節點樹的遍歷:
parentElement:回傳當前元素的父元素節點(IE不兼容)
children:只回傳當前元素的元素子節點
node.childElementCount(相當于node.children.length):回傳當前元素節點的子元素個數
firstElementChild:回傳第一個元素節點(IE不兼容)
lastElementChild:回傳最后一個元素節點(IE不兼容)
nextElementSibling:回傳后一個兄弟元素節點
previousElementSibling:回傳前一個兄弟元素節點
(IE不兼容都是指IE9和IE9以下瀏覽器不兼容)
節點的四個屬性:
nodeName:元素的標簽名,以大寫形式表示,只讀
nodeValue:Text節點或Comment節點的文本內容,可讀寫
nodeType:該節點的型別,只讀
attribute:Element節點的屬性集合
節點的一個方法:Node.hasChildNodes()(判斷是否有子節點)
Element節點的一些屬性:
innerHTML:添加HTML結構內容
innerText/textContent:添加文本結構內容(innerText 火狐不兼容,textContent IE老版本不好使)
Element節點的一些方法:
ele.setAttribute(屬性名,屬性值):設定節點屬性
ele.getAttribute(屬性名):獲取節點屬性
date(日期)物件
系統提供的
var date=new Date();
詳細功能方法可參考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
定時器 , 延時器
設定定時器:
定時器名=setInterval(function(){
.....
},1000)
清除定時器:
clearInterval(定時器名)
設定延時器:
延時器名=setTimeout(function(){
.....
},1000) //時間間隔在window系統里面最小是15ms,在MAC系統里面最小是10ms(即使設定為0,也會按照最小的時間間隔執行)
清除延時器:
clearInterval(延時器名)
關于setTimeout和setInterval的最小值,詳細可參考網址:https://www.cnblogs.com/daysme/p/6207495.html
獲取視窗屬性,dom尺寸
查看滾動條的滾動距離:
window.pageXOffset/pageYOffset(橫向/縱向) (IE8/IE8以下不兼容)
document.body/documentElement.scrollLeft/scrollTop (兼容性混亂)
(使用的時候可兩者相融合(相加),適應兼容性)
如:document.body.scrollLeft+document.documentElement.scrollLeft
封裝兼容性方法:getScrollOffset(){
if(0 && window.pageXOffset){
return{
x:window.pageXOffset,
y:window.pageYOffset
}
}
else{
return{
x:document.body.scrollLeft+document.documentElement.scrollLeft,
y:document.body.scrollTop+document.documentElement.scrollTop
}
}
}
查看視口的尺寸:
window.innerWidth/innerHeight(查看視窗的寬高)(IE8/IE8以下不兼容)
document.documentElement.clientWidth/clientHeight(標準模式下任何瀏覽器兼容)
document.body.clientWidth/clientHeight(適用于怪異模式下的瀏覽器)
判斷是否為怪異模式:document.compatMode:CSS1Compat(正常模式),backCompat(怪異模式)
封裝兼容性方法:getViewportOffset(){
if(0 && window.innerWidth){
return {
w:window.innerWidth,
h:window.innerHeight
}
}
else{
if(document.compatMode==='BackCompat'){ //怪異模式下
return {
w:document.body.clientWidth,
h:document.body.clientHeight
}
}
else{
return {
w:document.documentElement.clientWidth,
h:document.documentElement.clientHeight,
}
}
}
}
查看元素的幾何尺寸:domEle.getBoundingClientRect()
回傳一個物件,包含left,top,right,bottom,width,height等屬性(但width,height在IE老版本中沒有顯示)
回傳結果不實時
查看元素的尺寸:dom.offsetWidth,dom.offsetHeight
查看元素的位置:dom.offsetLeft,dom.offsetTop
dom.offsetParent(回傳最近的有定位的父級,若無則回傳body,body.offsetParent回傳null)
封裝函式:getElementPosition(求相對于檔案的坐標)
使滾動條滾動的三個方法:scroll(x,y):滾動到...
scrollTo(x,y):滾動到...
scrollBy(x,y):滾動了...(會累加)
腳本化CSS
讀寫元素css屬性:
dom.style.prop
可讀寫行間樣式,沒有兼容性問題,碰到float這樣的保留字屬性,前面應加css(即float --> cssFloat)
復合屬性盡量拆解
組合單詞變成小駝峰式寫法
查詢計算樣式:
window.getComputedStyle(ele,null)[prop]
計算樣式只讀
回傳的計算樣式的值都是絕對值,沒有相對單位
IE8及IE8以下不兼容
null用在獲取偽元素時,改變null(如:window.getComputedStyle(ele,'after').width)
查詢樣式(IE8及IE8以下可用,IE獨有):ele.currentStyle.prop
計算樣式只讀
回傳的計算樣式的值不是經過轉換的絕對值
封裝兼容性方法:getStyle(ele,prop){
if(window.getComputedStyle){
return window.getComputedStyle(ele,null)[prop];
}
else{
return ele.currentStyle.prop;
}
}
事件
系結事處理函式:
ele.onxxx=function(e){} 兼容性很好,但是一個元素的同一個時間上只能系結一個處理程式 this指向元素本身
obj.addEventListener(type,fn,false){} IE9以下不兼容,可為一個事件系結多個處理程式 this指向元素本身
obj.attachEvent('on'+type,fn){} IE獨有,一個事件同樣可以系結多個處理程式 this指向window
封裝兼容性的函式方法:addEvent(ele,type,handle){
if(ele.addEventListener){
ele.addEventListener(type,handle,false);
}
else if(ele.attachEvent){
ele.attachEvent('on'+type,function(){
handle.call(ele);
})
}
else{
ele['on'+type]=handle;
}
}
解除事件處理函式:
ele.onclick=false/null/''
ele.removeEventListener(type,fn,false)
ele.detachEvent('on'+type,fn)
事件處理模型:
事件冒泡:結構上(非視覺上)嵌套關系的元素,會存在事件冒泡的功能,即同一事件,自子元素冒泡向父元素(自底向上)
(focus,blur,change,submit,reset,selectd等事件不冒泡)
取消冒泡事件發生:e.stopPropagation()(不支持IE9以下的版本)
e.cancelBubble=true(IE獨有)
事件捕獲:結構上(非視覺上)嵌套的關系的元素,會存在事件捕獲的功能,即同一事件,自父元素捕獲至子元素(事件源元素) (自頂向下) IE沒有捕獲事件
把addEventlistener中第三個引數改為true可觸發事件捕獲
觸發順序:先捕獲后冒泡
阻止默認事件(表單提交,a標簽跳轉,右鍵選單等):
return false:以物件屬性的方式注冊的事件才生效
e.preventDefault() (IE9以下不兼容)
e.returnValue=false (兼容IE9)
事件物件:
event(非IE瀏覽器都有) || window.event(用于IE瀏覽器)
事件源物件:
event.target (火狐只有這個)
event.srcElement (IE只有這個)
上面兩種chrome都有
事件委托:
利用事件冒泡和事件源物件進行處理
優點:性能不需要回圈所有的元素一個個系結事件
靈活,當有新的元素時不需要重新系結事件
事件分類:
滑鼠事件:click,mousedown,mousemove,mouseup,contextmenu,mouseover,mouseout,mouseenter,mouseleave
event中的button屬性可區分滑鼠按鍵(左鍵為0,右鍵為2)
鍵盤事件:keydown,keyup,keypress(keydown > keypress > keyup)
keydown和keypress的區別:keydown可回應任意鍵盤按鍵
keypress只回應字符類鍵盤按鍵,可回傳ASCII碼并轉換成相應字符
文本操作事件:input(實時獲取文本的值),focus,blur,change(失焦后才獲取文本的值)
表單操作類(window上的事件):scroll,load
JSON
一種傳輸資料的格式(以物件為樣板,本質上是物件,但用途有區別,物件就是本地用的,json是用來傳輸的)
JSON中,屬性名必須帶雙引號
JSON.parse():string -> json
JSON.stringfy():json -> string
異步加載js
js加載的缺點:加載工具方法沒必要阻塞檔案,使得js加載會影響頁面效率,一旦網速不好,那么整個網站將等待js加載而不進行后續渲染等作業
js異步加載的三種方案:
1. defer異步加載,等到dom檔案全部決議完才會被執行,只有IE能用,也可將代碼寫到內部,
2. async異步加載,加載完就執行,async只能加載外部腳本,不能把js寫在script標簽里
3. 創建script,插入到DOM中,加載完畢后callback
(其中第一和第二個方法執行時也不阻塞頁面)
js加載的時間線
1. 創建Document物件,開始決議web頁面,決議HTML元素和他們的文本內容后添加Element物件和Text節點到檔案中, (document.readyState='loading')
2. 遇到link外部css,創建執行緒加載,并繼續決議檔案
3. 遇到script外部js,并且沒有設定async,defer,瀏覽器加載,并阻塞,等待js加載完成并執行該腳本,然后繼續決議檔案
4. 遇到script外部js,并且設定有async,defer,瀏覽器創建執行緒加載,并繼續決議檔案,對于async屬性的腳本,腳本加載完成后立即執行,(異步禁止使用document.write())
5. 遇到img等,先正常決議dom結構,然后瀏覽器異步加載src,并繼續決議檔案
6. 當檔案決議完成,document.readyState='interactive'
7. 檔案決議完成后,所有設定有defer的腳本會按照順序執行
8. document物件觸發DOMContentLoaded事件,標志著程式執行從同步腳本執行階段,轉化為事件驅動階段
9. 當所有async的腳本加載完成并執行后,img等加載完成后,document.readyState='complete',window物件觸發load
正則運算式
轉義字符:'\'
/^開頭,結尾$/
正則運算式作用:匹配特殊字符或有特殊搭配原則的字符的最佳選擇
兩種創建方式:直接量(推薦):var reg=/.../(后面可加i(忽略大小寫)/g(全域匹配)/m(多行匹配))
new RegExp():var reg=new RegExp('...','i/g/m')
正則運算式上的方法:reg.test(str)(檢索字串中指定的值,回傳 true 或 false)
reg.exec(str)(檢索字串中指定的值,回傳找到的值,并確定其位置)
...
支持正則運算式的string物件的方法:str.match(reg)(在字串內檢索指定的值,或找到一個或多個正則運算式的匹配)
str.search(reg)(檢索與正則運算式相匹配的值,回傳str中第一個與 reg相匹配的子串的起始位置,若沒有找到任何匹配的子串,則返-1)
str.replace(reg/str,replacement)(用一些字符替換另一些字符,或替換一個與正則運算式匹配的子串)
...
正則運算式中一些元字符對應的運算式:\w===[0-9A-z_],\W===[^\w]
\d===[0-9],\D===[^\d]
\s===[\t\n\r\v\f],\S===[^\s]
\b===單詞邊界,\B===非單詞邊界
.===[^\r\n]
正則運算式的一些量詞:n+(出現一次到多次)
n*(出現0次到多次)
n?(出現0到1次)
n{x}(出現x次)
n{x,y}(出現x到y次)
以上量詞遵循貪婪匹配原則(盡可能匹配多的)
正向預查(從左到右進行匹配):?=xxx(匹配后面跟著xxx的東西)
?!xxx(匹配后面不跟著xxx的東西)
負向預查(從右到左進行匹配):?<=xxx(匹配緊跟xxx后面的東西)
?<!xxx(不匹配緊跟xxx后面的東西)
e.g.1 檢驗一個字串首尾是否含有數字
var reg=/^\d|\d$/g;
var str='123abc';
reg.test(str) -> true
e.g.2 檢驗一個字串首尾是否都含有數字
var reg=/^\d[\s\S]*\d$/g;
var str='123abc123';
reg.test(str) -> true
e.g.3 輸出以下replace后的結果
var str='aa'; //var reg=/a/;
console.log(str.replace('a'/reg,'b'))
結果為ba(一般情況下只匹配到一個)
var reg=/a/g;
console.log(str.replace(reg,'b'))
結果為bb(全域匹配可匹配多個)
e.g.4 把aabb轉成bbaa
var reg=/(\w)\1(\w)\2/g;
var str='aabb';
console.log(str.replace(reg,'$2$2$1$1'));
或:console.log(str.replace(reg,function($,$1,$2){
return $2+$2+$1+$1
}));
e.g.5 把一串數字用科學計數法表示(從右往左,每三個數打一個點)
var str='10000000000';
var reg=/(?=(\B)(\d{3})+$)/g;
str.replace(reg,'.');
詳情可參考網址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp
或https://www.w3school.com.cn/jsref/jsref_obj_regexp.asp
一些雜碎
一旦經歷了var的操作,所得出的window上的屬性,這種屬性叫做不可配置的屬性,delete不掉
undefined和null不與數字比較
typeof(arguments):object
document.documentElement等于html
在正則運算式中,加上?可打破貪婪匹配
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/267138.html
標籤:其他
上一篇:HTML5快速上手筆記--------------------------持續更新
下一篇:父子組件的傳值
