# js-进阶 call的使用及模拟实现
用指定的对象来替换修改函数内部的this,并执行这个函数。
函数.call(newObj, 参数1, 参数2, ...参数n)
参数:
newObj : 用newObj替换函数中的this
参数1...参数n : 函数自身需要的参数。
1
2
3
4
2
3
4
# 示例
- (1)不带参数的情况
function f(){
console.log(this.name)
}
var obj1 = {name:"a"}
var obj2 = {name:"b"}
f.call(obj1); // a
f.call(obj2); // b
1
2
3
4
5
6
7
2
3
4
5
6
7
执行函数f,并使用obj1,obj2来代替其中的this。
- (2)带参数的情况
function f(a,b){
console.info(this.name, a,b)
}
var obj1 = {name:"a"}
var obj2 = {name:"b"}
f.call(obj1,1,2); // a 1 2
f.call(obj2,3,4); // b 3 4
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# call从哪里来
function f(){
console.log(this.name)
}
var obj1 = {name:"a"}
f.call(obj1)
1
2
3
4
5
2
3
4
5
f是一个函数,也是一个对象,它的构造器是Function,可以通过f.__proto__ === Function.prototype验证这一点。由于f也是属性的集合,那么call是不是它的属性呢?
var f = function(){}
f.hasOwnProperty("call") // false
1
2
2
证明call不是它的自有属性。但按原型链的规则,接下来它会去
__proto__属性中去继续找call:
var f = function(){}
f.__proto__.hasOwnProperty("call") //true
1
2
2
所以函数f可以使用call属性。
进一步说,
call属性是f.__proto__的自有属性,就相当于是Function.prototype的自有属性。
Function.prototype.hasOwnProperty("call") //true
1
Function
只要是function,就都可以使用call函数(当然了,不涉及箭头函数)。
# call的应用场景
它其实可用作代码的一个比较好巧妙的设计方式:一个独立的函数,并不属于任何对象,但是,它却可以临时借给其它对象用一下,在使用的过程中,这个
函数内部的this就是这个对象。
# Object.prototype.totString.call
一个比较经典的应用是判断变量的数据类型。
console.log(Object.prototype.toString.call("1"))
// [object String]
console.log(Object.prototype.toString.call(1))
// [object Number]
console.log(Object.prototype.toString.call(false))
// [object Boolean]
console.log(Object.prototype.toString.call([]))
// [object Array]
console.log(Object.prototype.toString.call({}))
// [object Object]
console.log(Object.prototype.toString.call(function(){}))
// [object Function]
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- (1)Object是一个对象,它有一个属性是prototype。这个属性的值又是一个对象,在Object.prototype这个对象中有一个属性叫toString,特殊地,它是一个方法。由于它是一个function,则它可以使用call。
- (2)从格式上来看:Object.prototype.toString这个函数借给对象f用一下。会调用Object.prototype.toString函数 ,同时,用f去代替函数内部的this。
- (3)Object.prototype.toString的返回值是字符串,并不是数组(只是看起来前后有[ ] )。它的返回结果是固定格式的:
[object 当前对象的构造器的名字]。
# 把类数组转成数组
类数组不是真正的数组,它只是看起来像数组。如果你的网页中有很多个li标签,则通过
var list = document.getElementsByTagName('li'),你就会得到一个类数组
var arr = Array.prototype.slice.call(lis)
1
如果用eS6的
Array.from()会简单的多