温故知新:Javascript 杂记
目录
温故而知新,复习后才发现很多基础掌握得不牢固。
数据类型 #
typeof
检查输入参数机器码后三位,000
代表object
类型,而null
恰好用全 0 表示。
typeof null; // object
typeof
对于未实现[[Call]]
方法的引用类型返回object
,已实现该方法的则返回function
。
typeof Array; // function
- 简单类型和作为
object
的复杂类型:
typeof "hello"; // string
typeof new String("hello"); // object
instanceof
判断实例时向上追踪原型链。
[] instanceof Array
[] instanceof Object
- 比
typeof
更准确的类型判断:
Object.prototype.toString.call([]); // Array
- 逻辑运算符与非布尔类型混用:
5 || 0; // 5
0 || "a"; // 'a'
5 && 0; // 0
- 拆箱时调用
toPrimitive()
方法:- 如果是原始类型值则直接返回;
- 否则调用
.valueOf()
,如果返回值是原始类型值则返回; - 否则调用
.toString()
,返回得到的string
。
[].valueOf() // []
[].toString() // ''
{}.valueOf() // {}
{}.toString() // [object Object]
[] + [] // ''
[] + {} // [object Object]
- 部分浏览器中将
{}
视作空代码块:
{
}
+[]; // 0
深浅拷贝 #
浅拷贝 #
- 遍历赋值
for (var i in origin) {
clone[i] = origin[i];
}
Object.create
,实际会拷贝到clone
的_proto_
上:
clone = Object.create(origin);
深拷贝 #
- 借助 JSON:
clone = JSON.parse(JSON.stringify(origin));
Object.assign
,与空对象合并:
clone = Object.assign({}, origin);
编码 #
escape
不会对字母、数字以及*@-_+./
进行编码,对其他所有字符均进行编码,目前已废弃。encodeURI
将输入参数视作完整的 URI,不会对字母、数字以及,/?:@&=+$#
进行编码,对其他所有字符均进行编码。encodeURIComponent
将输入参数视作 URI 的一部分,不会对字母、数字以及-_.!~*'()
进行编码,对其他所有字符均进行编码。
函数与作用域 #
- 函数与变量的声明会被提前到所在作用域最前面。变量赋值不会被提前。
- 闭包:
function foo() {
var a = 2;
function bar() {
console.log(a);
}
return bar;
}
var baz = foo();
baz(); // 2
- 一个经典例子,
timer
访问到的i
是循环结束后的全局作用域中的i
:
for (var i = 1; i <= 5; ++i) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
} // 6 6 6 6 6
解决方案:
- 用 IIFE 创建作用域
for (var i = 1; i <= 5; ++i) {
(function (j) {
setTimeout(function timer() {
console.log(j);
}, j * 1000);
})(i);
} // 1 2 3 4 5
- 借助
let
的特性
for (let i = 1; i <= 5; ++i) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
} // 1 2 3 4 5
- 类数组转为
Array
:
arr = Array.prototype.slice.apply(args);
实际上,调用 apply
、call
、bind
等方法均会对 this
进行显式绑定。
this
的默认绑定:内部函数(或者其他类似的找不到this
指向的情况)中的this
指向window
(严格模式下指向undefined
):
var a = {
b: 1,
getB: function () {
function c() {
console.log(this.b); // undefined
}
c(); // window.c()
console.log(this.b); // 1(隐式绑定)
},
};
a.getB();
同理,回调函数也常常会丢失 this
。
new
调用的所谓 “构造函数” 实际上是对新创建的对象进行初始化的一种“构造调用”,步骤如下:- 创建新对象;
- 执行
[[Prototype]]
连接; - 绑定
this
,即所谓的new
绑定; - 如果调用的函数没有返回对象,则返回该新对象
- 优先级:
new
绑定 > 显式绑定 > 隐式绑定 > 默认绑定 - 箭头函数自动继承外层作用域的
this
,且无法修改。
其他 #
sort
默认将元素转为字符串后升序排序。
var arr = [2, 13, 3, 11, 5, 7];
arr.sort(); // [11,13,2,3,5,7]