Skip to content
本页目录

运算符

关于new运算符,需要特别说明

由于JavaScript函数有两个内部方法:[[Call]][[Construct]]

  • 当通过new运算符调用函数时,执行[[Construct]]方法,创建一个实例对象,然后将this绑定到实例上,再执行函数体,最后并返回实例。
  • 当直接调用函数的时候,执行[[Call]]方法,直接执行函数体。

由于箭头函数的内部实现并没有[[Construct]]方法,所以不能被用作构造函数,如果通过new运算符的方式调用,会报错, 具体的可以查看MDN相关内容,传送门使用new运算符

new运算符

让我们先回顾下调用new运算符时发生的事情,以const yui = new Kon('yui', 14)为例:

  1. 首先创建实例对象,将实例对象的[[prototype]]属性链接到构造函数的prototype上;
  2. 然后将构造函数的作用域赋值给该实例对象(即将this绑定到该实例);
  3. 接着执行构造函数,为该实例添加属性和方法;
  4. 最后返回该实例对象。
JavaScript
function NewFactory() {
  // 获取构造函数
  const Constructor = [].shift.call(arguments)
  // 创建实例对象,并连接原型,此处做了简写
  // const _o = {} 
  // _o.__proto__ = Constructor.prototype
  const _o = Object.create(Constructor.prototype)
  // 绑定this,执行函数体
  const ret = Constructor.apply(_o, arguments)
  // 构造函数可能有返回值
  return typeof ret === 'object' ? ret : _o
}

现在测试下NewFactory

JavaScript
function Kon(name, age) {
  this.name = name
  this.age = age
  // return {
  //   info: `樱丘高中-${name}-${age}`
  // }
}
// new运算符
const yui = new Kon('yui', 14)  // Kon {name: 'yui', age: 14}
// NewFactory
const mio = NewFactory(Kon, 'mio', 14)  // Kon {name: 'mio', age: 14}

newFactory测试结果和new运算符效果一致。

补充Object.create()

JavaScript
const create = (obj, options) => {
  // const _o = {} 
  // _o.__proto__ = obj.prototype
  const F = function () { }
  F.prototype = obj
  const _o = new F()
  // 当 obj 不为 null 时,以上代码和注释代码是等效的
  if (options) Object.defineProperties(_o, options)
  return _o
}

const yui = create(null,{
  name: {
    writable: true,
    configurable: true,
    value: 'yui'
  },
  age: {
    configurable: false,
    get: function() { return 14 },
    set: function(value) {
      console.log(`呆唯${value}`)
    }
  }
})

typeof运算符

此处使用正则表达式的肯定正序环视(?=)来提取目标字符串。

JavaScript
const typeOf = (arg) => {
  const typeStr = Object.prototype.toString.call(arg)
  const [, type] = typeStr.match(/(?=\s([a-z]+)\])/i)
  return type
  // return type.toLocaleLowerCase()
}

typeOf(123)  // 'Number'
typeOf(true) // 'Boolean'
typeOf('123') // 'String'
typeOf([])  // 'Array'
typeOf({})  // 'Object'
typeOf(null)  // 'Null'
typeOf(undefined)  // 'Undefined'
typeOf(Symbol(123))  // 'Symbol'
typeOf(() => { })  // 'Function'
// 基本类型包装类
typeOf(new Number(123))  // 'Number'

此方法与原生typeof运算符的几点不同:

JavaScript
// 基本类型的包装类,typeof返回 'object'
typeof(new Number(123))  // 'object'
// 对于null,typeof也返回 'object'
typeof(null)  // 'object'
// 对于数组类型,typeof也返回 'object'
typeof([])  // 'object'

instanceof运算符

instanceof的底层逻辑就是一直沿着原型链查找,在链中找到就返回true,没找到就返回false

JavaScript
const instanceOf = (left, right) => {
  if (right === null) {
    throw new TypeError(`'instanceOf' 右侧必须是对象`)
  }
  let proto = left.__proto__
  while (true) {
    if (proto === null) return false
    if (proto === right.prototype) return true
    proto = proto.__proto__
  }
}

instanceOf([], Array)  // true
class Kon { }
const yui = new Kon()
instanceOf(yui, Kon)  // true
instanceOf([], null)  // Uncaught TypeError: 'instanceOf' 右侧必须是对象