ES6方向:元属性new.target

            function Person(name) {
                this.name = name;
            }
            
            let person1 = new Person('test001');
            let person2 = Person('test002');
            
            console.log(person1); //Person {name: 'test001'}
                                  //name: "test001"
                                  //[[Prototype]]: Object

            console.log(person2); // undefined

在这段代码中,person1是通过new关键字来调用Person(),而person2没有通过new关键字调用则返回的是undefined,在JavaScript的函数机制中,本身的内部存在两个不同的方法,一个是[[Call]],另一个是[[Construct]],通过new关键字调用函数时,会先调用[[Construct]]来创建一个实例对象,再去执行函数体,将this绑定在这个实例上,如果没有使用new关键字,那么会执行[[Call]]函数,从而直接执行函数体。

在ES5中想要判断一个函数是否是通过new关键字被调用的,也就是说想要得知这个函数是否通过new去执行了construct()构造函数,最简便的方法便是通过instanceof去判断。

            function Person(name) {
                if(this instanceof Person) {
                    this.name = name;
                    console.log('success...')
                } else {
                    throw new Error('未通过new执行construct函数...');
                }
            }

可以看出,首先会检查this的指向是否是属于Person构造出去的实例,如果是的,那么才会进行初始化赋值,否则,就会抛出异常。但是这种方法一般书本上也不会去推荐使用,因为,javascript中存在可以修改this指向的方法,比如:Call()

            function Person(name) {
                if(this instanceof Person) {
                    this.name = name;
                    console.log('success...')
                } else {
                    throw new Error('未通过new执行construct函数...');
                }
            }

            let person1 = new Person('test001');  // success...
            let person2 = Person.call(person1,'test002'); // success...

调用Person.call(),将第一个变量person传入作为第一个参数,相当于Person函数里面将this指向了person1实例,而函数本身是无法区分Person.call()和new Person()的。

ES6中引入了new.target元属性来解决这一问题,元属性指的是非对象的属性,可以提供非对象目标的补充信息,当调用函数的[[Construct]]时,new.target被赋值为new操作符的目标,通常是新创建的对象实例,如果调用的[[Call]]时,则new.target的值为undefined,通过这个元属性,便可以检测是否通过new构造出来的对象。

            function Person(name) {
                if(typeof new.target !== 'undefined') {
                    this.name = name;
                    console.log('success...')
                } else {
                    throw new Error('未通过new执行construct函数...');
                }
            }

            let person1 = new Person('test001');
            let person2 = Person.call(person1,'test002');

            console.log(person1);
            console.log(person2);
结果打印.png

也可以检查new.target是否被某个特定的构造函数所调用

            function Person(name) {
                console.log(new.target);
                if(typeof new.target !== 'undefined') {
                    this.name = name;
                    console.log('success...')
                } else {
                    throw new Error('未通过new执行construct函数...');
                }
            }
            
            function Thing(name){
                debugger
                console.log(this);
                Person.call(this,name);
            }

            let person1 = new Person('test001');
            let thing1 = new Thing('car');

            console.log(person1);
            console.log(thing1);

你可能感兴趣的:(ES6方向:元属性new.target)