深入學習jquery原始碼之基本型別與引用型別
深入學習jquery原始碼之基本型別與引用型別
基本型別
基本的資料型別有:undefined,boolean,number,string,null.基本型別的訪問是按值訪問的,就是說你可以操作儲存在變數中的實際的值。
基本型別的值是不可變得:
var name = 'jozo';
name.toUpperCase(); // 輸出 'JOZO'
console.log(name); // 輸出 'jozo'
不能給基本型別新增屬性和方法
var person = 'jozo'; person.age = 22; person.method = function(){//...}; console.log(person.age); // undefined console.log(person.method); // undefined
基本型別的比較是值的比較:
只有在它們的值相等的時候它們才相等。
var a = 1;
var b = true;
console.log(a == b);//true
它們不是相等嗎?其實這是型別轉換和 == 運算子的知識了,也就是說在用==比較兩個不同型別的變數時會進行一些型別轉換。像上面的比較先會把true
轉換為數字1再和數字1進行比較,結果就是true了。 這是當比較的兩個值的型別不同的時候==運算子會進行型別轉換,但是當兩個值的型別相同的時候,
即使是==也相當於是===。
var a = 'jozo'; var b = 'jozo'; console.log(a === b);//true
基本型別的變數是存放在棧區的(棧區指記憶體裡的棧記憶體)棧區包括了變數的識別符號和變數的值。
引用型別
也可以說是就是物件了。物件是屬性和方法的集合。
也就是說引用型別可以擁有屬性和方法,屬性又可以包含基本型別和引用型別。
為引用型別新增屬性和方法,也可以刪除其屬性和方法
var person = {};//建立個控物件 --引用型別 person.name = 'jozo'; person.age = 22; person.sayName = function(){console.log(person.name);} person.sayName();// 'jozo' delete person.name; //刪除person物件的name屬性 person.sayName(); // undefined
引用型別的值是同時儲存在棧記憶體和堆記憶體中的物件
javascript和其他語言不同,其不允許直接訪問記憶體中的位置,也就是說不能直接操作物件的記憶體空間,那我們操作啥呢? 實際上,是操作物件的引用,
所以引用型別的值是按引用訪問的。
引用型別的儲存需要記憶體的棧區和堆區(堆區是指記憶體裡的堆記憶體)共同完成,棧區記憶體儲存變數識別符號和指向堆記憶體中該物件的指標,
也可以說是該物件在堆記憶體的地址。
var person1 = {name:'jozo'};
var person2 = {name:'xiaom'};
var person3 = {name:'xiaoq'};
引用型別的比較
var person1 = {};
var person2 = {};
console.log(person1 == person2); // false
引用型別是按引用訪問的,換句話說就是比較兩個物件的堆記憶體中的地址是否相同,那很明顯,person1和person2在堆記憶體中地址是不同的:
簡單賦值
在從一個變數向另一個變數賦值基本型別時,會在該變數上建立一個新值,然後再把該值複製到為新變數分配的位置上:
此時,a中儲存的值為 10 ,當使用 a 來初始化 b 時,b 中儲存的值也為10,但b中的10與a中的是完全獨立的,該值只是a中的值的一個副本,此後,
這兩個變數可以參加任何操作而相互不受影響。
var a = 10;
var b = a;
a ++ ;
console.log(a); // 11
console.log(b); // 10
物件引用
當從一個變數向另一個變數賦值引用型別的值時,同樣也會將儲存在變數中的物件的值複製一份放到為新變數分配的空間中。前面講引用型別的時候提到,
儲存在變數中的是物件在堆記憶體中的地址,所以,與簡單賦值不同,這個值的副本實際上是一個指標,而這個指標指向儲存在堆記憶體的一個物件。那麼賦值操作後,
兩個變數都儲存了同一個物件地址,則這兩個變數指向了同一個物件。因此,改變其中任何一個變數,都會相互影響:
var a = {}; // a儲存了一個空物件的例項
var b = a; // a和b都指向了這個空物件
a.name = 'jozo';
console.log(a.name); // 'jozo'
console.log(b.name); // 'jozo'
b.age = 22;
console.log(b.age);// 22
console.log(a.age);// 22
console.log(a == b);// true
引用型別的賦值其實是物件儲存在棧區地址指標的賦值,因此兩個變數指向同一個物件,任何的操作都會相互影響。
基本型別與引用型別引數的傳遞
值傳參針對基本型別,引用傳參針對引用型別,傳參可以理解為複製變數值。基本型別複製後倆個變數完全獨立,之後任何一方改變都不會影響另一方;引用型別複製的是引用(即指標),之後的任何一方改變都會對映到另一方。
基本型別引數傳遞
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(count); //按值傳遞 num = count
alert(count); // 20, 沒變化
alert(result); // 30
基本型別變數的值傳遞,方法裡面的變數修改不影響外層的遍歷。還是輸出23.因為23的值存在棧區,方法裡面修改變數僅僅在方法裡有效
void speak(int age){
System.out.println("我今年"+age+"歲了");
age=24;
System.out.println("方法裡age"+age);
}
public static void main(String[] args) {
Person6 zhangsan=new Person6();
int age=23;
zhangsan.speak(age);
System.out.println(age);
}
引用型別引數傳遞
function setName(obj) {
obj.name = "Nicholas";
}
var person = new Object();
setName(person); // obj = person
alert(person.name); // "Nicholas" 看起來是按引用傳遞,但千萬不要以為是按引用傳遞~~~
建立一個物件,並將其儲存在變數person中。然後,這個變數被傳遞到setName(obj)函式中之後就被複制給了obj。在這個函式內部,obj和person引用的是同一個物件,obj也會按引用來訪問同一個物件。
於是,在函式內部為obj新增name屬性後,函式外部的person也將有所反應;因為這時的person和obj指向同一個堆記憶體地址。
變數存在堆區,傳遞的僅僅是個引用,是堆區的一個具體的地方。傳的是引用(地址)而不是具體的值。方法內的變數變了外層呼叫也變了
class Duixiang{
int b;
int w;
int h;
}
public class Person {
void speak(int age,Duixiang duixiang){
System.out.println("我今年"+age+"歲了");
System.out.println("我的是:"+duixiang.b+","+duixiang.w+","+duixiang.h);
age=24;
System.out.println("方法裡age"+age);
duixiang.b=80;
}
public static void main(String[] args) {
Person zhangsan=new Person7();
int age=23;
Duixiang Duixiang=new Duixiang();
duixiang.b=90;
duixiang.w=60;
duixiang.h=90;
zhangsan.speak(age,duixiang);
System.out.println(age);
System.out.println("呼叫地方"+duixiang.b);
}
}
輸出:
我的是90,60,90
呼叫地方 80
物件也是按值傳遞的
function setName(obj) {
obj.name = "Nicholas";
obj = new Object(); //改變obj的指向,此時obj指向一個新的記憶體地址,不再和person指向同一個堆記憶體地址
obj.name = "Greg";
}
var person = new Object();
setName(person); //你看看下面,相信我也是按值傳遞的了吧
alert(person.name); //"Nicholas"
引用傳遞的是指標的值,obj=new Object()改寫了自己的指向,並不會影響到person的指向,這種方式就是按引用傳遞。即使不把物件賦值給函式的引數,obj改寫指向對person也沒影響
var person=new Object();
var obj = person; // 賦值
obj.name="ABC";
obj=new Object();
obj.name="BCD";
console.log(person.name);// ABC 並沒有影響person的指向