18.new

76 阅读3分钟
function Fn() {
  /**
   * EC(Fn)
   *  初始创建Fn这个类的一个实例对象,0x000
   *  初始this:this-> 0x0000
   */
  let total = 0 // 上下文的私有变量 和实例对象没有必然的联系
  this.x = 10 // this.xxx=xxx 都是给实例对象设置的私有属性和方法
  this.y = 20
  this.say = function () {
    console.log('SAY')
  }
  /**
   * 如果不设置返回值,或者返回值是一个基本类型值,默认都会把实例对象0x000 返回;
   * 如果手动返回的是一个引用数据类型值,则以自己返回为主
   */
  // return {
  //   name: 'zhufeng'
  // }
}
let f1 = new Fn()
console.log(f1)

let f2 = new Fn // new执行的时候,如果类不需要传递实参,可以不用加小括号(不加小括号,叫做无参数列表new;设置小括号,叫做带参数列表new;除了是否传递参数的区别,在运算的优先级上也有区别?new Fn->19 new Fn()->20)
// 每一次new都是把函数重新执行(重新形成一个新的私有上下文、重新创建一个实例对象,代码重新执行。。。)
console.log(f1, f2, f1 === f2) // => false


// 检测某个成员(属性/键值)是否属于这个对象,或者是否属于这个对象的私有属性
// in: 检测成员是否属于这个对象「特点:不论是私有属性,还是公有属性,只要有则检测结果就是true」
// hasOwnProperty:用来检测当前成员是否为对象的私有属性「特点:只有是私有属性,结果才是true,哪怕有这个属性,但是属于公用属性,结果也是false」

console.log(f1)
console.log('say' in f1) // -> true
console.log(f1.hasOwnProperty('say')) // -> true

// f1 是一个对象,他可以访问hasOwnPropertity方法并且执行,说明:'hasOwnProperty'属性是它的一个成员
console.log('hasOwnProperty' in f1) // => true
console.log(f1.hasOwnProperty('hasOwnProperty')) // -> false 说明'hasOwnProperty'不是他的私有属性,也就是他的公有属性「前提基于in检测出来的结果是true」


// obj: 要检测的对象
// attr: 要验证的成员
function hasOwnProperty(obj, attr) { // *待解决:
  // 思路一:是他的属性,但是还不是私有的,那么一定是公有的「bug: 如果某个属性即时私有的,也是公有的,则检测出来的结果是不准确的」
  // reurn (attr in obj) && (!obj.hasOwnProperty(attr))
  /**
   * let obj={A:10};
   * Object.prototype.A=20
   * 
   * A 即使他的私有的 也是公有的
   * 
   * return (attr in obj) && (!obj.hasOwnProperty(attr));
   * 
   */

  // 思路二:真正的思路应该是检测原型上的属性,因为原型上的属性是公有的
  let proto = Object.getPrototypeOf(obj)
  while (proto) {
    // 依次查找到原型链,直到找到Object.prototype为止
    if (proto.hasOwnProperty(attr)) {
      return true;
    }
    proto = Object.getPrototypeOf(proto)
  }
  return false
}


let sy = Symbol()
let obj = {
  name: 'zhufeng',
  age: 12,
  3: '哈哈哈',
  0: 'zhouxiaotian',
  [sy]: 100
}
console.log(obj)
console.log(obj.hasOwnProperty('name'))
console.log(obj.hasOwnProperty(sy))

// 很多‘对象’的操作是无法拿到Symbol属性的
Object.prototype.AAA = 100; // -> 'AAA'是obj公共属性 obj.hasOwnProperty('AAA')->false 'AAA' in obj->true
for (let key in obj) {
  console.log(key) // -> 'name' 'AAA' 
  // /**
  //  * for in 遍历的时候,
  //  *  1.无法遍历Symbol的私有属性,
  //  *  2.但是可以遍历到自己扩展的公共属性「内置的公共属性不可枚举(就是无法遍历到)」
  //  *  3.优先遍历数字属性,而且按照从小到大(不会严格按照书写顺序)
  //  *  4.先遍历私有,再遍历公有的
  // */
  // let obj = {
  //   '1003': 3,
  //   '1001': 1,
  //   '1002': 2,
  // }
  // for (let key in obj) {
  //   console.log(key)
  // }
}
// 解决:能够避免遍历公共的
for (let key in obj) {
  if (!obj.hasOwnProperty(key)) break; // 已经遍历到公共的,则私有已经遍历完,结束循环
}
// 解决:只想遍历私有的,包含Symbol
// Object.keys:获取一个对象非Symbol的私有属性(结果是一个数组,数组中包含获取的属性)
// 类似的还有:Object.getOwnPropertyNames
// Object.getOwnPropertySymbols:只获取Symbol的私有属性(结果也是一个数组)
let keys = [
  ...Object.getOwnPropertyNames(obj),
  ...Object.getOwnPropertySymbols(obj)
];
keys.forEach(key => {
  // console.log(`${key}:${obj[key]}`)
  console.log(key, obj[key])
})