对象链式调用、属性遍历、hasOwnProperty、instanceof、caller、callee

1、链式调用原理

// 返回this
var sched = {
    wakeup: function() {
        console.log('Running');
        return this;
    },
    morning: function() {
        console.log('Shopping');
        return this;
    },
    night: function() {
        console.log('Sleeping');
        return this;
    }
}

sched.wakeup().morning().night();

2、对象属性获取

// 对象属性获取-最早JS引擎获取对象使用中括号,后面才用点语法
var myLang = {
    No1: 'HTML',
    No2:'CSS'
}
console.log(myLang['No1']); // 'HTML'

3、对象枚举 - 对象遍历

// 对象枚举 - 对象遍历
var car = {
    brand: 'Benz',
    color: 'red',
    width: '2.5'
}

for(var key in car) {
    // 获取键名
    console.log(key + ':' + car[key]);

    // 获取键值,只能用 car[key] 获取,不能用car.key
    // 原因: car.key -> car['key'] -> undefined
    console.log(car.key); // undefined
}

4、hasOwnProperty

// hasOwnProperty : 排除原型
var obj = {
    name: 'test',
    age: 30
}
console.log(obj.hasOwnProperty(obj.name)); // false


// 一个用法示例
function Car() {
    this.brand = 'Benz';
    this.color = 'red';
}
Car.prototype = {
    lang: 5,
    width: 2.5
}
Object.prototype.name = 'Object';

var car = new Car();

for(var key in car) {
    // 打印全部属性
    // console.log(key + ':' + car[key]);

    // 排除原型上自定义的属性,只获取自身的属性
    if (car.hasOwnProperty(key)) {
        console.log(key + ':' + car[key]);
    }
}

// in 不排除原型 - 实际开发基本不会用到
console.log('lang' in Car); // false
console.log('name' in Car); // true

5、instanceof

// instanceof: 用于判断 引用类型 属于哪个 构造函数 的方法
function Test(){}
var test = new Test();
console.log(test instanceof Test); // true
console.log(test instanceof Object); // true
console.log([] instanceof Object); // true
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true

6、callee 和 caller

// callee 实参列表中的一个属性
// arguments.callee : 返回实参列表对应的函数
function test(a, b, c) {
    console.log(arguments.callee); // 返回test函数
    console.log(arguments.callee.length); // 3 - 形参个数
    console.log(test.length); // 3 - 形参个数
    console.log(arguments.length); // 2 - 实参个数
}
test(1, 2);


// 在哪个函数中执行就是哪个函数
function test1() {
    console.log(arguments.callee); // ƒ test1() {}
    function test2() {
        console.log(arguments.callee); // ƒ test2() {}
    }
    test2();
}
test1();


// 累加递归
function sum(n) {
    if (n <= 1) {
        return 1;
    }
    return n + sum(n - 1);
}

// 表达式写法
var sum = (function(n){
    if (n <= 1) {
        return 1;
    }
    // 找不到函数名,只能用 arguments.callee
    return n + arguments.callee(n - 1);
})(100);

console.log(sum);  // 5050
// caller 返回调用当前被调用函数的函数引用,只有在执行才生效
test1();
function test1() {
    test2();
}
function test2() {
    // test1 调用了 test2 ,所以返回 test1
    console.log(test2.caller); // ƒ test1() {...}
}