javascript基礎總結(一)——綜合

一、查找做用域

當前函數在哪一個做用域下定義的,那麼他的上級做用域就是誰  , 和函數在哪執行沒有任何關係javascript

//做用域實例
var num = 12;
function fn(){
    var num = 120;
    return function(){
        console.log(num);
    }
}
var f = fn();
f();//->120

(function(){
    var num = 1200;
    f();//->120
}())

二、++i 和 i++的區別

//實例說明
var i = 5;
5 + i++ //->10

//i++ 是先運算i自己再加1

//========
var j = 5;
5 + (++j) //->11

//++j 是自己先加1再運算

//面試題
var n = 2;
var num =  5 + (++n) + (n++) + (n++) + (++n); //  - > 21

三、預解釋

在js執行以前,瀏覽器首頁會把帶var和function的關鍵字進行提早申明或定義;var(只是提早申明) function(提早申明+定義)java

注:若是在全局做用域下定義一個 num = 10(沒有var)和帶var 是有區別的
//實例說明

console.log(num);//->undefined
console.log(num1);//->num1 is not defined

var num = 10;//->先預解釋->window.num = 10
num1 =  10;//->window.num1 = 10

//不帶var的num1沒有提早申明因此報is not definend
預解釋面試題
//實例1
function a(b){
 
    alert(b);
 
    function b(){
        alert(b);
    }
    b();
}
a(1);  //1->alert(b函數),2->alert(函數)

//實例2

alert(a);    //undefined
var a = 0;
alert(a);    //0
function fn(){
    alert(a);    //0;由於沒var, 因此這裏的a會被看做是全局的,往上查找,找到a=0,因此是0,若是全局也沒有就會報錯
    a = 2;
    alert(a);    //2
}
fn()
alert(a); //2,fn把這全局的a修改了

//實例3
<script>
 alert(a);//報錯,由於遇到<script>標籤對時,會先對這一塊進行預解析,運行到下面的纔會再進行預解析,下面沒預解析,因此找不到a,因而報錯了
</script>
<script>
    alert(a);    //undefined
    var a = 0;
    alert(a);    //0
</script>

四、區分this

  • 函數執行,首先看函數名是否有".",有的話,"."前面是誰this就是誰;沒有的話this就是window
  • 自執行函數的this永遠是window
  • 給元素的某一個事件綁定方法,當事件觸發的時候,執行對應的方法,方法中的this是當前的元素
  • 構造函數中的this是這個類的實例
  • this還能夠經過call、apply、bind來改變
function fn(){
    console.log(this);
}
var obj = {
    name:"李四",
    writeJs:fn
}
obj.writeJs();//this->obj

var fn = obj.writeJs;
fn();//this->window

function sum() {
    fn();//this->window
}
sum();

