把你的前端拿捏得死死的,天天學習得爽爽的,達達前端程序員
感謝不負每一份熱愛前端的程序員,不論前端技能有多奇葩,歡迎關注
但願能夠經過這篇文章,可以給你獲得幫助。javascript
對於在JavaScript中的字符串,對象,數組是沒有固定大小的,只有當對他們進行動態分配存儲時,解釋器就會分配內存來存儲這些數據,當JavaScript的解釋器消耗完系統中全部可用的內存時,就會形成系統崩潰。html
內存泄漏,在某些狀況下,再也不使用到的變量所佔用內存沒有及時釋放,致使程序運行中,內存越佔越大,極端狀況下能夠致使系統崩潰,服務器宕機。
so,JavaScript有本身的一套垃圾回收機制,JavaScript的解釋器能夠檢測到何時程序再也不使用這個對象了(數據),就會把它所佔用的內存釋放掉。前端
針對JavaScript的來及回收機制有如下兩種方法(經常使用):標記清除,引用計數。java
當變量進入到執行環境時,垃圾回收器就會將其標記爲「進入環境」,當變量離開環境時,就會將其標記爲「離開環境」。node
垃圾回收器在運行時會給存儲在內存中的全部變量都加上標記,接着去掉環境環境中的變量,和被環境中的變量所引用的變量的標記,在此以後再被加上標記的變量將被視爲準備刪除的變量,就是要刪除的變量,垃圾收集器完成內存清除工做,銷燬這些帶有的標記的值,回收它們所佔用的內存空間。程序員
說到引用計數,部分人是不知道是啥的,引用計數做爲垃圾回收策略的一種,含義是跟蹤記錄每一個值被引用的次數。es6
當聲明瞭一個變量並將一個引用類型賦值給該變量時,則這個值的引用次數就是爲1。web
相反的,若是該變量的值變成了另一個,則這個值的引用次數減一。(當這個值的引用次數變爲0的時候,說明沒有變量在使用,則這個值無法被訪問。)---於是就能夠將它佔用的空間回收起來,這樣垃圾回收器就會在運行的時候清理引用次數爲0的值佔用的空間。面試
可是引用計數存在若是相互引用大量的存在會致使大量的內存泄漏;同時若是出現循環引用問題也會致使內存泄漏的問題。ajax
因此,要減小JavaScript中的垃圾回收,在初始化的時候新建對象,而後在後續過程當中儘可能多的重用這些建立好的對象。咱們能夠:1. 數組array優化;2. 對象儘可能優化;3. 循環優化。
以下內存分配方式:
{} 建立一個新對象 [] 建立一個新數組 funtion(){...} 建立一個新的方法 new Foo() new 關鍵字,一次內存的分配
重複利用:對對象object的優化,遍歷此對象的全部屬性,逐個刪除屬性,最終將對象清空爲一個空對象。
嗯,好的,DOM節點類型有:Document節點,整個文檔是一個文檔節點;Element節點,每一個HTML標籤是一個元素節點;Attribute節點,每個HTML屬性是一個屬性節點;Text節點,包含在HTML元素中的文本是文本節點。
通常狀況下,腳本的下載和執行將會按照文檔的前後順序同步執行,當 腳本下載和執行 的時候,文檔解析會被阻塞,在 腳本下載和執行 完成以後文檔纔會往下繼續進行解析。
若是script標籤中沒有defer或async屬性,瀏覽器在渲染過程當中遇到script標籤時,會中止渲染來下載執行js代碼,等待js執行完畢後,瀏覽器再從中斷的地方恢復渲染。
你會知道這樣瀏覽器會形成阻塞,若是你想要你的項目首屏渲染很快的話,就儘可能不要在首屏加載js文件,因此學習的時候會建議將script標籤放在body標籤底部。
說到defer(延遲執行)和async(異步加載)屬性的區別,下面展現使用script標籤有如下三種狀況:
<script src="dadaqianduan.js"></script> // 瀏覽器會當即加載並執行相應的腳本 <script async src="dadaqianduan.js"></script> // 後續文檔的加載和渲染與js腳本的加載和執行是並行進行的 <script defer src="dadaqianduan.js"></script> // 加載後續文檔的過程和js腳本的加載是並行進行的,js腳本的執行須要等到文檔全部元素解析完成以後,DOMContentLoaded事件觸發執行以前
當加載的js腳本有多個的時候,async是無順序的加載,而defer是有順序的加載,defer屬性表示延遲執行引入的JavaScript,這段JavaScript加載時HTML並未中止解析,so,defer是不會阻塞html解析的,它是等Dom加載完後再去執行JavaScript代碼的。(當html解析過程當中,遇到defer屬性,就會異步加載該js文件,不會中斷HTML文檔的解析,當整個HTML解析完成後,回頭再來解析該js文件)
defer屬性-是否延遲執行腳本,直到頁面加載爲止;async屬性-腳本一旦可用,就異步執行。defer屬性並行加載JavaScript文件,會按照頁面上的script標籤順序執行,而async並行加載,下載完成就當即執行,不會按照頁面上的順序執行。
面試前端,當面試官問你,談談你對閉包的理解的時候,該怎麼回答呢?
簡單說就是 定義在一個函數內部的函數,內部函數持有 外部函數 內的變量 或 參數的引用。 內部函數依賴外部函數, 外部函數參數和變量 不會被垃圾回收機制回收,這些變量會始終存在於內存中。
好處能夠讀取函數內部的變量,能夠避免全局變量的污染,壞處會增長內存的使用量,容易致使內存泄漏,解決方法就是退出函數前,將不適用的局部變量所有刪除。在JavaScript中,函數便是閉包,只有函數纔會產生做用域。
閉包特性,函數嵌套函數,在函數內部能夠引用外部的參數和變量,參數和變量不會被垃圾回收機制回收。
因爲在js中,變量的做用域屬於函數做用域,在函數執行後,做用域就會被清理,內存也會被回收,可是因爲閉包是創建在一個函數內部的 子函數,因爲子函數能夠訪問上級做用域的緣由,即便上級函數執行完,做用域也不會隨之銷燬。
在本質上,閉包就是將函數內部和函數外部鏈接起來的一座橋樑。
代碼閉包表現形式:
// 做爲函數參數傳遞 var a = 1; function foo() { var a = 2; function dada() { console.log(a); } da(dada); } function da(fn) { // 閉包 fn(); } foo(); // 輸出2
unshift()方法能夠想數組開頭添加一個或多個元素,並返回新的長度。
arrayObject.unshift(newelement1,newelement2,....,newelementX) newelement1 必需。向數組添加的第一個元素。 newelement2 可選。向數組添加的第二個元素。 newelementX 可選。可添加若干個元素。
返回值- arrayObject
的新長度。
unshift()
方法將把它的參數插入 arrayObject
的頭部,並將已經存在的元素順次地移到較高的下標處,以便留出空間。該方法的第一個參數將成爲數組的新元素 0,若是還有第二個參數,它將成爲新的元素 1,以此類推。
請注意,unshift()
方法不建立新的建立,而是直接修改原有的數組。 該方法會改變數組的長度。
1.encodeURl( )
用於將URL轉換爲十六進制編碼。
2.decodeURI( )
用於將編碼的URL轉換回正常URL。
innerHTML
內容每次刷新,所以很慢。 在innerHTML
中沒有驗證的餘地,所以,更容易在文檔中插入錯誤代碼,從而使網頁不穩定。
DOM節點操做方法:
document.getElementById(id); // 返回對擁有指定id的第一個對象進行訪問 document.getElementsByName(name); // 返回帶有指定名稱的節點集合 document.getElementsByTagName(tagName); // 返回帶有指定標籤名的對象集合 document.getElementsByClassName(className); // 返回帶有指定class名稱的對象集合
createDocumentFragment() //建立一個DOM片斷 document.createElement(eName); // 建立一個節點 document.createAttribute(attrName); // 對某個節點建立屬性 document.createTextNode(text); // 建立文本節點
document.insertBefore(newNode, referenceNode); // 在某個節點前插入節點 parentNode.appendChild(newNode); // 給某個節點添加子節點
cloneNode(true | false); // 複製某個節點
parentNode.removeChild(node); // 刪除某個節點的子節點node是要刪除的節點
getAttribute(name) // 經過屬性名稱獲取某個節點屬性的值 setAttribute(name,value); // 經過某個節點屬性的值 removeAttribute(name); // 刪除某個屬性
curtNode.previousSibling; // 獲取已知節點的相鄰的上一個節點 curtNode.nextSibling; // 獲取已知節點的下一個節點
使用localStorage
,使用localStorage.setItem(key,value)
;添加內容
使用storage事件監聽添加、修改、刪除的動做
window.addEventListener("storage",function(event){ $("#name").val(event.key+"="+event.newValue); });
$(function(){ $("#btn").click(function(){ var name = $("#name").val(); localStorage.setItem("name", name); }); });
console.log(null==undefined)//true console.log(null===undefined)//false
null
: Null類型,表明「空值」,表明一個空對象指針
undefined
: Undefined類型,當一個聲明瞭一個變量未初始化時,獲得的是undefined
undefined表示「缺乏值」,此處應該有一個值,可是尚未定義。
null表示「沒有對象」,該處不該該有值。
new操做符首先,建立了一個空對象:
var obj = new Object();
設置原型鏈:
obj._proto_ = Object.prototype
示例代碼瞭解new的做用:
function da(name) { this.name = name; } da.prototype.sayName = function() { console.log(this.name); } const jeskson = new da('dada'); console.log(jeskson.name); // dada jeskson.sayName(); // dada
由例子得出:
new 經過構造函數 da 建立出來的實例能夠訪問到構造函數中的屬性
new 經過構造函數 da 建立出來的實例能夠訪問到構造函數原型鏈中的屬性,(經過new操做符,實例與構造函數經過原型鏈鏈接了起來)
若是給構造函數一個return返回值,(沒有顯式的return任何值,默認返回undefined)
function da(name) { this.name = name; return 1; } const jeskson = new da('dada'); console.log(jeskson.name); // dada
這個返回值沒有任何的用處,構造函數若是返回原始值,這個返回值沒有意義。
function da(name) { this.name = name; console.log(this); // da {name: 'dada'} return {age:1} } const jeskson = new da('dada'); console.log(jeskson); // {age:1} console.log(jeskson.name); // undefined
構造函數若是返回值爲對象,那麼這個返回值就會被正常使用。
js的延遲加載有助於提升頁面的加載速度
延遲有:defer屬性,async屬性,動態建立DOM方式,使用JQuery的getScript方法,使用setTimeout延遲方法,讓JS最後加載。
使用setTimeout延遲方法
<script type="text/javascript" > function A(){ $.post("/lord/login",{name:username,pwd:password},function(){ alert("Hello"); }); } $(function (){ setTimeout('A()', 1000); //延遲1秒 }) </script>
call(), applay() 都屬於Function.prototype的一個方法,它是JavaScript引擎內實現的,屬於Function.prototype,因此每一個Function對象實例,每一個方法都有call,apply屬性。
call()和apply() ,它們的做用都是相同的,不一樣的在於,它們的參數不一樣。
call(this, arg1, arg2, arg3); apply(this, arguments); function add(a,b){ console.log(a+b); } function sub(a,b){ console.log(a-b); } add.call(sub, 2, 1); add.apply(sub, [2,1]);
對於A.applay(B)或A.call(B),簡單地說,B先執行,執行後根據結果去執行A,用A去執行B的內容代碼,再執行本身的代碼。
var f1 = function(a,b) { console.log(a+b); } var f2 = function(a,b,c) { console.log(a,b,c); } f2.apply(f1,[1,2]) // 1 2 undefined
解析一下就是,先執行f1,f1執行後,這裏注意f1是f1,不是f1()執行方法,因此裏面的console.log等內容代碼並無執行,相等於,初始化了代碼f1,因爲沒有返回值,結果是undefined,f2執行的時候this指向window。參數中爲[1,2]
,解析後參數爲1,2,undefined;執行f2方法後,打印出結果值爲:1 2 undefined
A.call(B, 1,2,3) 後面的參數都是獨立的參數對象,會被自動解析爲A的參數:
var f1 = function(a,b) { console.log(a+b); } var f2 = function(a,b,c) { console.log(a,b,c); } f2.call(f1,[1,2]); // [1,2] undefined undefined f2.call(f1, 1, 2); // 1 2 undefined
解析一下就是,參數中的[1,2]
,由於傳入了一個數組,至關於只傳入了第一個參數,b和c參數沒有傳。
使用apply()和call():
//apply用法 var arr = new Array(1,2,3) var arr1 = new Array(11,21,31) Array.prototype.push.apply(arr,arr1) console.log(arr)//[1, 2, 3, 11, 21, 31] //call用法 var arr = new Array(1,2,3) var arr1 = new Array(11,21,31) Array.prototype.push.call(arr,arr1[0],arr1[1],arr1[2]) console.log(arr)//[1, 2, 3, 11, 21, 31]
數組利用Math求最大和最小值
//apply的用法 var _maxNum = Math.max.apply(null,[1,3,2,4,5]) console.log(_maxNum)//5 var _minNum = Math.min.apply(null,[1,3,2,4,5]) console.log(_minNum)//1 //call的用法 var _maxNum = Math.max.call(null,1,3,2,4,5) console.log(_maxNum)//5 var _minNum = Math.min.call(null,1,3,2,4,5) console.log(_minNum)//1
one總結:Function.prototype.apply和Function.prototype.call的做用是同樣的,區別在於傳入參數的不一樣;第一個參數都是指定函數體內this的指向;第二個參數就不一樣了,apply是傳入帶下標的集合,數組或者類數組,apply把它傳給函數做爲參數,call從第二個開始傳入的參數是不固定的,都會傳給函數做爲參數。call比applay的性能要好,日常多用call。
two總結:尤爲是es6引入了Spread operator延展操做符後,即便參數是數組,可使用call了。
let params = [1,2,3,4,5]; dada.call(obj, ... params);
傳入的第一個參數爲 null, 函數體內的 this 會指向默認的宿主對象, 在瀏覽器中則是 window
var func = function( a, b, c ){ console.log(this === window); // 輸出:true }; func.apply( null, [ 1, 2, 3 ] ); // 在嚴格模式下,函數體內的 this 仍是爲 null var func = function( a, b, c ){ "use strict"; console.log(this === null); // 輸出:true }; func.apply( null, [ 1, 2, 3 ] );
改變this指向
var obj1={ name: 'dada' }; var obj2={ name: 'da' }; window.name = 'window'; var getName = function(){ console.log ( this.name ); }; getName(); // 輸出: window getName.call( obj1 );// 輸出: dada getName.call(obj2 ); // 輸出: da
document.getElementById( 'div1' ).onclick = function(){ console.log( this.id );// 輸出: div1 var func = function(){ console.log ( this.id );// 輸出: undefined } func(); }; //修正後 document.getElementById( 'div1' ).onclick = function(){ var func = function(){ console.log ( this.id );// 輸出: div1 } func.call(this); };
工廠模式,建立方式
function createPerson(name,age,job){ var o = new Object(); o.name=name; o.age=age; o.job=job; o.sayName = function(){ alert(this.name); } } var person1 = createPerson("da",1,"it"); var person2 = createPerson("dada",2,"it");
構造函數模式
function Person(name,age,ob){ this.name=name; this.age=age; this.job=job; this.sayName = function(){ alert(this.name); } var person1 = new Person("dada",1,"web"); var person2 = new Person("dada",2,"web"); }
使用原型模式:
function Person(){ } Person.prototype.name = "da"; Person.prototype.age = 1; Person.prototype.job = "web"; Person.prototype.sayName = function(){ alert(this.name); } var person1 = new Person(); person1.sayName(); //"dada" var person2 = new Person(); person2.sayName(); //"dada" alert(person1.sayName == person2.sayName); //true
組合使用構造函數模式和原型模式
function Person(name,age){ this.name = name; this.age = age; this.friends = ["da","dada"]; } Person.prototype = { constructor:Person, sayName:function(){ alert(this.name); } } var person1 = new Person("da1",1); var person2 = new Person("da2",2); person1.friends.push("dadada"); console.log(person1.friends); //["da","dada","dadada"] console.log(person2.friends); //["da","dada"] console.log(person1.friends === person2.friends); //false console.log(person1.sayName === person2.sayName); //true
動態原型模式
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; if(typeof this.sayName!="function"){ Person.prototype.sayName=function(){ alert(this.name); }; } }
JavaScript對象的建立方式,1,Object構造函數式,2,對象字面量式,3,工廠模式,4,安全工廠模式,5,構造函數模式,6,原型模式,7,混合構造函數和原型模式,8,動態原型模式,9,寄生構造函數模式,10,穩妥構造函數模式。
學習使用異步很重要,在瀏覽器端,耗時很長的操做都應該異步執行,避免瀏覽器失去響應,最好的例子是ajax操做。
簡單的promise對象的構造函數的結構: var Promise = function() { this.callbacks = []; // 用於管理回調函數 } Promise.prototype = { construct: Promise, resolve: function(result) { // 請求成功時執行的方法 }, reject: function(result) { // 請求失敗時執行的方法 }, complete: function(type, result) { // 執行回調 }, then: function(successHandler, failedHandler) { // 綁定回調函數 } }
對於回調函數,好處是簡單,容易理解,可是缺點在於代碼的閱讀和維護,各個部分之間高度耦合,流程也會很亂,每一個任務只能指定一個回調函數,稱之爲:回調地獄。
// 同步操做變成異步操做 f1(); f2(); function f1(callback) { setTimeout(function() { callback(); },1000); } f1(f2);
事件監聽(採用事件驅動模式,任務的執行不取決於代碼的順序,而取決於某個事件是否發生)示例以下:
$('#clickBtn').on('click',function(e){console.log('xxx');}
f1.on('dada', f2); function f1() { setTimeout(function() { f1.trigger('dada'); },1000); } // f1.trigger('dada')表示執行完成後,當即觸發dada事件,而後開始執行f2
對於事件監聽,可綁定多個事件,並且每一個事件能夠指定多個回調函數,能夠「去耦合」,有利於實現模塊化,缺點就是整個程序都要編程事件驅動型,運行流程會變得很不清晰。
對於採用發佈,訂閱方式,和「事件監聽」相似。(發佈/訂閱)
對於使用Promise對象實現,每個異步任務返回一個Promise對象,該對象有一個then方法,容許指定回調函數。
同源策略的目的是爲了防止某個文檔或腳本從多個不一樣源裝載,同源策略是指,協議,域名,端口相同。同源策略是一種安全協議,指一段腳本只能讀取來自同一來源的窗口和文檔的屬性。
有同源限制能夠放置黑客盜取信息。
函數是第一類對象:
這些函數能夠做爲參數傳遞給其餘函數,做爲其餘函數的值返回,分配給變量,也能夠存儲在數據結構中。
若是公民分等級,一等公民什麼均可以作,次等公民這不能作那不能作。JavaScript的函數也是對象,能夠有屬性,能夠賦值給一個變量,能夠放在數組裏做爲元素,能夠做爲其餘對象的屬性,什麼均可以作,別的對象能作的它能作,別的對象不能作的它也能作。這不就是一等公民的地位嘛。
函數聲明:
foo(); // 在函數聲明以後調用 foo,能夠正常調用。由於 foo 被提早到最前面定義了。 function foo() { return true; }
調用:
函數名(參數) 函數名.call(函數名,參數) 函數名.apply(函數名,[參數]) new 函數名(參數) 定時器 把函數聲明變成函數表達式再調用 ES6裏的模版字符串
函數表達式:
foo(); // 在函數表達式以前調用函數,報錯。由於這時候尚未 foo 這個變量。 var foo = function() { return foo; };
調用
函數名(參數) 函數名.call(函數名,參數) 函數名.apply(函數名,[參數]) new 函數名(參數) 直接在後面加上一對小括號 定時器 ES6裏的模版字符串 以被賦值的形式出現(根據具體形式調用)
在向執行環境中加載數據時,解析器對函數聲明和函數表達式不同的,解析器首先讀取讀取函數聲明,並使它在執行任何代碼以前可用,對於函數表達式,就須要等到解析器執行到它所在的代碼行。
JavaScript解釋器中存在一種變量聲明被提高的機制,也就是說函數聲明會被提高到做用域的最前面,即便寫代碼的時候是寫在最後面,也仍是會被提高至最前面。
var getName // 變量被提高,此時爲undefined getName() // dada 函數被提高 var getName = function() { console.log('da') } // 函數表達式此時纔開始覆蓋函數聲明的定義 getName() // da function getName() { console.log('dada') } getName() // da
在JavaScript中定義一個函數有四種方式
1. 函數聲明 2. 函數表達式 3. ES6裏箭頭函數 4. new Function()
代碼以下:
document.cookie = 'user=jeskson;expires='+new Date(0);
一個英文字符 佔用一個字節,一箇中文 字符佔用兩個字節
function byte(str) { var bytes = str.length; for(var i=0; i<bytes; i++) { if(str.charCodeAt(i)>255) { bytes++; } } return bytes } console.log(byte('dada'));
attribute是dom元素在文檔中做爲HTML標籤擁有的屬性,property就是dom元素在JavaScript中做爲對象擁有的屬性。
attribute特性,property屬性。
默認狀況下,在頁面加載期間,HTML 代碼的解析將暫停,知道腳本中止執行。若是服務器速度較慢或者腳本特別沉重,會致使網頁延遲,在使用Deferred時,腳本會延遲執行直到HTML解析器運行。這減小了網頁加載時間,而且它們的顯示速度更快。
function outer() { var a = '變量1' var inner = function() { console.info(a); } return inner; // inner就是一個閉包函數,由於它能訪問到outer函數的做用域 }
在JavaScript中的一大特色就是閉包,不少高級應用都要依靠閉包來實現。因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大的,因此不要亂濫用閉包,不然會致使頁面的性能問題,在IE中可能會致使內存泄漏,因此能夠在退回函數前,將不使用的局部變量所有刪除。
hasOwnProperty
效果動態圖:
<button onclick="fun()" >按鈕</button> <script> function fun() { document.write("write內容"); } </script> <button onclick="fun()">按鈕</button> <script> function fun() { document.getElementById("p").innerHTML="新增長的innerHTML內容"; } </script>
讀取服務器中的文件內容
function readAjaxFile(url) { // 建立xhr var xhr = new XMLHttpRequest(); // 監聽狀態 xhr.onreadystatechange = function() { // 監聽狀態值 if(xhr.readyState === 1 && xhr.status === 200) { console.log(xhr.responseTest) } } // 打開請求 xhr.open('GET', url, true) // 發送數據 xhr.send(null) }
讀取本地計算機中的內容
function readInputFile(id) { var file = document.getElementById(id).files[0]; // 實例化 var reader = new FileReader(); // 讀取文件 reader.readAsText(file) // 監聽返回 reader.onload = function(data) { console.log(data, this.result); } }
document.form.action = 'submit';
eval的功能是把對應的字符串解析成JavaScript代碼並運行。可是應該避免使用eval,使用它可能會形成程序不安全,影響性能因要一次解析成JavaScript語句,一次執行。
["1","2","3"].map(parseInt)
[1,NaN,NaN]
因parseInt須要兩個參數val,radix,其中radix表示解析時用的基數,map傳遞了3個參數item, index, array,對應的radix不合法致使解析失敗。
this指的是調用函數的那個對象,通常狀況下,this是全局對象Global,能夠做爲方法調用。this隨着函數的使用場合的不一樣,this的值會發生變化。
this是誰調用就指向誰,在全局環境裏,指向的是window對象。
var name = 'jeskson'; function person() { return this.name; } console.log(this.name); // jeskson console.log(window.name); // jeskson console.log(person()); // jeskson
局部環境:
var name = "jeskson"; function person() { console.log(this.name); } person(); // jeskson var obj = { name: "dada", person: function() { console.log(this.name); } } obj.person(); // dada
構造函數內使用this
function Person(name) { this.name = name; return name; } console.log(new Person('jeskson').name); // jeskson
使用apply和call函數改變this的指向
function person() { return this.name; } var obj = { name: 'jeskson' } console.log(person.call(obj)); // jeskson console.log(person.apply(obj)); // jeskson
對象函數調用,哪一個對象調用就指向哪一個對象
<input type="button" id="btnDa" value="dada"> <script> var btnDa = document.getElementById("btnDa"); btnDa.onClick=function() { console.log(this); // this指向的是btnDa對象 } </script>
使用new實例化對象,在構造函數中的this指向實例化對象
var show = function() { this.myName="jeskson"; /// this指向的是obj對象 } var obj = new show();
getElementsByTagName
和document.childNodes
方法時,它們返回的NodeList
對象都屬於僞數組。Array.prototype.slice.call(fakeArray)
將數組轉化爲真正的Array對象。什麼是僞數組,是能經過Array.prototype.slice
轉換爲真正的數組的帶有length
屬性的對象。
// 標準的有僞數組對象 var da = { 0: 'a', 1: 'b', length: 2}; var dada = Array.prototype.slice.call(da); console.log(da[0]); // a var dadada = [].slice.call(dada); console.log(da[0]); // a
僞數組:就是沒法使用數組的方法和api,但任然可使用便利數組的方式遍歷他們。
一個僞數組Array.prototype.slice.call()
進行轉換爲一個真正的數組
caller是JavaScript函數類型的一個屬性,它引用調用當前函數的函數; callee則不是函數對象的屬性,它是函數上下文中arguments對象的屬性。
aaaabbbccccddhgddada
function dealStr(str) { var obj = {}; for(var i = 0; i<str.length; i++){ var v = str.charAt(i); if(obj[v] && obj[v].value === v) { ++obj[v].count }else{ obj[v] = { count: 1, value: v } } } return obj; } var obj = dealStr(str); for(key in obj) { console.log(obj[key].value+'='+obj[key].count); }
function trim(str) { if (str && typeof str === "string") { return str.replace(/(^\s*)|(\s*)$/g,""); //去除先後空白符 } }
for循環數組
var arr3 = []; // 遍歷arr1 for (var i = 0; i < arr1.length; i++) { arr3.push(arr1[i]); } // 遍歷arr2 for (var j = 0; j < arr2.length; j++) { arr3.push(arr2[j]); } console.log(arr3); // [1,2,3,4,5,6]
concat()方法:concat()方法,做用是鏈接兩個或更多的數組,並返回一個新的數組。
var arr3 = arr1.concat(arr2); console.log(arr3); // [1,2,3,4,5,6]
apply()方法
arr1.push.apply(arr1, arr2);
&&
運算符||
運算符!
運算符事件代理,又稱爲事件委託,就是把本來須要綁定的事件委託給父元素,讓父元素負責事件監聽,事件代理的原理是DOM元素的事件冒泡,使用事件代理的好處是提升性能。
xxx is not defined
已經經過var指令聲明,可是沒有賦值,沒有定義類型,因此會打印undefined
未定義
全家變量是整個代碼中均可用的變量,這些變量沒有任何做用域。var關鍵字用於聲明局部變量或對象,若是省略var關鍵字,則聲明一個全局變量。
使用全局變量所面臨的問題是局部變量和全局變量名稱的衝突,很難調試和測試依賴於全局變量的代碼。
setTimeout(function,delay)
函數用於啓動在所屬延遲以後調用特定功能的定時器。setInterval(function,delay)
函數用於在提到的延遲中重複執行給定的功能,只有在取消時才中止。clearInterval(id)
函數指示定時器中止。===
運算符===
爲嚴格等式運算符,只有當兩個操做數具備相同的值和類型時,,纔會返回true
for, while, do...while, for_in, for of (es6新增) while(條件表達式語句) { 執行語句塊; } do { 執行語句塊; } while(條件表達式語句); for(初始化表達式;循環條件表達式;循環後的操做表達式) { 執行語句塊; }
var obj = { name: 'jeskson' } console.log(obj.name);//'jeskson' delete obj.name; console.log(obj.name);//undefined
alert, confirm, prompt
其做用是用於防止頁面刷新,並在調用時傳遞參數「0」;用於調用另外一種方法而不刷新頁面
cookie是一些數據,存儲你電腦上的文本文件中,當web服務器向瀏覽器發送web頁面時,在鏈接關閉後,服務端不會記錄用戶的信息。
Cookie的形式,Cookie是由name=value形式成對存在的,Cookie字符串必須以分號做爲結束符,Cookie除了name屬性以外還存在其餘4個相關屬性。
設置Cookie的語法以下: set-Cookie:name=value;[expires=date];[path=dir];[domain=domainn];[secure]
pop()
方法將最後一個元素從給定的數組中取出並返回
var da = [ 1, 2, 3]; da.pop(); // da: [1,2]
datatypes
的兩個基本組是 原始類型和引用類型。
typeof是一個運算符,用於返回變量類型的字符串描述。
push方法是將一個或多個元素添加或附加到數組的末尾。
unshift方法是將一個或多個元素添加到數組的開頭。
爲對象添加屬性的方法,經常使用兩種:
在將頁面加載到瀏覽器中時,這兩個功能均可以用來執行任務,可是它們在執行方式和執行時間方面存在細微的差別。
當瀏覽器加載DOM樹和全部其餘資源(例如圖像,對象等)時,「 window.onload
」將執行代碼。
onDocumentReady
在構建DOM樹時執行,而無需等待其餘資源加載。這樣可使用onDocumentReady
更快地針對DOM執行代碼。
另外一個區別是window.onload
與跨瀏覽器不兼容,而使用相似jQuery的document.ready()
則能夠在全部瀏覽器上很好地工做。
用於循環對象的屬性:
for (var item in object
被聲明爲沒有任何命名標識符的函數,通常來講,匿名函數在聲明後沒法訪問。
var da = function() { console.log('dadaqianduan.cn') } da();
單擊子級的處理程序,父級的處理程序也將執行一樣的工做。
對事件冒泡機制的理解?
事件流的執行順序,捕獲階段-》目標階段-》冒泡階段。冒泡從裏到外的執行。<div><span>點我</span></div>,
在div上定義的事件,點擊span的時候會觸發span上面綁定的事件
,以後也會觸發外面div上面的事件,這就是冒泡。
冒泡階段是從目標到window
對象的過程。事件默認是冒泡的,當父元素添加監聽事件,點擊子元素後,父元素上的事件會被觸發,這就是典型的冒泡。
它只是一個類數組對象,並無數組的方法。
構造函數是用來建立對象時初始化對象,與new一塊兒試用,建立對象的語句中構造函數的名稱必須與類名徹底相同。
split()
方法是用來切割成數組的形式join()
方法是將數組轉換成字符串"abcdef".split("") // ["a", "b", "c", "d", "e", "f"] "abcdef".split() // ["abcdef"] "2:3:4:5".split(":",3) // ["2", "3", "4"] [1,2,3,4,5].join() // "1,2,3,4,5" [1,2,3,4,5].join(':') // "1:2:3:4:5"
JavaScript
的每一個對象都繼承另外一個父級對象,父級對象稱爲原型(prototype)
對象。
原型鏈幾乎是前端面試的必問題目
每個實例對象都有一個私有屬性__proto__
指向其構造函數的原型對象prototype
,該原型對象也會做爲實例對象有一個私有屬性__proto__
,層層向上直到一個對象的原型對象值爲null
。
當訪問一個對象的屬性或方法時,js
引擎會先查找該對象自己是否包含,若是沒有,會去該對象的__proto__
屬性所指向的原型對象上找,若是沒有,會繼續向上一層找,直到某個對象的__proto__
值爲null
,這就是原型鏈。
在js中,每一個構造函數都有一個prototype屬性,指向另一個對象,說明整個對象全部的屬性和方法都會被構造函數所擁有。
function Person (name, age) { this.name = name this.age = age } console.log(Person.prototype) Person.prototype.type = 'it' Person.prototype.sayName = function () { console.log(this.name) } var p1 = new Person('jeskson', 18); var p2 = new Person('dada', 18); console.log(p1.sayName === p2.sayName) // => true
構造函數Person:
function Person() {} --> 原型屬性(prototype) 神祕的對象Person.prototype --> 由構造函數建立 Person實例 --> __proto__ 原型對象 --> 神祕對象
任何一個構造函數都有一個prototype
屬性,該屬性是一個objec
t對象。
構造函數的prototype對象都有一個默認的constructor
屬性,指向prototype
對象所在函數。
經過構造函數獲得的實例對象內部會包含一個指向構造函數的 prototype
對象的指針 __proto__
console.log(obj.__proto__); console.log(obj.prototype); console.log(obj.__proto__ === Object.prototype);
(.__proto__)
指向原型1. 實例對象.__proto__===原型 2. 原型.constructor===構造函數 3. 構造函數.prototype===原型
typeof 是一個一元運算,它返回值是一個字符串,該字符串說明運算數的類型。
instanceof,判斷該對象是誰的實例
instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的prototype屬性,instanceof只能用來判斷對象和函數,不能用來判斷字符串和數字
function getDataType(obj) { if (obj === null) { return 「null」; } else if (typeof obj === 「object」) { if (obj instanceof Array) { return 「array」; } else { return 「object」; } } else { return typeof obj; } }
事件流是指從 頁面中接收事件的順序。
指不太具體的元素更早地接收到事件,而最具體的節點最後接收到事件。
它就是一個經過函數指針調用的函數。
自執行函數是指聲明的一個匿名函數,能夠當即調用整個匿名函數,通常用於框架,插件等場景,好處在於避免各類JavaScript庫的衝突,隔離做用域,避免污染。
事件委託是利用冒泡的原理,把事件加到父級上,觸發執行效果。好處在於,減小事件數量,提升性能,避免內存外泄。
在 JavaScript 中,數據類型的轉換有:隱式類型轉換和強制類型轉換(也叫顯式類型轉換)兩種方式。
隱式類型轉換:
== 只作值的判斷,實際隱式轉換了類型,而後才進行的比較
強制類型轉換:
parseInt() 將字符串強類型制轉換爲數字整數類型 parseFloat() 將字符串類型轉換爲浮點類型 Number() 只能將純數字的字符轉換爲數字
NaN
表示「不是數字」,可是它的類型是Number
,NaN和任何內容比較,甚至是本身,結果都是false.
廣義跨域就是指跨域訪問,簡單來講就是 A 網站的 javascript 代碼試圖訪問 B 網站,包括提交容和獲取內容容。因爲安全緣由,跨域訪問是被各大瀏覽器所默認禁止的。
跨域是指不一樣域名之間的相互訪問。
var d = new Date(); var year = d.getFullYear(); var month = d.getMonth() + 1; month = month < 10 ? "0" + month : month; var day = d.getDate(); daty = day<10? "0"+day : day; console.log(year+'-'+month+'-'+day);
var isArray = []; function getRandom(start, end) { return Math.floor(Math.random() * (end-start+1) + start) } for(var i = 0; i<10; i++){ isArray.push(getRandom(10,100)) } isArray.sort() console.log(isArray)
function clone(obj) { var buf; if(obj instanceof Array) { var i = obj.lenght; buf = []; while(i--) { buf[i] = clone(obj[i]) } return buf; }else if(obj instanceof Object) { buf = {}; for(var i in obj) { buf[i] = clone(obj[i]) } return buf; }else{ return buf = obj; } }
function noRepeat(arr) { var i = 0, len = arr.length, obj = {}, result = []; while(++i < len) { obj[arr[i]] || result.push(arr[i]) obj[arr[i]] = true; } return result; }
getElementById()
根據元素id查找getElementsByTagName(tag)
根據標籤名稱查找getElementsByName(name)
根據元素名稱進行查找function Person(name, job, site) { this.name = name; this.job = job; this.site = site; } Person.prototype = { getName: function() { console.log('my name'+this.name); } getJob: function() { console.log('my job'+ this.job); } getWork: function() { console.log('my work' + this.site); } } var da = new Person('dada', 'it', 'shenzheng'); da.getName(); da.getJob(); da.getWork();
變量做用域,變量的可用性範圍。一般來講,一段程序代碼中所用到的名字並不老是有效可用的,而限定這個名字的可用性的代碼範圍就是這個名字的做用域。做用域的使用,可提升程序邏輯的局部性,加強程序的可靠性,減小名字衝突。從做用域角度區分,變量可分爲全局變量和局部變量。
JavaScript是如何實現繼承的(六種方式)
1.原型鏈:利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。
原型鏈實現繼承例子:
function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function() { return this.property; } function SubType() { this.property = false; } //繼承了SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function (){ return this.property; } var instance = new SubType(); console.log(instance.getSuperValue());//true
2.借用構造函數:在子類型構造函數的內部調用超類構造函數,經過使用call()和apply()方法能夠在新建立的對象上執行構造函數。
function SuperType() { this.colors = ["red","blue","green"]; } function SubType() { SuperType.call(this);//繼承了SuperType } var instance1 = new SubType(); instance1.colors.push("black"); console.log(instance1.colors);//"red","blue","green","black" var instance2 = new SubType(); console.log(instance2.colors);//"red","blue","green"
3.組合繼承:將原型鏈和借用構造函數的技術組合在一塊,從而發揮二者之長的一種繼承模式。
function SuperType(name) { this.name = name; this.colors = ["red","blue","green"]; } SuperType.prototype.sayName = function() { console.log(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() { console.log(this.age); } var instance1 = new SubType("da",18); instance1.colors.push("black"); consol.log(instance1.colors);//"red","blue","green","black" instance1.sayName();//"EvanChen" instance1.sayAge();//18 var instance2 = new SubType("dada",20); console.log(instance2.colors);//"red","blue","green" instance2.sayName();//"dada" instance2.sayAge();//20
4.原型式繼承:藉助原型能夠基於已有的對象建立新對象,同時還沒必要須所以建立自定義的類型。
5.寄生式繼承:建立一個僅用於封裝繼承過程的函數,該函數在內部以某種方式來加強對象,最後再像真正是它作了全部工做同樣返回對象。
6.寄生組合式繼承:經過借用函數來繼承屬性,經過原型鏈的混成形式來繼承方法
做用域鏈與函數執行棧相對應。js運行環境分爲全局、函數以及eval三類,每當代碼執行進入了一個新的運行環境就會將環境的執行上下文入棧,退出環境時將其出棧,從棧頂到棧底造成從內層到外層的嵌套關係。
由執行上下文建立的詞法環境持有外層執行上下文的詞法環境引用,當JS引擎在當前詞法環境中找不到相應的變量時,會逐層向外查找,如此造成的鏈表即爲做用域鏈。
做用域鏈指的是代碼執行時,查找變量的規則,先在當前自身的做用域查找,找不到在往上級做用域查找,查不到的話直至全局環境,固然全局環境不能訪問局部做用域的變量
JavaScript中的每一個對象都有一個prototype屬性,稱爲原型,而原型的值也是一個對象,所以它也有本身的原型,這樣就造成了一條原型鏈,原型鏈的鏈頭是object,它的prototype比較特殊,值爲null。
__proto__
是在查找鏈中用於解析方法的實際對象等,prototype
使用如下命令__proto__
建立對象時用於構建的對象new
:
(new Foo).__proto__ === Foo.prototype; (new Foo).prototype === undefined;
prototype
是Function
對象的屬性,它是由該功能構造的對象的原型。
__proto__
是對象的內部屬性,指向其原型。當前提供了Object.getPrototypeOf(o)
方法,儘管事實上的標準__proto__
更快。
可使用instanceof
經過將函數prototype
與對象的__proto__
鏈進行比較來找到關係,也能夠經過更改來打破這些關係。
function Point(x, y) { this.x = x; this.y = y; } var myPoint = new Point(); // the following are all true myPoint.__proto__ == Point.prototype myPoint.__proto__.__proto__ == Object.prototype myPoint instanceof Point; myPoint instanceof Object;
一、 函數式聲明
二、 函數表達式(函數字面量)
三、 函數構造法,參數必須加引號
四、 對象直接量
五、 原型繼承
六、 工廠模式
// 經過函數字面量 function da() {} // 函數表達式 var da = function() {} // 經過構造函數 var da = new Function();
全局屬性和函數可用於全部內建的 JavaScript 對象。默認的this指向window,默認全局對象的屬性和方法不用在前面加window,能夠直接調用。
頂層函數(全局函數):
decodeURI() 解碼某個編碼的 URI。 decodeURIComponent() 解碼一個編碼的 URI 組件。 encodeURI() 把字符串編碼爲 URI。 encodeURIComponent() 把字符串編碼爲 URI 組件。 escape() 對字符串進行編碼。 eval() 計算 JavaScript 字符串,並把它做爲腳本代碼來執行。 getClass() 返回一個 JavaObject 的 JavaClass。 isFinite() 檢查某個值是否爲有窮大的數。 isNaN() 檢查某個值是不是數字。 Number() 把對象的值轉換爲數字。 parseFloat() 解析一個字符串並返回一個浮點數。 parseInt() 解析一個字符串並返回一個整數。 String() 把對象的值轉換爲字符串。 unescape() 對由 escape() 編碼的字符串進行解碼。
頂層屬性(全局屬性)
Infinity 表明正的無窮大的數值。 java 表明 java.* 包層級的一個 JavaPackage。 NaN 指示某個值是否是數字值。 Packages 根 JavaPackage 對象。 undefined 指示未定義的值。
經常使用的是Array對象、Date對象、正則表達式對象、string對象、Global對象
Concat():表示把幾個數組合併成一個數組。 Join():返回字符串值,其中包含了鏈接到一塊兒的數組的全部元素,元素由指定的分隔符分隔開來。 Pop():移除數組最後一個元素。 Shift():移除數組中第一個元素。 Slice(start,end):返回數組中的一段。 Push():往數組中新添加一個元素,返回最新長度。 Sort():對數組進行排序。 Reverse():反轉數組的排序。 toLocaleString();返回當前系統時間。 ceil():向上取整。 floor():向下取整。 round():四捨五入。 random():取隨機數。 get/setDate():返回或設置日期。 get/setFullYear():返回或設置年份,用四位數表示。 get/setYear():返回或設置年份。 get/setMonth():返回或設置月份。0爲一月 get/setHours():返回或設置小時,24小時制 get/setMinutes():返回或設置分鐘數。 get/setSeconds():返回或設置秒鐘數。 get/setTime():返回或設置時間(毫秒爲單位)。
DOM,文檔對象模型(Document Object Model)。DOM是 W3C(萬維網聯盟)的標準,DOM定義了訪問HTML和XML文檔的標準。在W3C的標準中,DOM是獨於平臺和語言的接口,它容許程序和腳本動態地訪問和更新文檔的內容、結構和樣式。
分三種:
我是Jeskson(達達前端),感謝各位人才的:點贊、收藏和評論,咱們下期見!