【ECMAScript】对象属性遍历、this、caller_callee

1. 实现链式操作

每个函数return this

var sched = {
  wakeup: function(){
    console.log('Running');
    return this;
  },
  morning: function(){
    console.log('Go shopping');
    return this;
  },
  noon: function(){
    console.log('Having a rest');
    return this;
  },
  afternoon: function(){
    console.log('Studying');
    return this;
  },
  evening: function(){
    console.log('Walking');
    return this;
  },
  night: function(){
    console.log('Sleeping');
    return this;
  }
}
sched.wakeup().morning.().afternoon().evening().night();

2. 对象

2.1 通过[]访问属性名

[] 里面放字符串

var myLang = {
  No1: 'HTML',
  No2: 'CSS',
  No3: 'JavaScript',
  myStudingLang: function(num){
    console.log(this[`No${num}`]);
  }
}

myLang.myStudingLang(1);

最早的 JS 引擎 都是通过 obj[‘name’] 访问的,

后来有了 . 语法,实际上访问 obj.name ,内部隐式的转换为 obj[‘name’](chrome v8 引擎不一定是这么做的)

2.2 对象枚举

枚举:一组有共同特性的集合

JavaScript 的枚举实际上就是对象,有枚举就有遍历,是相辅相成的。

枚举 -> 遍历:在一组信息,按顺序一个一个的去获取其信息的过程

for-in 既可以遍历对象,也可以遍历数组

2.2.1 遍历数组

var arr = [1, 2, 3, 4, 5];

// 这个循环的过程就叫遍历的过程
// 方式1
for(var i = 0; i < arr.length; i++){
  console.log(arr[i]);
}

// 方式2
for(var i in arr){ 
  console.log(arr[i]);
}

2.2.2 遍历对象

var car = {
  brand: '马自达', // key : value
  color: 'white',
  displacement: '2.0'
}

for(var key in car){
  console.log(key + ': ' + car[key]);
  
  // car.key 不行原因: car.key -> car['key'] -> undefined
  console.log(car.key); // undefined
  
}

2.3 hasOwnProperty

功能:排除原型上的自定义属性

var obj = {
  name: 'Tom',
  age: 30
}

obj.hasOwnProperty('name') // true 

例1

function Car(){
  this.brand = '马自达';
  this.color = 'white';
  this.displacement = '2.0';
}

Car.prototype = {
  lang: 5,
  width: 2.5
}

Object.prototype.name = 'Object';

var car = new Car();
console.log(car);

for(var key in car){ // 原型链上的自定义属性也会被打印出来
  // 找对象自身的属性,而不找原型上的所有属性
  if(car.hasOwnProperty(key)){ 
    console.log(key + ': ' + car[key]);
  }
}
var car = {
  brand: '马自达',
  color: 'white',
}

// 隐式的在找 car['displacement']
console.log('displacement' in car); // false

hasOwnProperty 是排除原型的,但是 in 是不排除的

function Car(){
  this.brand = '马自达';
  this.color = 'white';
  this.displacement = '2.0';
}

Car.prototype = {
  displacement: '3.0'
}

var car = new Car();
console.log('displacement' in car); // true

2.4 instanceof ⭐⭐

判断对象是否是该构造函数实例化出来的

A 对象的原型里到底有没有B构造函数的原型,在原型链上,只要B实例化出来的对象,它的原型和A对象原型链上重合的都是true

2.4.1 例子

function Car(){}
var car = new Car();

function Person(){}
var p = new Person();

console.log(car instanceof Car); // true
console.log(p instanceof Car); // false
console.log(car instanceof Object); // true
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true
console.log({} instanceof Object); // true

2.4.2 判断是否是数组的4种方式

var a = [];

// 1.
console.log(a.constructor); 

// 2. 
console.log(a instanceof Array);

// 3.
var str = Object.prototype.toString, // 缓存方法
    trueTip = '[object Array]';
str.call(a) === trueTip; // call 更改 this 指向
console.log(str); // [object Array]

分析:
Object.prototype = {
  toString: function(){
    this.toString(); // call(a) 就相当于 a.toString
  }
}

// 4. 
Array.isArray(a); // true

2.4.3 让 arr 调用 Object 上的 toString

var arr = new Array(1, 2, 3);
console.log(arr); // [1, 2, 3]
console.log(arr.toString()); // 1, 2, 3

// 让 arr 调用 Object 上的 toString
Object.prototype.toString.call(arr); // [object Array]

2.5 Object.defineProperty

实现下面条件,打印内容⭐

if(a == 1 && a == 2 && a == 3) {
  console.log('You win!!');
}

答:相等性判断 会经过 toString

// 方法1
var a = {
  _a: 0,
  toString() {
    return ++this._a;
  }
};
if(a == 1 && a == 2 && a == 3) {
  console.log('You win!!');
}

变形:

// get set -> getter setter

// window -> a

var _a = 0;
Object.defineProperty(window, 'a', {
  get(){
    return ++_a;
  }
})

if(a === 1 && a === 2 && a === 3) {
  console.log('You win!!');
}

变形:

var obj = {
  _a: 0,
  get a(){ // 语法糖
    return ++this._a
  }
}

// 或者
var obj = {
  _a: 0
}
Object.defineProperty(obj, 'a', {
  get(){
    return ++obj._a;
  }
})

if(obj.a === 1 && obj.a === 2 && obj.a === 3) {
  console.log('You win!!');
}

3. this

3.1 普通函数中的 this

  1. 在普通函数中,只要没有实例化这个函数, this 是默认指向 window 的;
  2. this 在全局范围内也是指向 window 的
// 函数内部的 this
function test(b) {
  this.d = 3; // 相当于 window.d = 3,相当于直接 d = 3
  var a = 1;
  function c(){}
}

