js函数涉及到作用域时,函数定义时作用域以及很多东西无法确定,只有调用它时才能确定
call
作用是改变运行时上下文(作用域,即this),但是很多博客解释的非常复杂,这个解释比较清楚,直接上代码,上下两段代码等价。
function add(c,d) {
return this.a + this.b + c + d;
}
const obj = {a: 1, b: 2};
console.log(add.call(obj, 3, 4)); // 10
// 等价于
const o = {
a: 1,
b: 2,
add: function(c,d) {
return this.a + this.b + c + d;
}
};
console.log(o.add(3,4)) // 10
// 感觉相当于把add这个方法拉到obj这个作用域里来
apply
apply和call区别在于apply第二个参数是Array,而call是将一个个传入,将第一段代码改写可得
function add(c,d) {
return this.a + this.b + c + d;
}
const obj = {a: 1, b: 2};
console.log(add.apply(obj, [3, 4])); // 10
// 或者
const e = [3, 4];
console.log(add.apply(obj, e)); // 10
bind
bind 的作用和call很像,也会将它的第一个参数变成函数运行时的作用域对象,后边的参数作为函数的参数传入,但是它的独特型在于它会新建一个函数,上述的作用发生在这个新的函数被调用时,而且,当这个新函数作为构造函数时,它当时绑定的this对象(也就是刚刚的第一个参数)会失效,不过后边的参数依然有效。
function foo(c,d) {
this.b = 100;
console.log(this.a);
console.log(this.b);
console.log(c)
console.log(d)
}
var func = foo.bind({a: 1},'no.1')
func('no.2')
// 1
// 100
// no.1
// no.2
// 即使call也不能改变this
func.call({a: 2},'no3')
// 1
// 100
// no.1
// no.3
// 当 bind 返回的函数作为构造函数的时候,
// bind 时指定的 this 值会失效,但传入的参数依然生效。
// 所以使用func为构造函数时,this不会指向{a: 1}对象,this.a的值为undefined
new func('no.4')
类数组对象转数组
类数组对象虽然可以访问到某个键值,但是却不能进行遍历
es5和es6都有各自的方法实现:
const list = document.getElementsByTagName('li')
console.log(Array.isArray(list)) // 不是数组
console.log(list[2].innerHTML) // 可以输出其下某个元素的值
console.log(list.forEach); // 无法进行遍历
// ES5方法将类数组对象数组化
var es5 = Array.prototype.slice.call(list)
// 或者使用 var es5 = [].slice.call(list)
console.log(es5)
// ES6方法将类数组对象数组化
var es6 = Array.from(list)
console.log(es6)