JS容易出现误区的操作符

类型判断

typeof

typeof操作符返回一个字符串,表示未经计算的操作数的类型。

  • typeof运算符,判断数据类型,对于基本类型,返回基本类型,对于引用类型的,不管哪一种引用类型,都返回'object'

  • typeof 除了null 返回'object',和函数返回'function',其他都能正确返回,凡是引用类型返回都是'object'

typeofnew一个构造函数生成内容的判断需要特别注意

var str = new String('String');
var num = new Number(100);

typeof str; // 返回 'object'
typeof num; // 返回 'object'

var func = new Function();

typeof func; // 返回 'function'

因此,通过typeof判断基本数据类型,也会返回不一样的结果,需要特别注意,在不确定是否是基本数据类型的场景下慎用,不过大部分场景中很少存在通过构造函数生成基本数据类型,可以使用typeof判断。

instanceof

instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。通常用来判断实例是否属于一个父类型

instanceof如何实现这样的功能,语言规范里面有详细的介绍,这里截取部分:

function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
  var O = R.prototype;// 取 R 的显示原型对象
  L = L.__proto__;// 取 L 的隐式原型对象
  while (true) {
    if (L === null)
        return false;
    if (O === L)// 这里重点:当 O 严格等于 L 时,返回 true 
        return true;
    L = L.__proto__;
  }
}

instanceof 也可以用来判断一些内置对象类型,比如function instanceof Function, reg instanceof RegExp

const reg = new RegExp(/e/i);
reg instanceof RegExg; // true

Object.prototype.toString()

toString也可以做为类型判断, 返回一个类似 [Object Type]的字符串,和typeof不一样的地方在于能判断nullDateMath等内置对象。但是对于new一个构造函数,和typeof判定是一样的。

var toString = Object.prototype.toString;

toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]

//Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]

对象上指定属性判断

in

如果指定的属性在指定的对象或其原型链中,则in 运算符返回true。

重点是需要注意的是原型链存在指定的属性,也会返回true,所以in一般用来判断纯粹的对象。

Object.prototype.hasOwnProperty()

当有这种需求时,只能使用Object.prototype.hasOwnProperty()来判断,这是一个比较蛋疼的方式。

let hasOwnProperty = Object.prototype.hasOwnProperty
if (hasOwnProperty.call(obj, "foo")) {
  console.log("has property foo")
}

Object.hasOwn()

因此,在ES2022版本,新增了一个API,Object.hasOwn(),用来解决判断对象上是否有指定属性,不会像原型链查找

let object = { foo: false }
Object.hasOwn(object, "foo") // true

let object2 = Object.create({ foo: true })
Object.hasOwn(object2, "foo") // false

function Person() {
}
Person.prototype.name = 'nick';
let person = new Person();

console.log('name' in person); // true
console.log(Object.prototype.hasOwnProperty(person, 'name')); // false
console.log(Object.hasOwn(person, 'name')); // false

但是通过class生成类,Object.hasOwn判定为true

class Person {
  constructor() {
    this.name = 'Nike';
  }
}

let person = new Person();
console.log('name' in person); // true
console.log(Object.prototype.hasOwnProperty(person, 'name')); // false
console.log(Object.hasOwn(person, 'name')); // true

由规范得到,instanceof将表达式1的__proto__与表达式2的prototype进行严格相等===比较:

如果相等返回true;如果不相等,则继续循环获取前面表达式的__proto__,直到 Object.__proto__===null为止返回false。

console.log(Object instanceof Object);//true 
console.log(Function instanceof Function);//true 
console.log(Number instanceof Number);//false 
console.log(String instanceof String);//false 
console.log(Function instanceof Object);//true 
console.log(Foo instanceof Function);//true 
console.log(Foo instanceof Foo);//false

delete

delete用于删除某个对象的属性,如果没有指向这个属性的引用,那它最终会被释放。

使用注意事项:

  • 如果你试图删除的属性不存在,那么delete将不会起任何作用,但仍会返回true

  • 如果删除属性的该对象原型链上有同名属性,delete只会删除自身属性,删除之后,对象会使用原型链上的属性。(也就是说,delete操作只会在自身的属性上起作用)

  • 任何用letconst声明的属性不能够从它被声明的作用域中删除

  • 使用var声明的属性不能从全局作用域中或者函数作用域中删除

  • 不可设置的属性不能被删除

delete删除数组对象

delete只能删除指定数组元素的对象,数组的大小不改变,删除后位置空余,显示undefined,或者其他填充值。

数组方法array.splice指定删除数组元素对象,数组大小发生变化。

Last updated