JavaScript學習補充(二)

變量作用域與解構賦值
在JavaScript中,用var申明的變量實際上是有作用域的
如果在函數體內申明,則該變量的作用域是整個函數體,在函數體外不可引用該變量;如果兩個不同的函數各自申明同一個變量,該變量只能在各自函數體內起作用;由於JavaScript函數可以嵌套,內部函數可以訪問外部函數定義的變量,外部的不能訪問內部定義變量;如果內部變量和外部變量重名,則內部函數的變量將屏蔽外部變量
變量提升
 JavaScript先掃描整個函數體語句,把所有申明的變量提升到函數頂部;
 因此要嚴格遵守“在函數內部首先聲明所有變量”這一規則
'use strict'
function fun(){
	var a='hello,'+b;
	console.log(a);//'hello,undefined'.JavaScript自動提升了b的聲明,但是沒有提升變量b的值
	var b='boy';
}
全局作用域
JavaScript默認有一個全局對象window,全局作用域的變量實際上被綁定到window的一個屬性(不在任何函數內定義的變量就具有全局作用域)可以通過  函數名或者window.函數名訪問全局變量;
頂層函數的定義也是一個全局變量,綁定到window對象
我們每次調用的alter()函數實際上也是window的一個變量
'use strict'
function fun(){
	alert('fun');
}
fun();//直接調用fun()
window.fun();//通過window.fun()調用
任何變量(或函數)如果沒有在當前作用域中找到,就會繼續往上找,最後如果在全局作用域中也沒有,則報ReferenceError錯誤
名字空間
var MA={};//唯一的全局變量MA,充當名字空間
//其他變量
MA.name="ma";
MA.version=1.0;
//其他函數
MA.fun=function(){return 'fun';};

局部作用域

JavaScript的變量作用域實際上是函數內部,我們無法在for循環等語句塊內定義具有局部作用域的變量,
ES6的let代替var可以申明一個塊級作用域的變量