(function() {
    fn();//this->window
)()

document.getElementById('div').onclick = fn;//this->#div

document.getElementById('div').onclick = function() {
    //this->#div
    fn();//this->window
}
this綜合實例(360面試題)
var num = 20;
var obj = {
    num: 30,
    fn: (function (num) {
        this.num *= 3;
        num += 15;
        var num = 45;
        return function () {
            this.num *= 4;
            num += 20;
            console.log(num);
        }
    }) (num)
}

var fn = obj.fn;
fn();//65
obj.fn();//85

五、單例模式

描述同一個事物(同一個對象)的屬性和方法放在一個內存空間下,起到分組的做用,這樣不一樣事物之間的屬性名相同,相互也不會發生衝突,咱們把這種分組編寫代碼的模式叫作「單例模式」;面試

var obj = {
    name: '張三',
    age: '18',
    writeJs: function(){
        console.log('my is '+this.name+' can write js');
    }
    
}

obj.writeJs();
注:obj又叫作「命名空間」,單例模式項目開發常用,咱們可使用單例模式進行模塊化開發;

六、工廠模式

單例模式雖然能解決分組做用,可是不能實現批量生產,屬於手工做業模式;正則表達式

工廠模式->「函數的封裝」,「低耦合高內聚」:減小頁面中的冗餘代碼,提升代碼的重複利用編程

function createJs(name,age){
    var obj = {};
    obj.name = name;
    obj.age = age;
    obj.writeJs = function(){
        console.log('my is '+ this.name +' can write js');    
    }
    return obj;
}

var zhangsan = createJs('張三','18');

zhangsan.writeJs();

全部的編程語言都是面向對象開發的。就有類的繼承、封裝、多態數組

  • 繼承:子類繼承父類的屬性和方法
  • 封裝:函授的封裝
  • 多態:當前方法的多種形態

後臺語言中的多態包含重載和重寫。js中的多態不存在重載,方法名同樣,後面的會把前面的覆蓋掉,最後只保留一個方法。(js中有一個相似重載但不是重載:能夠根據傳遞的參數不同,實現不一樣的功能)重寫:子類重寫父類的方法瀏覽器

七、構造函數模式

  • 構造函數是經過new關鍵詞建立一個實例;
    var ex = new CreateJs();其中ex就是CreateJs的實例,生成CreateJs這個類;
  • Js中全部的類都是函數數據類型,它經過new執行變成一個類,可是他自己也是個普通的函數
  • Js中全部的實例都是對象數據類型
  • 在構造函數模式中,類中出現的this.xxx=xxx中this是當前類的一個實例
  • 不一樣實例之間方法不同(下例)
  • 在構造函數模式中,瀏覽器會默認把咱們的實例返回(返回對象數據類型的值);若是咱們手動寫return返回;app

    • 若是ruturn是一個基本數據類型的值,當前實例不變,例如:return 10;
    • 若是return是一個引用數據類型的值,當前實例會被本身返回的值替換,例如:ruturn {name:"張三"}
  • 檢測某個實例是否屬於這個類 instanceof;dom

    • zhangsan instancaof CreateJs->true
    • in:檢測某一個屬性是否屬於這個對象 attr in object,不論是私有屬性仍是共有屬性,只要存在,用in檢測都是true
    • hasOwnProperty:用來檢測某一個屬性是否爲這個對象的私有屬性,這個方法只能檢測私有屬性 obj.hasOwnProperty(attr);
function CreateJs(name,age) {
    this.name = name;
    this.age = age;
    this.writeJs = function() {
        console.log('my is '+ this.name +' can write js');  
    }
    
}

var zhangsan = new CreateJs('張三','18');
zhangsan.writeJs();
var lisi = new CreateJs('李四','20');
lisi.writeJs();
zhangsan.writeJs === lisi.writeJs//false

八、原型鏈模式

  • 每個函數數據類型(普通函數、類)都有一個天生自帶的屬性:prototype(原型),而且這個屬性是一個對象數據類型的值;
  • prototype上瀏覽器天生給它加了個屬性constructor(構造函數),屬性值是當前函數(類)自己;
  • 每一對象數據類型(普通對象、實例、prototype..)天生自帶一個屬性__proto__,屬性值是當前實例所屬類的prototype(原型)
  • Object是Js中全部對象的基類,Object.prototype上沒有__proto__這個屬性
function CreateJs(name,age) {
    this.name = name;
    this.age = age;
}

CreateJs.prototype.writeJs = function() {
    console.log('my is '+ this.name +' can write js');  
}

var zhangsan = new CreateJs('張三','18');
zhangsan.writeJs();
var lisi = new CreateJs('李四','20');
lisi.writeJs();
zhangsan.writeJs === lisi.writeJs//true

經過對象名.屬性名獲取屬性值的時候,首先在對象的私有屬性找,若是私有屬性存在,則獲取的是私有屬性值;編程語言

若是私有沒有,則經過__proto__找到所屬類的原型,原型上存在的話獲取的是公有的屬性值;

若是原型上也沒有,則繼續經過原型上的__proto__繼續向上查找,一直找到Object.protoype爲止

九、call、apply、bind使用

call、apply的區別

對於 apply、call 兩者而言,做用徹底同樣,只是接受參數的方式不太同樣。

func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])

實例:

//一、數組之間追加
var array1 = [12 , "foo" , {name "Joe"} , -2458]; 
var array2 = ["Doe" , 555 , 100]; 
Array.prototype.push.apply(array1, array2); 
/* array1 值爲  [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */

//二、獲取數組中的最大值最小值(數組中自己沒有max方法)
var  numbers = [5, 458 , 120 , -215 ]; 
var maxInNumbers = Math.max.apply(Math, numbers),   //458
    maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

//三、檢驗數據類型
Object.prototype.toString.call(obj) === '[object Array]' ;

//四、類數組轉數組
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));

bind

bind()方法會建立一個新函數,稱爲綁定函數,當調用這個綁定函數時,綁定函數會以建立它時傳入 bind()方法的第一個參數做爲 this,傳入 bind() 方法的第二個以及之後的參數加上綁定函數運行時自己的參數按照順序做爲原函數的參數來調用原函數

var bar = function(){
    console.log(this.x);
}
var foo = {
    x:3
}

