Decorator装饰器
定义
- Decorator装饰器其实是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要装饰的目标类。
- ES6+里的装饰器,依赖 ES5 的 Object.defineProperty方法实现(vue的双向绑定也依赖这个方法)
代码举例
下面的代码中:
testable就是一个装饰器,并对Person类增加了一个属性
readonly也是一个装饰器,它对Person的属性进行readonly操作
function testable(target) {
target.isTestable = 'aa'
}
// 对类属性进行装饰
function readonly(target, name, descriptor) {
descriptor.writable = false
return descriptor
}
@testable
class Person {
@readonly
name: 'xiao A'
}
console.log('xxx', Person.isTestable, 'xxx')
setInterval(() => {
console.log(Person.name, Person.isTestable, 1)
}, 1000)
setTimeout(() => {
console.log('xiaob:')
try {
Person.name = 'xiao B'
} catch (error) {
console.log('xiaob:', error)
}
}, 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 来调用函数,会自动执行下面操作:
- 创建一个全新的对象。
- 这个新对象会被执行 [[Prototype]] 连接。
- 这个新对象会绑定到函数调用的 this。
- 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象
Example
function foo() {
console.log(this.a);
}
var a = 0;
var obj1 = {
a: 2,
foo,
}
foo() //0, 默认绑定
obj1.foo(); // 2, 隐式绑定
obj1.foo.call({a: 1}); // 1, 显式绑定
var f = new foo();
数据类型
JavaScript 有两种方式判断两个值是否相等。
等于操作符:等于操作符由两个等号组成:==
JavaScript 是弱类型语言,这就意味着,等于操作符会为了比较两个值而进行强制类型转换。
"" == "0" // false
0 == "" // true
0 == "0" // true
false == "false" // false
false == "0" // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true
上面的表格展示了强制类型转换,这也是使用 == 被广泛认为是不好编程习惯的主要原因, 由于它的复杂转换规则,会导致难以跟踪的问题。此外,强制类型转换也会带来性能消耗,比如一个字符串为了和一个数组进行比较,必须事先被强制转换为数字。
严格等于操作符
严格等于操作符由三个等号组成:===
不像普通的等于操作符,严格等于操作符不会进行强制类型转换。
"" === "0" // false
0 === "" // false
0 === "0" // false
false === "false" // false
false === "0" // false
false === undefined // false
false === null // false
null === undefined // false
" \t\r\n" === 0 // false
上面的结果更加清晰并有利于代码的分析。如果两个操作数类型不同就肯定不相等也有助于性能的提升。
比较对象
虽然 == 和 === 操作符都是等于操作符,但是当其中有一个操作数为对象时,行为就不同了。
{} === {}; // false
new String('foo') === 'foo'; // false
new Number(10) === 10; // false
var foo = {};
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
GMT(Greenwich Mean Time)代表格林尼治标准时间
CST同时代表如下4个不同的时区:
Central Standard Time (USA) UT-6:00
Central Standard Time (Australia) UT+9:30
China Standard Time UT+8:00
Cuba Standard Time UT-4:00
下面是常用的获取当前时间的方法,需要的话可以封装一下用来返回不同风格的日期
var date = new Date();
date.getTime();//获取当前时间戳
//注:getMonth返回的是(0-11)需要加1
console.log(date.getFullYear() + '年' + (date.getMonth()+1) + '月' + date.getDate() + '日');
console.log(date.getHours() + '时' + date.getMinutes() + '分' + date.getSeconds() + '秒');
如果想把某个时间戳转化成日期
var date = new Date(1488094640437);
//同时支持不同形式的入参
// new Date('2017-02-01')
// new Date(year, month, day, hours, minutes, seconds, milliseconds)
// 然后可以获取这个时间戳对应的日期
console.log(date.getFullYear() + '年' + (date.getMonth()+1) + '月' + date.getDate() + '日');
console.log(date.getHours() + '时' + date.getMinutes() + '分' + date.getSeconds() + '秒');