深入学习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的指向