看完这篇文章,你将了解:
- splice 方法不仅能删除元素,还能添加元素
- Object.prototype.valueOf 方法
- forEach 的 this 与遍历机制
- 事件的冒泡属性
- 七种类型在 typeof 运算符下的返回值
一. Array.prototype.splice
有一道题目,问我 Array 方法中哪个不能添加元素。排查之后只剩 pop 和 splice。
一查 MDN,发现 splice 不仅可以删除元素,还可以替换元素。而当删除元素为 0 时,相当于添加元素
语法是
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
- start: 表示修改开始位置,可以为负,负数表示倒数
- deleteCount: 可选,表示删除元素个数,可以省略,省略表示后面全删
- item1, ...: 可选,表示替换元素
比如:
从第 2 位开始删除 0 个元素,插入“drum”
var myFish = ["angel", "clown", "mandarin", "sturgeon"]; var removed = myFish.splice(2, 0, "drum"); // 运算后的 myFish: ["angel", "clown", "drum", "mandarin", "sturgeon"] // 被删除的元素: [], 没有元素被删除
从倒数第 2 位开始删除 1 个元素
var myFish = ['angel', 'clown', 'mandarin', 'sturgeon']; var removed = myFish.splice(-2, 1); // 运算后的 myFish: ["angel", "clown", "sturgeon"] // 被删除的元素: ["mandarin"]
splice(a, b, c) 读作:从第 a 位起删除 b 个元素,插入 c (a 从 0 计数)
二. Object.prototype.valueOf
先看一段代码
let i = 1 + {valueOf: function() { return 9 }}
// i === 10
MDN 是这么说的:
JavaScript calls the
valueOf
method to convert an object to a primitive value. You rarely need to invoke thevalueOf
method yourself; JavaScript automatically invokes it when encountering an object where a primitive value is expected.JS 调用 valueOf 方法将一个对象转换成原始类型。
每个对象都自带 valueOf 函数因此很少需要你自己动手实现
当一个对象期望为原始类型值的时候,就会调用 valueOf
所以说,当下面语句
1 + obj
+obj
出现的时候,obj 需要将自己转换成数字类型,这时会调用自身的 valueOf 方法转换成数字。
而 valueOf 方法可以自己覆盖,所以上面的代码返回 10
三. forEach 的 this 与遍历机制
先看一段令人困惑的代码
new Array(5).forEach(() => console.log(this))
// undefined
在我的设想里,新建长度为 5 的数组后,应该遍历输出 5 次函数环境下的 this。
根据 MDN,this 的值应该是 window
arr.forEach(callback, thisArg)
- callback 依次传入三个参数(值,下标,数组)
- thisArg 是独立于 callback 的参数,用于传入 callback 成为其 this 值
...
如果
thisArg
参数有值,则每次callback
函数被调用的时候,this
都会指向thisArg
参数上的这个对象。如果省略了thisArg
参数,`或者赋值为 null
或undefined
,则 this 指向全局对象
上面的代码,只传入第一参数 callback,省略第二参数 thisArg。因此 this 应为 window
事实上,代码却没有输出 5 个 window。
为了定位问题,这里做几个试验
[1, 2, 3, 4, 5].forEach(() => console.log(this))
// window * 5
// 说明非构造函数生成的数组是正常的
var arr = new Array(5)
arr.forEach(() => console.log(this))
// undefined
// 说明跟数组对象是否为匿名对象无关
new Array(1, 2, 3, 4, 5).forEach(() => console.log(this))
// window * 5
// 找到了,说明跟构造函数成员是否为空有关
经过试验,终于确定了问题所在。原来并不是 this 的问题,单纯只是 new Array(5) 调用的 forEach 里,回调函数一次也没有执行!
查看 stackoverflow 上的相关问答,终于搞懂了原因
原来,forEach 遍历是按成员遍历不是按长度遍历。
当我们 new Array(5) 的时候,返回 [empty, empty, empty, empty, empty]。empty 并不是成员值,因此不会遍历。比如:
var arr = new Array(5)
arr.forEach(function(elem, index, array) {
console.log(index);
});
//prints nothing
arr[3] = 'hey'
arr.forEach(function(elem, index, array) {
console.log(index);
});
//prints only 'hey' even though arr.length === 5
注意:没有值并不等于 undefined,比如:
arr = [undefined, undefined, undefined, undefined, undefined]
arr.forEach(() => console.log(this))
// 5 * window
下面 forEach 的一个简易实现,可以彻底说明问题
Array.prototype.my_for_each = function(callback, thisArg) {
for (var i = 0; i < this.length; i++) {
if (i in this) {
callback.call(thisArg, this[i], i, this);
}
}
};
// new Array(2)
// {length: 2}
// new Array(1, 2)
// {"0": 1, "1": 2, length: 2}
// [undefined, undefined]
// {"0": undefined, "1": undefined, length: 2}
// var arr = [1]; arr[3] = 1
// {"0": 1, "3": 1, length: 4}
重复一遍,forEach 是按成员遍历,不是按长度遍历
四. 事件的冒泡属性
冒泡,就是一个元素上的事件触发后会在父元素上也触发
不是所有的事件都像 click 一样,点了一个元素后,所有父元素的点击事件也会触发。比如 img 的 onload 事件,并不会冒泡到父元素
怎么知道一个事件是否冒泡?所有 event 都有一个 event.bubbles 属性,可以知道它是否冒泡
一般而言,以下三种事件不冒泡
UI事件
- load
- unload
- scroll
- resize
焦点事件
- blur
- focus
鼠标事件
- mouseleave
- mouseenter
五. JS 七种类型的 typeof 返回值
JS 有 七种类型:
Null, undefined, Number, String, Boolean, Symbol, Object
分别用 typeof 调用它们
typeof null //"object"
typeof undefined //"undefined"
typeof Number() //"number"
typeof String() //"string"
typeof Boolean() //"boolean"
typeof Symbol() //"symbol"
typeof Object() //"object"
typeof Function() //"function"
可以看到,大部分情况返回值按前面的记就行。只有两个例外:
- typeof null 值为 "object"
- typeof Function() 值为 "function"
六. 细节
- deferral 和 promise 的关系:都是异步函数,前者是 jquery 版的,后者是 es6 版的
- 原生 js 中,获取父元素的语句是:xx.parentNode。注意 parentNode 不是方法
- 十六进制转十进制:parseInt('0xA')
金句
- splice 不仅可以删除元素,还可以替换元素,添加元素
- splice(a, b, c) 读作:从第 a 位起删除 b 个元素,插入 c
- 对象转换原始类型时会调用 valueOf
- forEach 遍历是按成员遍历不是按长度遍历
- typeof 的返回值有两个例外,null 和 Function
暂无评论