基本类型、引用类型、函数声明、函数表达式、arguments、call、apply

课程目标

  • 理解基本类型、引用类型
  • 对象的拷贝
  • 理解函数声明、函数表达式
  • this
  • 理解arguments.callee、call、apply

课程内容

基本类型、引用类型

  • 基本类型值(数值、布尔值、null和undefined):指的是保存在栈内存中的简单数据段;
  • 引用类型值(对象、数组、函数、正则):指的是那些保存在堆内存中的对象,变量中保存的实际上只是一个指针,这个指针执行内存中的另一个位置,由该位置保存对象

var a = 1;
var b = a;
a = 2;
console.log(b); //1

var c = "hello",
    d = c;
c += " world";
console.log(d); 

var obj1 = {name: 'kevin', sex: male},
    obj2 = obj1;
obj1.name = 'xiaoming';
console.log(obj2);

var arr1 = [1,2,3],
    arr2 = arr1;
arr1.push(4);
console.log(arr2);

函数的参数传递

//对于基本类型,函数体复制一份新的变量
function add(num){
    num += 10;
    return num;
}
var count = 20;
var result = add(count); //传递的是外面的count,函数内部实际上创建一个新变量,把count的值负责进去
console.log(count);
console.log(result);

//对于引用类型,函数体里的变量是传递的参数的另外一个名字
function setName(obj){
    obj.name = 'kevin';
    return obj;
}             
var persion = {name: 'xiaoming', age: 100};
var persion2 = setName(persion);
console.log(persion);
console.log(persion2);

function setAge(obj){
    obj.age = 18;
    obj = {};
    obj.age = 20;
    return obj;
}
var persion = {name: 'xiaoming', age: 100};
var p2 = setAge(persion);
console.log(persion);
console.log(p2);

对象浅拷贝和深拷贝

//浅拷贝

function shallowCopy(oldObj) {
    var newObj = {};
    for(var i in oldObj) {
        if(oldObj.hasOwnProperty(i)) {
            newObj[i] = oldObj[i];
        }
    }
    return newObj;
}

//深拷贝

function deepCopy(oldObj) {
    var newObj = oldObj;
    if (oldObj && typeof oldObj === 'object') {
        newObj = Object.prototype.toString.call(oldObj) === "[object Array]" ? [] : {};
        for (var i in oldObj) {
            newObj[i] = deepCopy(oldObj[i]);
        }
    }
    return newObj;
}

函数声明vs函数表达式

解析器会率先读取函数声明,并使其在执行任何代码之前可用; 对于函数表达式,则必须等到解析器执行到它所在的代码行才会被执行。

//函数声明
sum(1, 2);  
//函数声明可以放在代码任何位置,真正在执行时会先把函数声明先放到代码顶部
function sum(a,b){
    console.log( a+b );
}  //这里没分号

//函数表达式
sum (1, 2);                //会报错, 必须先定义,再调用
var sum = function(a, b){  //这里的sum是个引用类型,可以认为是这个匿名函数起的别名。
    console.log( a+b );
};                         //这里有分号,相当于定义一个变量sum,sum的值是个函数。
sum(1, 2);                 //调用放在定义下面

认识this

对象里的this,指向这个对象,代表这个对象的作用域,也可以认为是这个对象

var dog = {
    name: '小呆',
    age: 2,
    sayName: function(){
        console.log(this);
        console.log(this === dog); //true
        alert(this.name);
    },
    setAge: function(age){
        this.age = age;
    }
}
dog.sayName();
console.log(this); //这里的this是window
console.log(this.dog);
console.log(window.dog);

arguments、call、apply

arguments是个对象,保存函数调用时传递的参数列表,arguments有个属性callee,指向本函数。

function factorial(num){
    if(num <= 1){
        return 1;
    }else{
        return num * factorial(num-1);
    }
}

function factorial(num){
    if(num <=1){
        return 1;
    }else{
        return num * arguments.callee(num-1);
    }
}

calll和apply用于改变函数作用域

var color = "red";
var o = { color: "blue" };
function sayColor(){
    alert(this.color);  //这里的this指window
}
sayColor();
sayColor.call(this);   //red
sayColor.call(window); //red
sayColor.call(o);      //blue