當前函數在哪一個做用域下定義的,那麼他的上級做用域就是誰 , 和函數在哪執行沒有任何關係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 }())
//實例說明 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>
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中有一個相似重載但不是重載:能夠根據傳遞的參數不同,實現不一樣的功能)重寫:子類重寫父類的方法瀏覽器
在構造函數模式中,瀏覽器會默認把咱們的實例返回(返回對象數據類型的值);若是咱們手動寫return返回;app
檢測某個實例是否屬於這個類 instanceof;dom
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
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的區別
對於 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)
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}]
一、動態建立節點方式
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. 字面量建立
var reg = /\d/;
2. 實例建立
var reg = new RegExp("\d");
每個正則表達式都是由元字符和 修飾符組成
:轉義後面字符所表明的含義
^ :以某一個元字符開始
$ :以某一個元字符結束
n :匹配一個換行符
. :除了n之外的任意字符
() :分組
x|y :x或y中的一個
[xyz] :x或者y或者z中的任何一個字符
[a-z] :a-z之間的任意字符
[^a-z]:除了a-z之間的任何字符 \d :一個0-9之間的任何數字 \b :匹配一個邊界符 \w :數字字母下劃線中的任意一個字符 \s:匹配一個空白字符 空格、製表符、換頁符...
* :出現0到屢次
+ :出現1到屢次
? :出現0到1次
{n} :出現n次
{n,} :出現n到屢次
{n,m} :出現n到m次
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]$/;
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?/(數字出現一次或不出現);放在一個量詞的元字符後面是取消捕獲的貪婪性++
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"]
把全部和正則匹配的字符都獲取到
var reg = /\d+/g var arr = 'ducen23niubi12'.match(reg); arr//["23", "12"]
雖然在當前的狀況下match比咱們的exec更加簡便一些,可是match中存在一些本身處理不了的問題:在分組捕獲的狀況下,match只能捕獲大正則匹配的內容,而對小正則捕獲的內容沒法獲取
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-->
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 的字符串。