bar(); // undefined
//bind是先綁定this和參數,不執行自己函數
//call和apply是綁定this和參數後當即執行自己函數
var func = bar.bind(foo);
func(); // 3

十、計算數組中最大值

<!--一、排序法-->
var arr = [12,43,2323,455,23,5];
arr.sort(function(x,y) {
    return x-y;
})
var max = arr[arr.length-1];

<!--二、假設法-->
var arr1 = [123,34,54,23,56,1];
var max = arr1[0];
for(var i = 0;i < arr1.length;i++ ) {
    var cur = arr1[i];
    if(cur>max) {
        max = cur[i];
    }
}

<!--三、Math.max + apply法-->
var arr2 = [23,43,123,341,3233];
var max = Math.max.apply(null,arr2);

<!--四、Math.max + eval法-->
var arr3 = [567,23,42,45,1,98];
var max = eval("Math.max("+arrr.toString()+")");

十一、數組求平均數

<!--一、類數組轉數組-->
function avgFn() {
    var arr = Array.prototype.slice.apply(arguments);
    arr.sort(function(x,y) {
        return x - y;
    })
    arr.shift()
    arr.pop();
    var arg =(eval(arr.join("+"))/arr.length).toFixed(2)  
    return arg;
    
}
avgFn(68,97,97,91,99.1,89.5,98.23)

<!--二、藉助於call-->
function avgFn() {
    var arr = [].sort.call(arguments,function(x,y) {
        return x-y;
    });
    [].shift.call(arguments);
    [].pop.call(arguments);
    return (eval([].join.call(arguments,"+"))/arguments.length).toFixed(2);
}

avgFn(68,97,97,91,99.1,89.5,98.23)

十二、sort的深刻

arr.sort();只能默認排序10之內的數字和26字母排序
var arr = [1,3,4,65,23,32,43,567];
arr.sort();//log->[1, 23, 3, 32, 4, 43, 567, 65]

var arr1 = [2,5,6,4,9,1.2,0.9];
arr1.sort();//log->[0.9, 1.2, 2, 4, 5, 6, 9]

var arr2 = ['a','y','b','t','p','c'];
arr2.sort();//log->["a", "b", "c", "p", "t", "y"]
arr.sort(function(){})傳遞參數
<!--升序-->
var arr = [1,3,4,65,23,32,43,567];
arr.sort();
/**
*執行中a和b的值
*a  b
*1  3
*3  4
*4  65
*65 23
*4  23
*65 32
*23 32
*65 43
*32 43
*65 567
*a - b > 0 a和b調換位置
*a - b <= 0 位置不變
*/

arr.sort(function(a,b){
    return a - b; 
})

<!--降序-->
arr.sort(function(a,b){
    return b - a;
})
利用localeCompare字母排序

localeCompare第一個字符串字母按照26個字母順序排序,若是第一個字母相同會按照第二個字母排序以此類推,漢字會先轉換成拼音再排序,若是漢字同音會按照漢字unicode順序排

'a'.localeCompare('b')
//-1
'c'.localeCompare('b')
//1

var arr = [{name:"wangwu",age:17},{name:"lisi",age:17},{name:"dahuang",age:21}];

arr.sort(function(a,b){
    return a.name.localeCompare(b.name);
})

//[{name:"dahuang",age:21},{name:"lisi",age:17},{name:"wangwu",age:17}]

var arr = [{name:"小呂",age:17},{name:"老王",age:17},{name:"大黃",age:21}];

arr.sort(function(a,b){
    return a.name.localeCompare(b.name);
})

//[{name:"大黃",age:21},{name:"老王",age:17},{name:"小呂",age:17}]

1三、DOM迴流(重排 reflow)、DOM重繪、DOM映射

  • DOM迴流:DOM樹渲染完畢之後,只要頁面中的HTML結構發生變化(增長刪除元素、位置發生變化),瀏覽器都要從新計算一遍最新的DOM結構,從新對當前頁面進行渲染;
  • DOM重繪:DOM樹位置不發生變化,如元素的顏色背景發生變化,會只針對這個元素渲染,不渲染整個頁面
  • DOM映射:頁面中的標籤和Js中獲取到的元素對象(元素集合)是牢牢綁定在一塊兒的,頁面中HTML結構改變了,Js不須要從新獲取,集合裏面的內容也會跟着自動改變

1四、js中數據綁定的方法

