手写new-instanceof-Object.create

一、new

new运算符原理:

  1. 创建一个空对象,作为将要返回的实例对象
  2. 将该空对象的原型,指向构造函数的prototype
  3. 将该空对象赋值给函数内部的this
  4. 开始执行构造函数内部的代码
  5. 返回this:
    • 手动返回数值,会被忽略
    • 手动返回对象,则忽略this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* rewrite new
* https://tc39.es/ecma262/#sec-new-operator
*/

function _new () {
var constructor = [].shift.call(arguments)

// 第一种方式
// var _this = {}
// _this.__proto__ = constructor.prototype

// 第二种方式
// var _this = Object.setPrototypeOf({}, constructor.prototype)

// 第三种方式
var _this = Object.create(constructor.prototype)

var res = constructor.apply(_this, arguments)
return typeof res === 'object' && res !== null ? res : _this
}

二、instanceof

instanceof原理:依次查找自身原型链上的原型,看是否有匹配上的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* rewrite instanceof
* https://tc39.es/ecma262/#sec-instanceofoperator
*/

function _instanceof (target, type) {
if (typeof target !== 'object' || target === null)
return false

type = type.prototype

// 第一种方式
// __proto__ 是私有属性,最好不要使用
// target = target.__proto__

// 第二种方式
target = Object.getPrototypeOf(target)

while (true) {
if (target === null)
return false

if (target === type)
return true

// target = target.__proto__
target = Object.getPrototypeOf(target)
}
}

三、Object.create

Object.create:有两个参数,第一个参数为原型对象,第二参数为属性描述对象

1
2
3
4
5
6
// Example: 
Object.create({a: 1}, {
b: {
value: 2
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* rewrite Object.create
* https://tc39.es/ecma262/#sec-object.create
*/

Object._create = function (target) {
if (typeof target !== 'object')
throw new TypeError("Object prototype may only be an Object or null.")

function F () { }
F.prototype = target
var _this = new F()
if (arguments[1])
Object.defineProperties(_this, arguments[1])
return _this
}