1. 程式人生 > >總結篇-Javascript部分(絕對乾貨,未完待續...)

總結篇-Javascript部分(絕對乾貨,未完待續...)

0-0.常用的四種設計模式

1.工廠模式:解決多個相似的問題;
2.單例模式:只能被例項化一次;
3.沙箱模式:自執行函式,使用閉包把內部方法暴露出來,例:
    var fn=(function(){
        function aFn(){};
        return {
            aFn:aFn
        }
    })
4.釋出者訂閱模式:有新訊息主動推送的功能模式;

0-1.程式設計正規化

1.指令式程式設計(流水式從上至下執行)
2.面向程式設計(函數語言程式設計:閉包(函式組合巢狀的方式),一類函式,箭頭函式)
3.面向物件式程式設計(OOP:原型(鏈式的連結物件的物件)繼承(存在父子間屬性函式的使用))
    優缺點: 物件函式屬性排列易於理解;命令式編碼風格計算機能直接快速編譯;
            多例項時亂象叢生,容易修改原始值導致解析不理想化(缺點)
4.函數語言程式設計:
    優缺點: 避免面向物件程式設計的缺點,自我執行理想化程度高;
            複用性良好,存在引數無引數狀態,且可以高效完成演算法;
            執行邏輯清晰,方便修改和優化更新;
            避免多執行緒衝突,邏輯混亂
            簡潔度很好,易讀性稍差(缺點)

0-2.寫JavaScript的基本規範?

不要在同一行宣告多個變數。
請使用 ===/!==來比較true/false或者數值
使用物件字面量替代new Array這種形式
不要使用全域性函式。
Switch語句必須帶有default分支
函式不應該有時候有返回值,有時候沒有返回值。
for迴圈必須使用大括號
if語句必須使用大括號
for-in迴圈中的變數 應該使用var關鍵字明確限定作用域,從而避免作用域汙染。

1.模擬字串去的hash值

function hashCode(str){  
    var h = 0, off = 0;   var len = str.length;  
    for(var i = 0; i < len; i++){  
        h = 31 * h + str.charCodeAt(off++);  
    }  
    var t=-2147483648*2;  
    if(h>2147483647){  
        h+=t  
    }  
    return h;  
}  

2.獲取本地時間的時間戳

var timestamp=Date.parse(new Date());	//特殊存在:毫秒顯示為000(不去秒以下的數值)
var timestamp=(new Date()).valueOf();
var timestamp=new Date().getTime();

3.fixed固定定位不隨滾動條移動

<div class=”fixedDiv”>…</div>

.fixedDiv{
	position:fixed;
	width:1000px;
	bottom:0;
	z-index:1000;
}

window.onscroll=function(){
	var sl=Math.max(document.body.scrollLeft,document.documentElement.scrollLeft);
	document.getElementsByClassName(“fixedDiv”)[0].style.left=(-sl)+”px”;
}

4.獲取指定字串中某字元出現的所有下標

function getAllIndex(str,chars){
    var arr=[];
    for(var i=0;i<str.length;i++){
        if(str.substring(i,i+1)==chars){
            arr.push(i)
        }
    }
    return arr
}

5.監聽滾動條的事件,並獲取top&bottom的距離

$(window).scroll(function() {  
    var scrollTop = $(this).scrollTop();  
    var docHeight = $(document).height();  
    var windowHeight = $(this).height();
    var scrollHeight=document.body.scrollHeight;

    console.log("scrollTop:"+scrollTop);
    console.log("scrollbottom:"+(docHeight-scrollTop-windowHeight));

    if(scrollTop + windowHeight == docHeight) {    
        alert("已經到最底部了!");  
    }
});

6.-‘類繼承’和‘原型繼承’有什麼區別?

類繼承:
    例項由類繼承而來(建築圖紙和實際建築的關係),同時還會建立父類—子類這樣一種關係,也叫做類的分層
分類。通常是用 new 關鍵字呼叫類的建構函式來建立例項的。不過在 ES6 中,要繼承 一個類,不用 class 關
鍵字也可以。儘量不用類繼承,除非是單一級的使用。

原型繼承:
    例項/物件直接從其它物件繼承而來,建立例項的話,往往用工廠函式或者 Object.create() 方法。例項可
以從多個不同的物件組合而來,這樣就能選擇性地繼承了。主要實現手段有:委託(原型鏈);組合;函式式(這
個函式式原型繼承不是函數語言程式設計。這裡的函式是用來建立一個閉包,以實現私有狀態或者封裝)

7.雙向資料繫結/單向資料流的含義和區別

雙向資料繫結:
    UI 層所呈現的內容和 Model 層的資料動態地繫結在一起,其中一個發生了變化,就會立刻反映在另一個
上。比如使用者在前端頁面的表單控制元件中輸入了一個值,Model 層對應該控制元件的變數就會立刻更新為使用者所輸入的
值;反之亦然,如果 Modal 層的資料有變化,變化後的資料也會立刻反映至 UI 層。Angular 則是雙向資料綁
定的典型。

