在使用JavaScript中,我们经常会使用到new操作符,但是很多时候,我们都是知道这么用就是对的。我们原来都是这么干的,并不知道这其中发生了什么。今天我们就一起来探究一下,new的时候JavaScript中发生了什么呢
前提知识
- call
- apply
我们先来了解一下 call 和 apply 这两个方法
call 和 apply 两个方法的功能是用来修改函数的执行上下文
call方法接收一个或一个以上的参数,当接收一个参数时,第一个参数表示要改变的原函数的执行上下文(this);接收多个参数时,第二个参数及后面所有参数用来替换原函数的参数
apply方法接受一个或两个参数,当接收一个参数时,第一个参数表示要改变的原函数的执行上下文(this);接收两个参数时,第二个参数必须是数组(或伪数组),用于替换原函数中arguments保存的参数
var A = {
name: 'chencc',
fn: function (skill){
this.skill = skill
console.log("name:" + this.name + ", skill:" + this.skill)
}
}
var B = {
name: 'chenhh'
}
A.fn('javascript') // name:chencc, skill:javascript
A.fn.call(B, 'Java') // name:chenhh, skill:Java
A.fn.apply(B,['java']) // name:chenhh, skill:java
上面例子,我们知道了call和apply,就是为了改变this指向的
New 关键字
JavaScript中,在实例化一个对象时,就会用到new
function Foo(name) {
this.name = name
}
Foo.prototype.show = function() {
console.log(this.name)
}
var foo = new Foo('chencc')
foo.show()
对于上面new操作符做了以下几件事
// 1 创建一个新的对象,这个对象类型是 object
var obj = {}
// 2 将构造函数的上的所有方法和属性都复制一份给obj
// 这里采用将obj的__proto__属性指向了构造函数的prototype
obj.__proto__ = Foo.prototype
// 3 将构造函数Foo的this指向创建的对象
var result = Foo.call(obj)
// 返回创建的对象给实例化的对象
// 对于构造函数可能会return 对象问题做了个处理
return typeof result === 'object' ? result : obj
写一个 new 的完整实现
function newFactory(SuperClass, ...args) {
if(typeof SuperClass !== 'function'){
throw 'newOperator function the first param must be a function';
}
// let obj = Object.create(null)
let obj = new Object();
// 这里 Object.create(SuperClass.prototype)
// 这个方法用于创建一个新对象。被创建的对象继承另一个对象的原型
obj.__proto__ = Object.create(SuperClass.prototype);
// 这样方式实现 实际上是 obj.__proto__.__proto__ === SuperClass.prototype
// obj.__proto__ = SuperClass.prototype
// 上面两种方式都可以实现继承对象的原型
let res = SuperClass.apply(obj, ...args);
let isObject = typeof res === 'object' && typeof res !== null;
let isFunction = typoof res === 'function';
return isObect || isFunction ? res : obj;
}
Object.create()
Object.create() 方法创建了一个新对象,使用现有的对象来提供新创建对象的[[proto]]。
eg1:
function Foo () {}
let a = Object.create(Foo)
a.__proto__ === Foo // true
这里我们来看下 Object.create 执行过程中干了什么吧,其实就是用了new。
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F()
}
// 详细分析
function Foo () {}
var F = function () {}
F.prototype = Foo
var a = new F()
a.__proto__ === F.prototype
a.__proto__ === Foo
Object.create(null) 创建的是一个空对象,在该对象上没有继承Object.prototype 原型链上的属性或者方法
总结
总得来说,new 关键字的实现,实际就是通过原型链和改变this指向的方式。最后生成一个新的实例化的对象,拥有父类的属性和方法。是JS继承的一个基础方式。
希望大家看到这里都能理解 new 的时候真正经历了哪些步骤。