切换主题
运算符
关于new
运算符,需要特别说明
由于
JavaScript
函数有两个内部方法:[[Call]]
和[[Construct]]
:
- 当通过
new
运算符调用函数时,执行[[Construct]]
方法,创建一个实例对象,然后将this
绑定到实例上,再执行函数体,最后并返回实例。- 当直接调用函数的时候,执行
[[Call]]
方法,直接执行函数体。
由于箭头函数的内部实现并没有[[Construct]]
方法,所以不能被用作构造函数,如果通过new
运算符的方式调用,会报错, 具体的可以查看MDN相关内容,传送门使用new
运算符。
new
运算符
让我们先回顾下调用new
运算符时发生的事情,以const yui = new Kon('yui', 14)
为例:
- 首先创建实例对象,将实例对象的
[[prototype]]
属性链接到构造函数的prototype
上;- 然后将构造函数的作用域赋值给该实例对象(即将
this
绑定到该实例);- 接着执行构造函数,为该实例添加属性和方法;
- 最后返回该实例对象。
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' 右侧必须是对象