單向資料流:
    意味著只有 Model 層才是單一資料來源。UI 層的變化會觸發對應的訊息機制,告知 Model 層使用者的目的。
只有 Model 層才有更改應用狀態的許可權,這樣一來,資料永遠都是單向流動的,其狀態的變化是很容易跟蹤的。
React 是單向資料流的典型。

8.jquery不常用但實用的方法

(1)位置相關
    offset()          $(“#qq”).offset()          相對瀏覽器視窗的位置
    offsetParent()    $(“#qq”).offsetParent()    #qq相對最近的已經定位的祖先的位置
    position()        $(“#qq”).position()        已定位的元素的position值
(2)DOM元素的包裹
    wrap()           $(“#qq”).wrap(“<div id=’qqPar’/>”) 
    wrapAll()        所有指定元素都會被包裹
    wrapInner()      指定元素的內容會被包裹
(3)刪除相關
    detach()         刪除了還能恢復
    empty()          刪除子元素的所有東西
    remove()         刪除指定元素
    unwrap()         刪除指定元素的父節點,但是保留本身

9.基本型別與引用型別有什麼區別?

基本資料型別: Undefined、Null、Boolean、Number、String
引用資料型別: Object, Array, Date, RegExp(正則), Function

區別:
    儲存:
        基本型別值在記憶體中佔據固定大小的空間,因此被儲存在棧記憶體中
        引用型別的值是物件, 儲存在堆記憶體中. 引用型別的變數實際上是一個指向該物件的指標
    複製:
        從一個變數向另一個變數複製基本型別的值, 會建立這個值的一個副本
        從一個變數向另一個變數複製引用型別的值, 複製的其實是指標, 因此兩個變數最終都指向同一個物件
    檢測:
        確定一個值是哪種基本型別可以用typeof操作符
        確定一個值是哪種引用型別可以使用instanceof操作符

10.null,undefined 的區別?

undefined 表示不存在這個值    typeof undefined //"undefined"
null 一個物件被定義了,值為“空值”    typeof null //"object"

undefined :是一個表示"無"的原始值或者說表示"缺少值",就是此處應該有一個值,但是還沒有定義。例如變數
被聲明瞭,但沒有賦值時,就等於undefined
null :是一個空物件, 沒有任何屬性和方法。例如作為函式的引數,表示該函式的引數不是物件

注意:在驗證null時,一定要使用 === ,因為 == 無法分別 null 和 undefined

11.什麼是閉包(closure),為什麼要用它?

閉包:是指有權訪問另一個函式作用域中變數的函式。
特點:
    1.建立閉包的最常見的方式就是在一個函式內建立另一個函式;
    2.利用閉包可以突破作用鏈域,將函式內部的變數和方法傳遞到外部;
    3.使用閉包主要是為了設計私有的方法和變數;
    4.閉包的優點是可以避免全域性變數的汙染,缺點是閉包會常駐記憶體,會增大記憶體使用量;
    5.在js中,函式即閉包,只有函式才會產生作用域的概念;
特徵:
    1.函式內再巢狀函式;
    2.內部函式可以引用外層的引數和變數;
    3.引數和變數不會被垃圾回收機制回收;
例子:
    var add = (function () {
        var counter = 0;
        return function () {return counter += 1;}
    })();
    add();
    //1
    add();
    //2

12.什麼是偽陣列

偽陣列概念:是能通過Array.prototype.slice 轉換為真正的陣列的帶有length屬性的物件;
偽陣列示例:
    1.arguments物件
    2.呼叫getElementsByTagName,document.childNodes之類的node集合
偽陣列變更:
    Array.prototype.slice.call(fakeArray)轉變為真正的Array物件,返回新陣列而不會修改原陣列

13.javascript建立物件的幾種方式

1.物件字面量(最後一個key-value不新增逗號)
    var obj={
        name:"yjs",
        age:25,
    };
    優缺點:複用性較差(缺)

2.建構函式(函式名首字母使用大寫,區分函式和自定義物件,可以傳參的呦)
    function NewObj(){}
    var person=new NewObj();
    person.name="yjs";
    person.age="25";
    person.city="sjz";
    person.getName=function(){
        console.log("物件的名稱是:"+person.name)
    }
    person.getName();
    優缺點:複用性較差(缺)

3.建構函式-含參(用this關鍵字定義構造的上下文屬性,一般不會出現return的語句)
    function One(name,age,city){
        this.name=name;
        this.age=age;
        this.city=city;
        this.getName=function(){
            console.log("物件的名稱是:"+person.name)
        }
    }
    var one=new One("yjs",25,"sjz");//例項化物件
    one.getName();
    優缺點:例項化的物件可以識別指定的型別(優);每次例項都會重新建立函式,全域性變數多(缺)

4.工廠函式(內建物件,這種事最不推薦使用的)
    var per=new Object();
    per.name="yjs";
    per.age=25;
    per.city="sjz";
    per.getName=function(){
        console.log("物件的名稱是:"+person.name)
    }
    per.getName();
    優缺點:所有的例項都指向一個原型,物件無法識別(缺)

5.原型
    function One(){}
    One.prototype.name="yjs";
    One.prototype.getName=function(){
        console.log("物件的名稱是:"+person.name)
    }
    var one=new One();
    one.getName();
    優缺點:建立函式放在原型避免全域性變數多的問題(優);不能初始化引數(缺)

6.混合(舉例為:建構函式方式和原型方式的混合,以上幾種可任意組合)
    function One(name){
        this.name=name;
    }
    One.prototype.getName=function(){
        console.log("物件的名稱是:"+person.name)
    }
    var one=new One("yjs");
    one.getName(); 

14.談談This物件的理解。

1.this總是指向函式的直接呼叫者(而非間接呼叫者);
2.如果有new關鍵字,this指向new出來的那個物件;
3.事件中,this指向觸發這個事件的物件(特殊:IE中的attachEvent中的this總是指向全域性物件Window);

15.call()和apply()方法的區別

作用:都能繼承另一個物件的方法和屬性
區別:引數列表不一樣
書寫:Function.call(obj, arg1, arg2,...)    Function.apply(obj, args) 
引數:obj-要被繼承的物件;第二個引數-傳遞的實參值
舉例:
    function A(a){console.log(a)}
    function B(b,c){console.log(b+c)}
    A.call(B,10);    //10
    B.applay(A,[10,20])    //30
    

16.new操作符具體幹了什麼

1.建立一個空物件,並且 this 變數引用該物件,同時還繼承了該函式的原型。
    var obj  = {};
2.屬性和方法被加入到 this 引用的物件中。
    obj.__proto__ = Base.prototype;
3.新建立的物件由 this 所引用,並且最後隱式的返回 this 。
    Base.call(obj);

17.IE與火狐的事件機制有什麼區別? 如何阻止冒泡

事件:網頁中的某個操作,點選,懸停,雙擊,鍵盤事件等
機制:IE是事件冒泡、其他的瀏覽器同時支援兩種事件模型(捕獲型事件和冒泡型事件)
阻止:ev.stopPropagation();(舊ie的方法 ev.cancelBubble = true;)

18.事件委託(事件代理)是什麼

原理:事件冒泡, 委託到已知的父級元素。

範圍:1.js指令碼動態新增的;2.不好定位的元素事件;3.相同元素過多;

例子:
    html部分:
    <ul id="list">
        <li id="li-1">Li 2</li>
        <li id="li-2">Li 3</li>
    </ul>

    js部分:
    document.getElementById("list").addHandler("click", function(e){
        var e = e || window.event;
        var target = e.target || e.srcElement;
        if(target.nodeName.toUpperCase == "LI"){
            console.log("li的ID是:"+e,target.id);
        }
    });

19.XML和JSON的區別

1.JSON相對於XML來講,資料的體積小,傳遞的速度更快;
2.JSON與JavaScript的互動更加方便,更容易解析處理,更好的資料互動;
3.JSON對資料的描述性比XML較差;
4.JSON的速度要遠遠快於XML;

20.哪些操作會造成記憶體洩漏

1.setTimeout 的第一個引數使用字串而非函式的話,會引發記憶體洩漏;
2.閉包、控制檯日誌、迴圈(在兩個物件彼此引用且彼此保留時,就會產生一個迴圈);
3.當頁面中元素被移除或替換時,若元素繫結的事件仍沒被移除,在IE中不會作出恰當處理,此時要先手工移除事件,不然會存在記憶體洩露。

21.面向物件中繼承實現

1.prototype原型鏈方式:
    function One(name){
        this.name = name;
        this.getName=function(){
            console.log(this.name);
        }
    }
    function Two(name){
        this.name = name;
    }
    Two.prototype = new One();
    var a = new One("gc");
    var b = new Two("yjs");
    a.getName();    //gc
    b.getName();    //yjs


2、call()/apply()方法
    function One(name){
        this.name = name;
        this.getName=function(){
            console.log(this.name);
        }
    }
    function Two(){
        var args = arguments;
        One.call(this,args[0]);    // One.apply(this,arguments);
    }
    var a = new One("gc");
    var b = new Two("yjs");
    a.getName();    //gc
    b.getName();    //yjs


3.混合方法(prototype,call/apply)
    function One(name){
        this.name = name;
        this.getName=function(){
            console.log(this.name);
        }
    }
    function Two(){
        var args = arguments;
        One.call(this,args[0]); 
    }
    Two.prototype = new One();
    var b = new Two("yjs");
    b.getName();    //yjs


4.物件冒充
    function One(name){
        this.name = name;
        this.getName=function(){
            console.log(this.name);
        }
    }
    function Two(name){
        this.tt = One; //將One類的建構函式賦值給this.tt
        this.tt(name); //js中實際上是通過物件冒充來實現繼承的
        delete this.tt; //移除對One的引用
    }
    var a = new One("gc");
    var b = new Two("yjs");
    a.getName();    //gc
    b.getName();    //yjs

22.