先理解兩個概念:基本類型和引用類型的值 1、基本類型和引用類型的值 (1)定義: 基本類型:指簡單的數據段,比如按值訪問的js五種基本數據類型undefined、null、boolean、number、srtring 引用類型的值:指保存在記憶體中的對象,註意一點,js不允許直接操作對象的空間 (2) ...
先理解兩個概念:基本類型和引用類型的值
1、基本類型和引用類型的值
(1)定義:
基本類型:指簡單的數據段,比如按值訪問的js五種基本數據類型undefined、null、boolean、number、srtring
引用類型的值:指保存在記憶體中的對象,註意一點,js不允許直接操作對象的空間
(2)相似和區別:
相同:定義兩種類型的方式都類似:創建一個變數並賦值
不同點1:對於引用數據的值,我們可以添加屬性進去,但是基本類型不行,強行添加會報undefined
下麵給個例子:
var person = new Object() person.name = "saebr"; console.log(person.name)//saber
而基本類型添加屬性會報undefined:
var name = "saber"; name.sex = "女"; console.log(name.sex)//undefined
不同點2:變數的複製也不相同:
var num = 777; var num1 = num; console.log(num1)//777
基本類型的複製,簡單來說就是用num的值來初始化num1,num1中也保存了值777,但是num和num1保存的777是兩個完全獨立的。
var obj = new Object(); var obj1 = obj; obj.name = "saber"; console.log(obj1.name)//saber
而引用類型的複製,最簡單的話來說就是obj保存了一個對象的新實例,複製的過程就是讓obj1的指針也指向這個對象,因此改變其中一個變數就會影響到另外一個變數。
不同點3:參數傳遞的不同
傳遞基本類型的值時,被傳遞的值會被覆制給一個局部變數,而傳遞引用類型的值時,會把值得記憶體的地址複製給局部變數,這麼說可能不好理解,擼兩個例子看看:
首先是基本類型的傳遞參數:
function add(num) { num += 1; return num; } var saber = 7; var archer = add(saber); console.log(saber)//7 console.log(archer)//8
使用數值等基本類型來傳參,函數內部的不會影響外部saber的變數,因為num和saber互相不認識,他們僅僅有相同的值,也就是如同上面所說的是完全獨立的。
其次是引用類型的傳遞參數:
var person = new Object(); function setName(obj){ obj.name = "saber" }; setName(person); console.log(person.name)//saber
看上去好像引用類型的傳遞參數是按引用傳遞,第一次看上去好像是這麼回事,在局部作用域裡面修改對象,會在全局作用域里展現出來,所以誤認為是按引用傳遞。
實際上js都是按值來傳遞參數的,上面的基本類型就不說了,簡單明瞭,下麵寫個例子證明一下,引用類型是按值傳遞的:
var person = new Object(); function setName(obj){ obj.name = "saber" obj = new Object(); obj.name = "archer" }; setName(person); console.log(person.name)//saber
也就是說如果是按引用傳遞的話,person會被修改為指向name屬性值為archer的新對象,但是結果是saber,這已經說明瞭一切。事實上,當函數執行完畢,這個archer的局部對象會被立即銷毀。
(3)檢測引用類型
檢測基本數據類型使用typeof,那麼如何檢測引用類型呢?
所有引用類型的值都是Object的實例,escript提供了instanceof來檢測引用類型和Object構造函數,如果是的話,返回true;
2、作用域
首先,要瞭解一個概念,全局執行環境被認為是windows對象,然後,每個函數都有自己的執行環境,當執行流進入一個函數時,這個函數的環境就會被推入一個環境棧中,當執行完,就會退出這個環境棧,然後返回之前的執行環境
作用域鏈
所以,當代碼在一個環境中執行時,就會創建一個對象的作用域鏈。簡單說一下作用域鏈,作用域鏈的下一個變數對象來自於外部環境,再下一個變數對象又來自更外一層的環境,這樣一層一層直到最外層的全局執行環境windows。
還是擼一串代碼看看,光說根本一連懵逼呀:
var SName = "saber"; function changeSavant(){ var AName = "archer"; // console.log(SName)//saber // console.log(AName)//archer這裡可以訪問兩個,訪問不了beateSavant裡面的LName beateSavant(); function beateSavant(){ var LName = AName; AName = SName; SName = LName; console.log(SName)//archer console.log(AName)//saber console.log(LName)//archer這裡三個都可以訪問到 } } // console.log(SName)//saber這個地方只能訪問到SName // console.log(AName)//AName is not defined changeSavant();
簡單來說,可以看到,函數內部的可以訪問到外部的,但是外部的無法訪問到內部的變數,那麼這是如何訪問到的呢,所以這就是作用域鏈的作用,首先函數的局部環境會先在自己的環境中搜索變數和函數名,搜索不到就再搜索上一層的作用域鏈。
這下是不是簡單明瞭了很多~
延長作用域鏈
js有兩種方式來延長作用域鏈:
(1)try catch中的catch
function add() { try{} catch{}//延長的作用域鏈 }
(2)with