一、動態建立節點方式
var oUl = document.getElementById('ul');
var oLi = document.createElement('li');
oLi.innerHTML = "hello world";
oUl.appendChild(oLi);
二、字符串拼接的方式
var oUl = document.getElementById('ul');

var str = '';
for(var i = 0;i < arr.length; i++) {
    str += "<li>";
    str += "hello" + arr[i];
    str += "</li>"
}
oUl.innerHTML += str;
三、文檔碎片方式
var oUl = document.getElementById('ul');
var frg = document.createDocumentFragment();//建立一個文檔碎片
var oLi = document.createElement('li');
oLi.innerHTML = "hello world";
frg.appendChild(oLi);

oUl.appendChild(frg);

frg = null;//手動清空碎片

1五、正則

什麼是正則

它是一個規則,用來處理字符串的規則。

正則的建立

1. 字面量建立
var reg = /\d/;
2. 實例建立
var reg = new RegExp("\d");

元字符

每個正則表達式都是由元字符和 修飾符組成
  1. 具備特殊意義的元字符

    :轉義後面字符所表明的含義

    ^ :以某一個元字符開始

    $ :以某一個元字符結束

    n :匹配一個換行符

    . :除了n之外的任意字符

    () :分組

    x|y :x或y中的一個

    [xyz] :x或者y或者z中的任何一個字符

    [a-z] :a-z之間的任意字符

[^a-z]:除了a-z之間的任何字符

\d :一個0-9之間的任何數字

\b :匹配一個邊界符

\w :數字字母下劃線中的任意一個字符

\s:匹配一個空白字符 空格、製表符、換頁符...
  1. 表明出現次數的量詞元字符

    * :出現0到屢次

    + :出現1到屢次

    ? :出現0到1次

    {n} :出現n次

    {n,} :出現n到屢次

    {n,m} :出現n到m次

()分組的做用

  • 改變x|y的優先級
var reg = /^18|19$/;
//1八、1九、18一、18九、11九、81九、1819....true
var reg = /^(18|19)$/;
//1八、19true
  • 分組引用
var reg = /^(\w)\1(\w)\2$/;
reg.test("aabb")//true
reg.test("abcd")//false
//\1表明和第一個分組出現如出一轍的內容
//\2表明和第二個分組出現如出一轍的內容

//去除重複的字符
var str = 'aaaabbbbccccddddddssss440000008888';
str.replace(/(\w)\1+/g,"$1");
//"abcds408"
  • 分組捕獲

正則在捕獲的時候,不只僅把大正則匹配到,並且還能夠把小分組的內容捕獲到

var reg = /^(\d{2})(\d{4})(\d{4})(\d{4})\d{2}(\d{1})[\d|X]$/
var arr = reg.exec('100604198805112411');
//["100604198805112411", "10", "0604", "1988", "0511", "1"]
//100604198805112411大正則匹配的內容
//"10", "0604", "1988", "0511", "1"小分組匹配

[](1)、在中括號中出現的全部的字符都是表明自己意義的字符(沒有特殊的含義)(2)、中括號不識別兩位數

var reg = /^[.]$/;
reg.test('1');//false
reg.test('.');//true

var reg = /[12]/;
//1||2 不是12

var reg = /^[21-57]$/;
//2||1-5||7中的任意一個
//年齡介於[16-58]
var reg = /^(1[6-9]|[2-4]\d|5[0-8])$/;
//簡單的驗證郵箱
var reg = /^[\w.-]+@[\da-zA-Z]+(\.[a-zA-Z]{2,4}){1,2}$/;
//中國標準真實姓名2-4位漢字
var reg = /^[\u4e00-\u9fa5]{2,4}$/;
//身份證號碼
//100604198805112411
//10(省)0604(市區縣)19880511(出身年月)24(沒用)1(奇數男、偶數女)1(0-9||X)
var reg = /^(\d{2})(\d{4})(\d{4})(\d{4})\d{2}(\d{1})[\d|X]$/;

正則的捕獲exec

  • 捕獲的內容是個數組
var reg = /\d+/;
reg.exec('ducen23niubi21');
//0:"23",index:5,input:"ducen23niubi"
  • 正則捕獲的特色
懶惰型:每一次執行exec只捕獲第一個匹配的內容,在不進行任何處理的狀況下,在執行屢次捕獲,捕獲的仍是第一個匹配的值
var reg = /\d+/
reg.lastIndex//0
res = reg.exec('ducen23niubi12')//["23"]
reg.lastIndex//0
res = reg.exec('ducen23niubi12')//["23"]
//解決懶惰性,在正則後加修飾符g
var reg = /\d+/g
reg.lastIndex//0
res = reg.exec('ducen23niubi12')//["23"]
reg.lastIndex//7
res = reg.exec('ducen23niubi12')//["12"]
reg.lastIndex//14
res = reg.exec('ducen23niubi12')//null
  • 貪婪性:正則每一次捕獲都是按照匹配最長的結果
