Decorator装饰器

定义

  1. Decorator装饰器其实是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要装饰的目标类。
  2. ES6+里的装饰器,依赖 ES5 的 Object.defineProperty方法实现(vue的双向绑定也依赖这个方法)

代码举例

下面的代码中:
testable就是一个装饰器,并对Person类增加了一个属性
readonly也是一个装饰器,它对Person的属性进行readonly操作

  1. function testable(target) {
  2. target.isTestable = 'aa'
  3. }
  4. // 对类属性进行装饰
  5. function readonly(target, name, descriptor) {
  6. descriptor.writable = false
  7. return descriptor
  8. }
  9. @testable
  10. class Person {
  11. @readonly
  12. name: 'xiao A'
  13. }
  14. console.log('xxx', Person.isTestable, 'xxx')
  15. setInterval(() => {
  16. console.log(Person.name, Person.isTestable, 1)
  17. }, 1000)
  18. setTimeout(() => {
  19. console.log('xiaob:')
  20. try {
  21. Person.name = 'xiao B'
  22. } catch (error) {
  23. console.log('xiaob:', error)
  24. }
  25. }, 5000)

注意:
装饰器只能用于类和类的方法,不能用于函数,因为存在函数提升。
如果一定要装饰函数,可以采用高阶函数的形式操作。

This详解

先说核心:JS中this永远指向属性或方法所属的对象,或者说指向调用它的对象,this是在运行时绑定的

1. 默认绑定:

这是最直接的一种方式,就是不加任何的修饰符直接调用函数

2. 隐式绑定

这种情况会发生在调用位置存在「上下文对象」的情况,如

3. 显式绑定

这种就是使用 Function.prototype 中的三个方法 call(), apply(), bind() 了。
这三个函数,都可以改变函数的 this 指向到指定的对象,
不同之处在于,call() 和 apply() 是立即执行函数,并且接受的参数的形式不同:

call(this, arg1, arg2, …)
apply(this, [arg1, arg2, …])
而 bind() 则是创建一个新的包装函数,并且返回,而不是立刻执行。

bind(this, arg1, arg2, …)
apply() 接收参数的形式,有助于函数嵌套函数的时候,把 arguments 变量传递到下一层函数中。

4. new 绑定

最后一种,则是使用 new 操作符会产生 this 的绑定。
在理解 new 操作符对 this 的影响,首先要理解 new 的原理。
在 JavaScript 中,new 操作符并不像其他面向对象的语言一样,而是一种模拟出来的机制。
在 JavaScript 中,所有的函数都可以被 new 调用,这时候这个函数一般会被称为「构造函数」,实际上并不存在所谓「构造函数」,更确切的理解应该是对于函数的「构造调用」。
使用 new 来调用函数,会自动执行下面操作:

  1. 创建一个全新的对象。
  2. 这个新对象会被执行 [[Prototype]] 连接。
  3. 这个新对象会绑定到函数调用的 this。
  4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象

Example

  1. function foo() {
  2. console.log(this.a);
  3. }
  4. var a = 0;
  5. var obj1 = {
  6. a: 2,
  7. foo,
  8. }
  9. foo() //0, 默认绑定
  10. obj1.foo(); // 2, 隐式绑定
  11. obj1.foo.call({a: 1}); // 1, 显式绑定
  12. var f = new foo();

数据类型

JavaScript 有两种方式判断两个值是否相等。

等于操作符:等于操作符由两个等号组成:==
JavaScript 是弱类型语言,这就意味着,等于操作符会为了比较两个值而进行强制类型转换。

  1. "" == "0" // false
  2. 0 == "" // true
  3. 0 == "0" // true
  4. false == "false" // false
  5. false == "0" // true
  6. false == undefined // false
  7. false == null // false
  8. null == undefined // true
  9. " \t\r\n" == 0 // true

上面的表格展示了强制类型转换,这也是使用 == 被广泛认为是不好编程习惯的主要原因, 由于它的复杂转换规则,会导致难以跟踪的问题。此外,强制类型转换也会带来性能消耗,比如一个字符串为了和一个数组进行比较,必须事先被强制转换为数字。

严格等于操作符

严格等于操作符由三个等号组成:===
不像普通的等于操作符,严格等于操作符不会进行强制类型转换。

  1. "" === "0" // false
  2. 0 === "" // false
  3. 0 === "0" // false
  4. false === "false" // false
  5. false === "0" // false
  6. false === undefined // false
  7. false === null // false
  8. null === undefined // false
  9. " \t\r\n" === 0 // false

上面的结果更加清晰并有利于代码的分析。如果两个操作数类型不同就肯定不相等也有助于性能的提升。

比较对象

虽然 == 和 === 操作符都是等于操作符,但是当其中有一个操作数为对象时,行为就不同了。

  1. {} === {}; // false
  2. new String('foo') === 'foo'; // false
  3. new Number(10) === 10; // false
  4. var foo = {};
  5. foo === foo; // true

这里等于操作符比较的不是值是否相等,而是是否属于同一个身份;也就是说,只有对象的同一个实例才被认为是相等的。 这有点像 Python 中的 is 和 C 中的指针比较。

结论

强烈推荐使用严格等于操作符。如果类型需要转换,应该在比较之前显式的转换, 而不是使用语言本身复杂的强制转换规则。

时间处理

计算机世界里的日期都是从1970年1月1日开始计算,时间戳是指1970年1月1日至今的毫秒数
关于时间/日期的处理,JS中有个一使用频率很高的库:moment
npm install moment —save即可使用。
官方文档:https://momentjs.com/
这个库我就不多介绍了,也有中文文档,有兴趣和强需求的同学可以看看。

接下来将介绍JS中原生的日期处理方法:Date
Date是JavaScript提供的日期和时间的操作接口。它表示的时间范围是:1970年1月1日00:00:00前后各1亿天(单位毫秒)。

我们经常会 new Date()打印当前时间,一般会得到如下结果
Wed Feb 01 2017 08:00:00 GMT+0800 (CST)
开始解读这个这个字符串,分别是周3,2月,1日,2017年,8点,至于GMT CST

  1. GMT(Greenwich Mean Time)代表格林尼治标准时间
  2. CST同时代表如下4个不同的时区:
  3. Central Standard Time (USA) UT-6:00
  4. Central Standard Time (Australia) UT+9:30
  5. China Standard Time UT+8:00
  6. Cuba Standard Time UT-4:00

下面是常用的获取当前时间的方法,需要的话可以封装一下用来返回不同风格的日期

  1. var date = new Date();
  2. date.getTime();//获取当前时间戳
  3. //注:getMonth返回的是(0-11)需要加1
  4. console.log(date.getFullYear() + '年' + (date.getMonth()+1) + '月' + date.getDate() + '日');
  5. console.log(date.getHours() + '时' + date.getMinutes() + '分' + date.getSeconds() + '秒');

如果想把某个时间戳转化成日期

  1. var date = new Date(1488094640437);
  2. //同时支持不同形式的入参
  3. // new Date('2017-02-01')
  4. // new Date(year, month, day, hours, minutes, seconds, milliseconds)
  5. // 然后可以获取这个时间戳对应的日期
  6. console.log(date.getFullYear() + '年' + (date.getMonth()+1) + '月' + date.getDate() + '日');
  7. console.log(date.getHours() + '时' + date.getMinutes() + '分' + date.getSeconds() + '秒');