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])
})