# 前端爱好者学习周刊:第10期

20200412

# 1.new Proxy()

使用Proxy对象可以给一个对象添加自定义行为:

const handler = {
    set: () => console.log('Added a new property!'),
    get: () => console.log('Accessed a property!')
}

const person = new Proxy({}, handler)

person.name = 'lydia' // Added a new property 
person.name // Accessed a property
1
2
3
4
5
6
7
8
9

Proxy对象语法 (opens new window):

const p = new Proxy(target, handler)
1

# isNaNNumber.isNaN

参考:

# 1).NaN

NaN即(Not-A-Number不是一个数字);

  • 获取: Number.NaN

  • js中唯一一个与自身不相等的存在:NaN == NaN// false

  • NaN!==NaN的原因:NaN只是Number上的一个静态属性;如Number('echo')会得到NaN,它只是为了说明这个值不是一个数字,一种表示方法,而非一个精准有效的值,因此NaN不能参与计算,也无法与自身比较。

  • 产生NaN的情况:

Number('echo') //NaN

parseInt('echo123') //NaN
parseInt('123echo') //123

parseFloat('时间跳跃123.1') //NaN
parseFloat('123.1时间跳跃') //123.1

1 - '听风是风' //NaN
1 * '123时间跳跃' //NaN
1 / 'echo123' //NaN

0 / 0 //NaN
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2).isNaN()

isNaNwindow上的方法

当我们向isNaN传递一个参数,它的本意是通过Number()方法尝试转换参数的类型为Number,如果转换成功返回false,否则转返回true,它只是判断这个参数能否转成数字而已,并不是判断是否严格等于NaN。不能转成数字即NaN

console.log(isNaN(null));            //false
console.log(isNaN(true));            //false
console.log(isNaN(false));           //false
console.log(isNaN(0));               //false
console.log(isNaN(undefined));       //true
console.log(isNaN("AB"));            //true
console.log(isNaN({ a: 1 }));        //true
console.log(isNaN(NaN));             //true
console.log(isNaN(123))              //false
console.log(isNaN('123时间跳跃'))     //true
1
2
3
4
5
6
7
8
9
10
console.log(Number(null));            //0
console.log(Number(true));            //1
console.log(Number(false));           //0
console.log(Number(0));               //0
console.log(Number(undefined));       //NaN
console.log(Number("AB"));            //NaN
console.log(Number({ a: 1 }));        //NaN
console.log(Number(NaN));             //NaN
console.log(Number(123))              //123
console.log(Number('123时间跳跃'))     //NaN

1
2
3
4
5
6
7
8
9
10
11

# 3).Number.isNaN()

ES6中提供了一个Number.isNaN()方法用于判断一个值是否严格等于NaN

console.log(Number.isNaN(null));            //false
console.log(Number.isNaN(true));            //false
console.log(Number.isNaN(false));           //false
console.log(Number.isNaN(0));               //false
console.log(Number.isNaN(undefined));       //false
console.log(Number.isNaN("AB"));            //false
console.log(Number.isNaN({ a: 1 }));        //false
console.log(Number.isNaN(NaN));             //true
console.log(Number.isNaN(123))              //false
console.log(Number.isNaN('123时间跳跃'))     //false
1
2
3
4
5
6
7
8
9
10

Number.isNaN()polyfill:

if (!Number.isNaN) {
  Number.isNaN = function(n) {
    return typeof n === "number" && window.isNaN( n );
  };
}
1
2
3
4
5
// 简单的实现,利用只有 NaN 不跟自己相等的特性
if (!Number.isNaN) {
  Number.isNaN = function(n) {
    return  return value !== value;
  };
}
1
2
3
4
5
6

# 3.for in和for of

  • for in可以遍历一个对象自有的、继承的、可枚举的、非Symbol的属性
  • for of可以迭代可迭代对象(包括array,Map,Set,String,arguments

# 4.error

  • 当js找不到要访问的值的引用时,抛出ReferenceErrors
  • 当值不是预期类型的时,会抛出TypeError
  • 当你编写了一个非有效的JS时,比如return写成了retunr时,会抛出语法错误SyntaxError

# 5. 从a == 1 && a == 2 && a == 3看隐式转换

【原题】-下面代码中 a 在什么情况下会打印 1 (opens new window)

出发点一:取a值时会进行get

# 1).修改getter

# (1).通过Object.defineProperty来对window对象上的a属性重新定义getter

Object.defineProperty(window, 'a', {
    get: function() {
          return this.value = this.value ? (this.value += 1) : 1;
    }
})
1
2
3
4
5

# (2).new Proxy()可以给一个对象添加自定义行为

var a1 = new Proxy({}, { 
        i: 1, 
        get() { 
            return () => this.i++ 
        } 
    }
)
1
2
3
4
5
6
7

出发点二a == 1做这个运算的时候会执行隐式转换,就会调用toString(),valueOf(),[Symbol.toPrimitive]

# 2).隐式转换toString(),valueOf(),[Symbol.toPrimitive]

var a = {
    i: 1,
    valueOf() {
        return a.i++;
    },
    toString() {
        return a.i++;
    },
    [Symbol.toPrimitive]() { // 优先级最高
        return a.i++;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
// ES6的生成器
const a3 = {
    gn: (function* () {
        yield 1;
        yield 2;
        yield 3;
    })(),
    valueOf() {
        return this.gn.next().value;
    }
};
1
2
3
4
5
6
7
8
9
10
11

# Symbol.toPrimitive

参考:toString方法和valueOf方法以及Symbol.toPrimitive方法的学习 (opens new window)

对象的Symbol.toPrimitive属性。指向一个方法。该对象被转化为原始类型的值时,会调用这个办法,返回该对象对应的原始类型值。 Symbol.toPrimitive被调用时,会接受一个字符串参数,表示当前运算的模式,一个有三种模式。

  • Number:该场合需要转成数值
  • String:该场合需要转成字符串
  • Default:该场合可以转成数值,也可以转成字符串。
// 没有 Symbol.toPrimitive 属性的对象
var obj1 = {};
console.log(+obj1);       //NaN
console.log(`${obj1}`);   //"[object Object]"
console.log(obj1 + "");   //"[object Object]"
1
2
3
4
5
// 拥有 Symbol.toPrimitive 属性的对象
let obj = {
  [Symbol.toPrimitive](hint) {
    if(hint === 'number'){
      console.log('Number场景');
      return 123;
    }
    if(hint === 'string'){
      console.log('String场景');
      return 'str';
    }
    // if(hint === 'default'){
      console.log('Default 场景');
      return 'default';
    // }
  }
}
console.log(2*obj); // Number场景 246
console.log(3+obj); // String场景 3default
console.log(obj + "");  // Default场景 default
console.log(String(obj)); //String场景 str
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21