概述
new操作符 作为经典面向对象语言的一大特征,其在 JS 中也有相应的实现
在 java 中,new 是通过调用类的构造器来返回这个类的 实例;而在 JS 中,构造器的概念由 prototype对象 来抽象代表
——在 JavaScript 中, new操作符 用于创建一个给定构造函数的实例对象的例子
eg:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function () {
console.log(this.name)
}
const person1 = new Person('Tom', 20)
console.log(person1) // Person {name: 'Tom', age: 20}
person1.sayName() // 'Tom'构造函数带基本类型返回值
eg:
function Test(name) {
this.name = name
return 1
}
const t = new Test('xxx')
console.log(t.name) // 'xxx'构造函数中返回一个原始值,然而这个返回值并没有作用
构造函数带引用类型返回值
eg:
function Test(name) {
this.name = name
console.log(this) // Test { name: 'xxx' }
return { age: 26 }
}
const t = new Test('xxx')
console.log(t) // { age: 26 }
console.log(t.name) // 'undefined'构造函数如果返回值为一个对象,那么这个返回值会被正常使用
实现流程
调用 new 的流程如下:
- 创建一个新的空对象
- 新对象的原型 (prototype) 设置为构造函数的原型对象
- 将构造函数的
this设置为创建的新的对象 - 判断构造函数的返回值类型,如果为基本类型,则返回创建的对象,如果为引用类型,则返回引用类型的对象
其中涉及到的知识点:
如何将新对象的原型对象设置为构造函数的原型对象
第二步:如何将新对象的原型对象设置为构造函数的原型对象
想当然的使用:obj.prototype = constructor.prototype 是不行的,有很多局限性,如 obj 一开始得初始化,确保存在 prototype属性
使用 Object.create() ,创建一个新对象,使用现有的对象来提供新创建的对象的 proto
可以看作以下简短代码的实现:
function create(obj) {
function F() {}
F.prototype = obj
return new F()
}API 使用具体参考:Object.create() - JavaScript | MDN
回到问题,我们使用 newObject = Object.create(constructor.prototype); 来实现功能
如何更改 this 的作用域
使用 call 或者 apply,二者的区别也就是方法第二个参数一个为 一系列的参数,一个为 类数组
作用可以参考以下用例
function People(name, age) {
this.name = name;
this.age = age;
}
function Student(name, age, grade) {
People.call(this, name, age);
this.grade = grade;
}
var student = new Student('小明', 21, '大三');
console.log(student.name + student.age + student.grade);//小明21大三API 使用具体参考:Function.prototype.call() - JavaScript | MDN
回到问题,我们使用 constructor.apply(newObject, arguments),该操作将 constructor 的 this 作用为 newObject
具体实现
function objectFactoty() {
let newObject = null;
// 调用 Array的原型方法 shift() ,拆解arguments参数为 构造函数 + 传参
let construct = Array.prototype.shift.call(arguments);
// 判断构造函数是否是一个函数
if (typeof constructor != "function") {
console.error('type error');
return;
}
// 将新对象的原型设置为构造器的原型对象
newObject.prototype = Objecte.create(constructor.prototype);
// 改变this作用域
result = constructor.apply(newObject, arguments);
// 判断返回对象,若存在返回值,则判断是否为引用类型返回值,
// 若不是引用类型返回值,则不提供返回对象
let flag = result && (typeof result === "object" || typeof result === "function");
// 返回结果
return flag ? result : newObject;
}
// 使用举例
objectFactory(function(name, age) {
this.name = name;
this.age = age;
}, "Tom", 20)参考
Object.create() - JavaScript | MDN
Function.prototype.call() - JavaScript | MDN
浅谈JS中call()和apply()的区别和用途