JavaScript中new操作符

377 阅读3分钟

在使用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 的时候真正经历了哪些步骤。