一、typeof

《JavaScript权威指南》中对 typeof 的介绍:typeof 是一元操作符,放在其单个操作数的前面,操作数可以是任意类型。返回值为表示操作数类型的一个字符串。

typeof返回的数据类型有6种,分别是:

1、object,对象类型;

tips:数组使用typeof 会返回object,null 被认为是一个空的对象引用,typeof(null)为object。

  

2、undefined,未定义类型;

 

3、string,字符串类型;

 

4、number,数字类型;

  

5、boolean,布尔类型;

 

6、function,函数类型。

 综上可以看出,对于数组、对象来说,其关系错综复杂,使用 typeof 都会统一返回 “object” 字符串

二、Object.prototype.toString.call()

toString() 方法返回一个表示该对象的字符串。

每个对象都有一个 toString() 方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString() 方法被每个 Object 对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中 type 是对象的类型。

ES5 规范中当 toString 方法被调用的时候,下面的步骤会被执行:

1. 如果 this 值是 undefined,就返回 [object Undefined]

2. 如果 this 的值是 null,就返回 [object Null]

3. 让 O 成为 ToObject(this) 的结果

4. 让 class 成为 O 的内部属性 [[Class]] 的值

5. 最后返回由 "[object " 和 class 和 "]" 三个部分组成的字符串

下面列举使用Object.prototype.toString.call()的几种情况:(标黄较为常用)

1.[object Number]

为什么需要call?
由于Object.prototype.toString()本身允许被修改,像Array、Boolean、Number的toString就被重写过,所以需要调用Object.prototype.toString.call(arg)来判断arg的类型,call将arg的上下文指向Object,所以arg执行了Object的toString方法。至于call,就是改变对象的this指向,当一个对象想调用另一个对象的方法,可以通过call或者apply改变其this指向,将其this指向拥有此方法的对象,就可以调用该方法了。

此处引用Object.prototype.toString.call()原理_年轻的老六的博客-CSDN博客_object.prototype.tostring.call

2.[object String]

3.[object Boolean] 

4.[object Undefined] 

5.[object Null] 

6.[object Object] 

7.[object Array] 

8.[object Date] 

9.[object Error] 

10.[object RegExp] 

11.[object Function] 

12.[object Math] 

13.[object JSON] 

三、.call()和.apply()的区别

此处参考博客:call()和apply()方法的区别和详细用法_想你有幸的博客-CSDN博客_call方法和apply的区别是什么

每个函数都包含两个非继承而来的方法:call()方法和apply()方法。callapply可以用来重新定义函数的执行环境,也就是this的指向;callapply都是为了改变某个函数运行时的context,即上下文而存在的,换句话说,就是为了改变函数体内部this的指向。

  • 相同点

call()apply()方法的相同点就是这两个方法的作用是一样的。都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域

一般来说,this总是指向调用某个方法的对象,但是使用call()和apply()方法时,就会改变this的指向,看个例子:

function add(a, b) {
    return a + b;
}
 
function sub(a, b) {
    return a - b;
}
 
console.log(add.call(sub, 2, 1));//3

为什么add.call(sub, 2, 1)的执行结果是3呢,因为call()方法改变了this的指向,使得sub可以调用add的方法,也就是用sub去执行add中的内容,再来看一个例子:

function People(name, age) {
    this.name = name;
    this.age = age;
}
 
function Student(name, age, grade) {
    People.call(this, name, age);
    this.grade = grade;
}
 
var student = new Student('小明', 21, '大三');
console.log(student.name + student.age + student.grade);//小明21大三

在这个例子中,我们并没有给Student的name和age赋值,但是存在这两个属性的值,这还是要归功于call()方法,它可以改变this的指向。
在这个例子里,People.call(this, name, age);中的this代表的是Student,这也就是之前说的,使得Student可以调用People中的方法,因为People中有this.name = name;等语句,这样就将name和age属性创建到了Student中。

总结一句话就是call()可以让括号里的对象来继承括号外函数的属性。

  • 不同点

call()apply()的不同点就是接收参数的方式不同

  • apply()方法接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
  • call()方法不一定接受两个参数,第一个参数也是函数运行的作用域(this),但是传递给函数的参数必须列举出来。

即call可以传入多个参数;apply只能传入两个参数,所以其第二个参数往往是作为数组形式传入。

PS:apply()可以将一个数组默认的转换为一个参数列表([param1,param2,param3]转换为param1,param2,param3)。

例:

var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
arr1.push.apply(arr1, arr2);
console.log(arr1);//[ 1, 2, 3, 4, 5, 6 ]

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