test(123);

console.log(d); // == this.d == window.d

分析:
AO = {
  arguments: [123], // 形参和实参一一对应的时候会存进 arugments 中
  this: window, // 预编译的时候 this 默认指向 window
  b: undefined -> 123, 
  a: undefined,
  c: function c(){}
}

1. 在普通函数中,只要没有实例化这个函数, this 是默认指向 window 的;
2. this 在全局范围内也是指向 window 的

3.2 构造函数中的 this

构造函数的 AO,GO

function Test(){
  // var this = {
  // 	__proto__: Test.prototype
  // }
  this.name = '123';
}

var test =  new Test();

分析:
AO = {
  this: window ->
      {			// 实例化的时候被覆盖了
        name: '123',
        __proto__: Test.prototype,
      }, // 这就形成了原型链
}

GO = {
  Test: function Test(){...},
  test: {
    name: '123',
    __proto__: Test.prototype,
  }
}

3.3 call, apply

function Person(){
  this.name = 'Tom';
  this.age = 18;
}

function Programmer(){
  Person.apply(this);
  this.work = 'Programming';
}

var p = new Programmer();
console.log(p);

3.4 总结

  1. 全局 this -> window
  2. 预编译函数 this -> window
  3. apply,call 改变 this 指向
  4. 构造函数的 this 指向实例化对象

4. callee, caller

4.1 callee

arguments.callee 实参列表当中的一个属性

function test(a, b, c){
  // 打印的是正在被执行的函数对象
  console.log(arguments.callee); // arguments 实参所指向的函数是谁,就打印谁
  // 通过 arguments.callee 找到对应的函数,然后再打印它的长度,
  // 相当于打印 test.length
  console.log(arguments.callee.length);
  console.log(test.length); // 形参的长度
  console.log(arguments.length); // 实参的长度
}

test(1, 2, 3)

arguments.callee 在哪个函数就指向哪个函数

function test1(){
  // arguments.callee 在哪个函数就指向哪个函数
  console.log(arguments.callee); 
  
  function test2(){
    console.log(arguments.callee);
  }
  
  test2()
}

test1();

例子:用递归的方式累加 n 位数

function sum(n) {
  if(n <= 1) {
    return 1;
  }
  return n + sum(n - 1);
}

var res = sum(10);
console.log(res);


// 用立即执行函数实现
var sum = (function(n){
  if(n <= 1) {
    return 1;
  }
  return n + arguments.callee(n - 1);
})(10);

console.log(sum);

4.2 caller

'use scrict';
test1();
function test1(){
  test2();
}
function test2(){
  // 返回当前被调用函数的函数引用
  console.log(test2.caller); // 调用当前函数的函数引用
}

5. 面试题

  1. 打印结果是什么

    function foo(){
      // 传 null ,没有改变 this 指向
      bar.apply(null, arguments); // 相当于执行 bar(arguments)
    }
    
    function bar(){
      console.log(arguments);
    }
    
    foo(1, 2, 3, 4, 5);
    // [1, 2, 3, 4, 5]
    
    所有的函数执行都有一个 call ,
    如bar() -> bar.call(arugments)-> bar(arguments)
    
  2. JS 的 typeof 可能返回的值有哪些?

    七种
    object, boolean, string, number, undefined, function, symbol
    
    注意: typeof(null) = object
    
  3. 执行结果是什么?

    function b(x, y, a){
      arguments[2] = 10;
      alert(a); // 10
    }
    
    b(1, 2, 3);
    
    
    function b(x, y, a){
      a = 10;
      alert(arguments[2]); // 10
    }
    
    b(1, 2, 3);
    
    实参和形参是映射关系,一一对应
    
  4. 打印结果?

    var f = (
      function f() {
        return 1;
      },
      function g() {
        return 2;
      }
    )
    
    console.log(typeof f); // function g(){..}
    
    var f = (
      function f() {
        return 1;
      },
      function g() {
        return 2;
      }
    )()
    
    console.log(typeof f); // 'number'
    
  5. 结果

    undefined == null; // true
    undefined === null; // false
    isNaN('100');	// false
    parseInt('1a') == 1; // true
    
  6. 打印结果

    function isNaN1(num){
      var res = Number(num);
      // NaN 不等于任何东西,包括它本身
      if(res == NaN){
        return true;
      } else {
        return false
      }
    }
    console.log(isNaN1('abc')) // false
    
    // ----- 改写 -----
    function isNaN1(num){
      var res = Number(num) + '';
      // NaN 不等于任何东西,包括它本身
      if(res == 'NaN'){
        return true;
      } else {
        return false
      }
    }
    
    console.log(isNaN1('abc')) // true
    
  7. 执行结果:{} == {},是否相等,为什么,怎么做?⭐

    {} == {}; // false ⭐
    因为引用值对比的是地址,两个空对象保存在不同的地址中
    
    修改:
    先声明一个对象,再把这个对象赋值给新对象,这个时候它们就相等了
    var obj = {};
    var obj1 = obj;
    obj == obj1;
    
  8. 打印结果是什么?

    var a = '1';
    function test(){
      var a = '2';
      this.a = '3';
      console.log(a);
    }
    
    test(); // '2'
    new test(); // '2'
    console.log(a); // '3'
    
    AO = {
      a: undefined -> '2',
      this: -> window 
            -> {
              a: 3,
              __proto__: test.prototype
                }
    }
    
    GO = {
      a: undefined -> 1 -> 3,
    }
    
  9. 打印结果是什么?

    var a = 5;
    function test(){
      a = 0;
      console.log(a);
      console.log(this.a);
      var a;
      console.log(a);
    }
    
    test(); // 0 5  0
    new test(); // 0 undefined 0
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值