'use strict'
function fun(){
	for(var i=0;i<10;i++){
	}
	i+=10;//仍然可以引用變量i

}
//ES6
'use strict'
function fun(){
	for(let i=0;i<10;i++){
		
	}
	i+=10;//SynataxError;
}
常量
之前都是用大寫字母表示常量,不能修改它的值,ES6之後用const定義,const和let都具有塊級作用域
解構賦值
即可以同時對一組變量進行賦值
對數組元素進行解構賦值時,多個變量要用【】括起來
如果數組本身還要嵌套,嵌套層次和位置要保持一致,解構賦值還可以忽略某些元素,
如需要從一個對象中取出若干屬性,對嵌套的對象屬性賦值,只要保證對應層次一致,使用解構賦值對對象屬性進行賦值時,如果對應屬性不存在,變量將被賦值爲undefined
使用默認值避免不存在的屬性返回undefined
有時候如果變量已經被聲明瞭,再次賦值時正確的寫法也會報語法錯誤,這是因爲JavaScript引擎把{開頭的語句當作了塊處理,於是=不再合法,解決方法是用小括號括起來
//之前
var arr=[1,2,3];
var x=arr[0];
var y=arr[1];
var z=arr[2];
//ES6
'use strict'
var[x,y,z]=[1,2,3];
//嵌套
let [x,[y,z]]=[1,[2,3]];
//忽略某些元素
let [, ,z]=[1,2,3];//忽略前兩個元素,只對z進行賦值第三個元素
z;//3
//去對象屬性
var person={
	name:'小木',
	age:10,
	gender:'male',
	school:'第一小學'
}var {name,age,gender}=person;
var{name,age:id}=person;
name;//'小木'
id;//10
//注意:age不是變量,而是爲了讓變量id獲得age屬性
age;//Uncaught ReferenceError:passport is not defined
var {name,single=true}=person;//使用默認值
name;//'小木'
single;//true

//嵌套
var man={
	name:'小木',
	age:10,
	gender:'male',
	address:{
		city:'Beijing'
		street:'大柵欄'
	}
}
var {name,age,address:{city}}=man;


//變量已經聲明後賦值
var a,b;
{a,b}={name:'Jim',a:10,b:20};//語法錯誤:Uncaught SyntaxError:Unexpected token=
({a,b}={name:'小木',a:10,b:20});

方法
var person={
	name:'小木',
	birth:1998,
	age:function(){
		var y=new Date().getFullYear();
		return y-this.birth;//this指向當前對象
	}
}
person.age();//22
getAge();//NaN//單獨調用getAge(),this指向window
//要保證this指向明確,必須用OBJ.xxx()形式調用
//static模式下報錯:Uncaught TypeError :Cannot read property'birth'of undefined

在strict模式下,讓函數的this指向undefined
上有大坑
方法重構後

'use strict'
var person={
	name:'BOB',
	age:function(){
	//var that=this;//在方法內部一開始捕獲this
		function getAge(){
			var y=new Date().getFullYear();
			return y-this.birth;

		}
		return getAge();
	}
};
person.age();//報錯:Uncaught TypeError :Cannot read property'birth'of undefined
//因爲this只在只在age 方法的函數內指向person,在函數內部定義的函數this又指向了undefined(在非static模式下,指向window)

//修復方法 用that變量捕獲this

apply

指定函數的this指向哪個對象,可以用函數本身的apply方法,接受兩個參數,第一個是需要綁定的this變量,第二個是Array函數本身的參數
function getAge(){
	var y=new Date().getFullYear();
	return y-this.birth;
	
}
var person={
	name:'BOB',
	birth:1998;
	age:getAge
};
person.age();//22
getAge.apply(person,[]);//22,this指向person,參數爲空
與apply相似的是call函數,區別:apply()把參數打包成數組再傳入,call()把參數按順序傳入
裝飾器
利用apply()還可以動態改變函數的行爲,因爲JavaScript所有對象是動態的,即使內置的函數我們也可以重新指向新的函數
'use strict'
var count=0;
var oldParseInt=parseInt;//保存原函數
window.parseInt=function(){
	count+=1;
	return oldParseInt.apply(null,arguments);//調用原函數
}
parseInt('10');
parseInt('20');
console.log(count);//2

高階函數

map

定義在JavaScript的Array中,我們調用Array的map()方法,傳入自己的函數,得到新的Array作爲結果
'use strict'
function pox(x){return x*x;}
var arr=[1,2,3,4];
var results=arr.map(pox);//[1,4,9,16]

reduce

  Array的reduce()把一個函數作用在這個數組上,這個函數必須接收兩個參數,把結果繼續和序列的下一個元素做累積計算
[x1,x2,x3,x4].reduce(f)=f(f(f(x1,x2),x3),x4)

filter

用於將Array的某些元素過濾掉,返回剩下的元素
只接收一個函數,filter()把傳入的函數一次作用於每個元素,根據返回值是true還是false決定是保留還是丟棄該元素
var arr=[1,2,3,4,5,6];
var f=function(x){return x%2!==0;};
var r=arr.filter(f);//[1,3,5]

//去掉空字符串 IE9以下版本沒有trim()方法
var arr=['a','','b',null,undefined,'c'];
var r=arr.filter(function(s){
 	return s&&s.trim();
 	});//['a','b','c']

回調函數

 filter()接受的回調函數,可以有多個參數,第一個參數是Array的某個元素,還可以接收另外兩個參數(元素的位置和數組本身)
var arr=['a','b','c'];
var r=arr.filter(function(element,index,self){
		console.log(element);
		console.log(index);
		console.log(self);
		return true;
	});
//去除重複元素
'use strict'
var r,arr=['apple','orange','orange'];
r=arr.filter(function(element,index,self){
		return self.indexof(element)===index;
	});

	
	

sort

sort()是將數字轉換爲String之後用ASCII碼進行排序
[10,20,1,2].sort();//[1,10,2,20]
//10在2的前面是因爲1的ASCII碼在2的前面
因爲sort()是高階函數,可以接受函數實現自定義功能
'use strict'
var arr=[10,20,1,2];
arr.sort(function(x,y){
	if(x<y) {return -1;}
	if(x>y) {return 1;}
	return 0;
});
console.log(arr);//[1,2,10,20]

sort()方法會直接對Array進行修改,他返回的結果仍是當前Array

var arr=['b','a','c'];
var arr1=arr.sort();
arr==arr1;//true

every()方法可以判斷數組的所有元素是否滿足測試條件

find()方法用於查找符合條件的第一元素,如果找到了返回這個元素,否則返回undefined

findIndex()查找符合條件的第一個元素,返回這個元素的索引,沒有找到返回-1

forEach()把每個元素依次作用於傳入的函數,但不會返回新的數組
forEach()用於遍歷數組,傳入的函數不需要返回值
來源於廖雪峯的官方網站

返回閉包時,返回函數不要引用任何循環變量,或者後續會發生變化的變量

一個立即執行的匿名函數可如下寫
(function(x){
	return x*x;
})(3);

箭頭函數
x=>xx
相當於
function(x){
return x
x;
}

使用之前檢測瀏覽器是否支持ES6的Arrow Function
'use strict'
var fn=x=>x*x;
console.log('支持');
//方式一
var fun=x=>x*x;
//方式二
x=>{
	return x;
}
//參數不是一個,用括號括起來
(x,y,...rest)=>{return x;}
//返回一個對象
x=>({foo:x})


箭頭函數和匿名函數的區別:箭頭函數內部this是詞法作用域,由上下文確定
var person={
	birth:1998,
	getage:function(){
		var b=this.birth;//1998
		var fn=()=>new Date().getFullYear()-this.birth;//this指向person對象
	}
};
person.getage();//22
用call()或apply()調用箭頭函數時,無法對this進行綁定,即傳入的第一個參數被省略
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章