又是新的征程,冲冲冲。
前言
本章的主角是new关键字
,首先我们先来看看关于new关键字
的使用,先直接怼代码。
function Person(name, age) {
this.name = name;
this.age = age;
}
// 在构造函数的原型上挂载方法
Person.prototype.say = function() {
console.log('姓名:' + this.name + ',年龄:' + this.age);
}
var p = new Person('橙某人', 18);
console.log(Person.prototype)
console.log(p)
console.log(Person.prototype === p.__proto__)
console.log(typeof p)
console.log(p.name);
console.log(p.age);
p.say();
我们从上面的例子能分析得到如下结论:
- 通过new关键字来实例化构造函数的实例,其实也就是返回了一个新对象。
- 构造函数的
this
要指向新对象,这样我们才能通过p.name
访问到相应属性,因为我们在构造函数是把name
属性放置构造函数this
上的。 - 新对象的原型(
__proto__
)指向了构造函数的原型(prototype
),因此我们能直接访问到构造函数原型上的say()
方法。关于原型还不的小伙伴可以看看它。传送门
所以new关键字
大致就干了怎么三件事情:
返回一个新对象、构造函数的this指向新对象,新对象原型指向构造函数原型!!!
返回一个新对象、构造函数的this指向新对象,新对象原型指向构造函数原型!!!
返回一个新对象、构造函数的this指向新对象,新对象原型指向构造函数原型!!!
模拟实现
实现一
通过上面的分析,是不是突然感觉new关键字
也没那么高大尚了? 一直就没有?Em...好吧。
好,话不多说,我们来试着实现这三件事情,不就返回一个新对象与改变相关指向吗?简单,我们先上代码观察一波先(注意看注解)。
function myNew(constructor) {
// 定义一个新对象
let newObject = new Object();
// 改变新对象的原型指向构造函数
newObject.__proto__ = constructor.prototype;
// 改变构造函数的指向, 传递相关参数
constructor.apply(newObject, [].slice.call(arguments, 1))
// 返回新对象
return newObject;
}
var p = myNew(Person, '橙某人', 18);
console.log(Person.prototype)
console.log(p)
console.log(Person.prototype === p.__proto__)
console.log(typeof p)
console.log(p.name);
console.log(p.age);
代码是不多的,测试代码结果也和原来上面图是一样的,这说明成功啦。
因为 new
是一个关键字,不能像其他原始方法(call()
)一样进行覆盖,所以我们用一个函数来模拟 new
的效果。
function Person(){}
// 原来的new用法
var p = new Person(parmas, ...);
// 模拟的new用法
var p = myNew(Person, parmas, ...);
上面代码主要是关注myNew()
方面,里面也就寥寥四行代码,是不是真的很简单。唯一比较需要关注的也是call()与apply()
方法,关于他俩不熟悉的小伙伴可以看看它。传送门
这就完了吗? 完了吗? 肯定是没有啦,继续冲它。
实现二
下面我们主要来谈论下关于构造函数返回值问题,先来看看下面的代码。
function Person(params){
return params;
}
let string = new Person('string');
let number = new Person(100);
let boolean = new Person(true);
let object = new Person({a: 1});
let array = new Person([1]);
let fun = new Person(() => {});
console.log(string);
console.log(number);
console.log(boolean);
console.log(object);
console.log(array);
console.log(fun);
我们根据输入的结果,大致可以知道,使用new关键字
调动函数时,如果return
的是String
、Number
、Boolean
类型的话则返回构造函数实例化的对象,而如果return
的是Object
、Array
、Function
等引用类型的对象的话,则返回这些值本身。
根据上面的测试,原来我们实现的myNew()
方法是一直就只是返回那个新对象,现在我们就需要改造改造了。
function myNew(constructor) {
let newObject = new Object();
newObject.__proto__ = constructor.prototype;
// 获取到构造函数的返回值
let resutl = constructor.apply(newObject, [].slice.call(arguments, 1))
// 判断是否是引用类型
return resutl instanceof Object ? newObject : resutl;
}
最后我们上测试代码看看。
function Person(params){
return params;
}
let string = myNew(Person, 'string');
let number = myNew(Person, 100);
let boolean = myNew(Person, true);
let object = myNew(Person, {a: 1});
let array = myNew(Person, [1]);
let fun = myNew(Person, () => {});
console.log(string);
console.log(number);
console.log(boolean);
console.log(object);
console.log(array);
console.log(fun);
至此,本章内容就真的讲完啦,感谢你的观看。