new操作符到底干了什么

298 阅读2分钟

之前一直很迷惑new一个函数到底是个啥,笔记本上到处戳戳,还有不同时期的不同理解。理解A:new X 是创建一个继承X.prototype的对象。理解B:使用new调用一个函数,将会构造函数的作用域付给新对象:a = new B()把B的this给a。????????????我记的啥,怎么看起来那么迷惑。

直到前不久看到一个说法,好像知道了一丢丢:

构造函数执行的时候会像普通函数一样,形成一个私有作用域,执行前会创建一个实例对象,让this指向这个对象,让实例对象的__proto__属性指向构造函数的原型即构造函数的prototype属性,执行完成后将这个对象返回。

举个例子:

function Fn(x, y) {
    //我们假设到了new Fn执行阶段,创建实例对象{__proto__:Object},将this指向实例对象,
    // 将实例的__proto__属性指向Fn.prototype得到{__proto__:Object}
    this.a = x  //将x赋值赋值给实例对象中的a,得到 {a:x, __proto__:Object}
    this.b = y  //将y给实例中的b {a:x, b: y,  __proto__:Object}
    var c = x   //Fn中保存的x
    this.getNum = function () {  //将函数给实例中的getNum属性,
        // 得到{a:x, b: y, getNum: f...,  __proto__:Object}
        console.log(this.a)
        console.log(c++)
    }
    //将得到的实例作为返回值返回
}
var f = new Fn(1, 1)
console.log(f) // =》{a: 1,b: 1,getNum: ƒ (),__proto__: Object}
f.getNum() // =》1,1
f.getNum() // =》1,2 c作为Fn执行时保存在作用域内的私有变量,
// getNum在这个作用域中创建,所以Fn这次执行的作用域是getNum的上级作用域,访问c时会像上级作用域查找
console.log(f.a) // =>1  f中有a属性
console.log(f.c) // =》undefined f中没有c属性
Fn.setStatic = function () {   //给Fn定义个静态方法
    console.log('我是静态方法')
}
Fn.setStatic() //调用静态方法

关于Fn执行内存不释放的闭包机制,可以看前两天写的我瞎说的闭包

以上都是在es5中,在es6中我们有了class语法糖:

class Fn {
    constructor(x,y){
        this.a = x
        this.b = y
        let c = x //设置私有变量
        this.getNum = function () {
            console.log(c++)
            console.log(this.a)
        }
    }
    say(){  //没有this的时候,函数定义在Fn的原型链上
        console.log(this.a)
    }
    static setStatic() {  //设置静态函数
        console.log('我是静态方法')
    }
}

let f = new Fn(1, 1)
console.log(f)  // {a: 1, b: 1, getNum: ƒ ()}
console.log(f.__proto__.say) //  => say(){console.log(this.a)} 是函数say
f.say() //1
f.getNum() //1, 1
f.getNum() //1,2
Fn.setStatic()  // 调用静态方法