# 1. new 函数实现
原理:
- 创建一个新的空对象
- 使新对象的__proto__原型 指向 构造函数的的prototype原型
- 绑定构造函数的this
- 如果函数没有对象类型,那么new表达式会直接返回这个对象
function _new (obj, args) {
if (typeof obj !== 'function')
throw new TypeError(obj + "is not a function");
//es6中new.target 指向这个对象。
_new.target = obj;
//模拟 Object.create
// function F () {};
// F.prototype = obj.prototype;
// F.prototype.constructor = F;
// let target = new F();
let target = Object.create(obj.prototype);
const result = obj.call(target, ...args);
let isObject = typeof result === 'object' && result !== null;
let isFunction = typeof result === 'function';
if (isObject || isFunction)
return result;
return target;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Test:
function Person () {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
}
const per = _new(Person, "myNew");
console.log(per);
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 2. new.target 使用及作用(ES6):
限制类的调用方法,判断new.target是不是未定义
写出只能被继承使用的类
将上述Person稍作修改,添加_new.target 限制
function Person () {
this.name = name;
if (_new.target == Person) {
throw _new(Error,['本类不能实例化'])
}
}
Person.prototype.getName = function () {
return this.name;
}
const per1 = _new(Person, "myNew"); //直接抛出错误,不允许实例化。
console.log(per);
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
接下来创建Student 继承 Person
// const per = _new(Person,["myNew"]);//直接抛出错误,不允许实例化。
// console.log(per);
function Student (){
Person.call(this,...arguments);
if (!(this instanceof Student)) {
console.warn('should be called with the new !')
}
}
function JiSheng(son,parent) {
let clone = Object.create(parent.prototype);//创建对象
son.prototype = clone; //指定对象
clone.constructor = son; //增强对象
}
JiSheng(Student, Person);
const st1 = _new(Student, ["aa"]); // 可以被实例化,因为当前_new.target === Student;不会触发Person的错误
console.dir(st1);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
补充:
- 在构造函数里使用
(!(this instanceof Student))
判断当前调用Student 是否是通过new调用,禁止直接调用。