var reg = /\d+/;
res = reg.exec('ducen2017niubi12');
//捕獲到的是["2017"]而不是2


//解決正則的貪婪性(在量詞元字符後面添加一個?)
var reg = /\d+?/;
res = reg.exec('ducen2017niubi12');
//捕獲的是["2"];

++?在正則中有不少做用,放在一個不一樣的元字符後面表明出現0-1次 /d?/(數字出現一次或不出現);放在一個量詞的元字符後面是取消捕獲的貪婪性++

正則的修飾符(g、i、m)

var reg = /\d/gim
//g:全局匹配
//i:忽略大小寫匹配
//m:多行匹配
var reg = /\d+/g
var arr = []
res = reg.exec('ducen23niubi12');
while(res) {
    arr.push(res[0]);
    res = reg.exec('ducen23niubi12')
}
arr//["23", "12"]

字符串中的match方法

把全部和正則匹配的字符都獲取到
var reg = /\d+/g
var arr = 'ducen23niubi12'.match(reg);
arr//["23", "12"]

雖然在當前的狀況下match比咱們的exec更加簡便一些,可是match中存在一些本身處理不了的問題:在分組捕獲的狀況下,match只能捕獲大正則匹配的內容,而對小正則捕獲的內容沒法獲取

字符串中的replace方法

var str = "ducen2015ducen2016";
str.replace('ducen','huming');
//"huming2015ducen2016"

str.replace(/ducen/g,function(arg){
    console.log(arguments);
    <!--執行2次
    ["ducen", 0, "ducen2015ducen2016"]
    ["ducen", 9, "ducen2015ducen2016"]
    -->
    return 'huming';
})
//"huming2015huming2016"

str.replace(/ducen(\d+)/g,function(arg){
    console.log(arguments)
    console.log(arguments[1])//2015 2016 獲取小正則
})
<!--["ducen2015", "2015", 0, "ducen2015ducen2016"]-->
<!--["ducen2016", "2016", 9, "ducen2015ducen2016"]-->

replace中的匿名函數執行次數,取決於正則捕獲的次數

每一次執行匿名函數裏面傳遞的參數值arguments和咱們本身經過exec捕獲到的結果是很是相似的(即便正則有分組,咱們也能夠經過arguments獲取)

return:你返回的結果是啥,就至關於把當前大正則捕獲的內容替換成返回的內容

var arr = ['零','壹','貳','叄','肆','伍','陸','柒','捌','玖']
var  s  = "20170401";
s.replace(/\d/g,function(){
    return arr[arguments[0]]
})
<!--"貳零壹柒零肆零壹"-->
<!--千位分割符-->
//1
"2343289".replace(/^(\d{1,3})((?:\d{3})+)$/,function(){
    return arguments[1]+"," + arguments[2].replace(/(\d){3}(?!$)/g,function(){
    <!--(?=$)、(?!$)正向預測、負向預測 -->
        return arguments[0]+ ","
    })
})

//2
var str = '2343289';
str.replace(/(\d)(?!$)/g,function(res,i){
    if((str.length-i-1)%3==0) {
        return res+ ","    
    }else{
        return res;
    }
})

//3
var str = '2343289';
str = str.split('').reverse().join('');
str = str.replace(/(\d{3})/g,'$1,');
str.split('').reverse().join('');


<!--結果:2,343,289-->

正則中?的用法

  • 在量詞後面表明0到1次(?)
var reg = /^(\+|-)?\d+(\.\d+)?$/;
  • 匹配不捕獲(?:)
var reg = /^(?:\+|-)?\d+(\.\d+)?$/
  • 取消正則貪婪捕獲,把?放在量字後面(?)
var reg = /\d+/;
res = reg.exec('ducen2017niubi12');
//捕獲到的是["2017"]而不是2

//解決正則的貪婪性(在量詞元字符後面添加一個?)
var reg = /\d+?/;
res = reg.exec('ducen2017niubi12');
//捕獲的是["2"];
  • 正向預查、負向預查(條件)
(?!n)->匹配任何其後緊接指定字符串 n 的字符串。
(?=n)->匹配任何其後沒有緊接指定字符串 n 的字符串。
相關文章
相關標籤/搜索