夜深了......
在探究JavaScript中的构造函数之前,我们需要搞清楚什么是构造函数,正如其名字一样 “构造” ,它的作用就是构造,接下来我们来看看它是在构造什么。
在继续往下说之前,我们需要明确所谓的构造函数其实就是一个函数,但是它具有自己的特征和用法,但是我们会发现如何区分和使用构造函数,那就不得不离不开JavaScript中的new关键字了。
在说明JavaScript中的构造函数时,我们必然不可能绕过它的两个特点:
函数体内部使用了this关键字,代表所要生成的对象实例。
生成对象的时候,必须使用new关键字。
以下就是一个最基础的使用new命令来实例化一个构造函数
let MyNew = function (){this.say_hello = function (){console.log('hello world')}}
let mynew = new MyNew
上述的操作就是通过new命令,让构造函数MyNew生成一个实例对象,并将结果交给mynew,mynew也就得到了构造函数中的属性
在实际中我们不可能通过一个构造函数来构造出一大堆相同对象,所以我们可以在new一个构造函数时传入参数。
let MyNew_1 = function (name){this.name = name
}
let mynew_1 = new MyNew_1('张三')
console.log(mynew_1.name) // '张三'
上述的操作就是通过new关键字在实例化一个对象的时候传入对应的参数。
因为在使用new关键字对构造函数进行实例化的时候,在最后它会自动的执行,所以在使用new关键字的可以发现。
let mynew_2 = new MyNew_1 // 不推荐let mynew_3 = new MyNew_1() // 推荐
上述的两种的方式虽然都可以,但是更推荐使用第二种,相较于第一种来说,更容易被识别。
在使用构造函数的时候,如果我们在使用构造函数时忘记了使用new关键字,那么它将会被当成一个函数来执行。
let MyNew_1 = function (name){this.name = name
}
let test = MyNew_1()
console.log(test.name) // undefined
上述之所以会输出undefined,使用为MyNew_1在被当成函数后,它的作用域就是全局的,而内部的this就指向的时window而window并没有声明这个变量,所以最后输出了undefined。
那么我们应该怎么避免这样的事情发生呢?
1.使用严格模式
除了正常运行模式,ECMAscript5添加了第二种运行模式:“严格模式”(strict mode)。顾名思义,这种模式是的Javascript在更严格的条件下运行。
function Fubar(foo, bar){'use strict';this._foo = foo;this._bar = bar;
}
Fubar()
使用严格模式后,如果你将构造函数当成函数使用,那么将会直接报错。结果如下:
之所以会报错,主要归功于在严格模式中,函数内部的this不能指向全局对象,默认等于undefined,导致不加new调用会报错(JavaScript 不允许对undefined添加属性。
2.使用instanceof关键字
我们可以通过instanceof关键字来判断。
function Fubar_1(foo, bar) {if (!(this instanceof Fubar_1)) {return new Fubar(foo, bar);}this._foo = foo;this._bar = bar;
}
console.log(Fubar_1(1, 2)._foo)// 1
console.log((new Fubar_1(1, 2))._foo) // 1
如上述代码,我们只需要判断this是否为Fubar_1的实例对象就可以知道该构造函数是否使用了new关键字,如果没有,则帮你new,并将实例化的对象返回。
在我们使用new关键字的时候,实际上它执行了下面的几步:
创建一个空对象,作为将要返回的对象实例。
将这个空对象的原型,指向构造函数的prototype属性。
将这个空对象赋值给函数内部的this关键字。
开始执行构造函数内部的代码。
转化为代码就是如下的操作:
function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {// 将 arguments 对象转为数组var args = [].slice.call(arguments);// 取出构造函数var constructor = args.shift();// 创建一个空对象,继承构造函数的 prototype 属性var context = ate(constructor.prototype);// 执行构造函数var result = constructor.apply(context, args);// 如果返回结果是对象,就直接返回,否则返回 context 对象return (typeof result === 'object' && result != null) ? result : context;
}// 实例
var actor = _new(Person, '张三', 28);
后面继续了解下🧐🧐🧐
当构造函数中有return语句的时候,我们只需要记住一点如果返回的是一个对象,则最终返回的就是这个对象,如果不是一个对象,则会返回this。
let MyNew_2 = function (){unt = unt
}
(new MyNew_2()) === 0 // false
let MyNew_3 = function (){unt = 0return {unt}
}
(new MyNew_3()).count === 0 // true
这是ECMASript 6 引入一个 新的属性它主要有两个作用:
当我们使用 new 操作符调用构造函数时,new.target 属性的值为构造函数,否则为 undefined
function Person (fullName) {if (typeof new.target !== 'undefined') {this.fullName = fullName;} else {throw new Error('须通过 new 关键字来调用 Person。');}}
let student = new Person('aa');
let student_1 = Person('aa'); // 报错
可以检查 new.target 是否被某个特定构造函数所有调用。
function Person (fullName, age) {if (typeof new.target === Person) {this.fullName = fullName;this.age = age;} else {throw new Error('必须通过 new 关键字来调用 Person。');}
}function Dog (fullName, age) {Person.call(this, fullName, age)
}let dog = new Dog('HeHe', 3)console.log(dog)
在es5中如果我们也要确定一个构造函数是否使用,那么我们将第一时间想到instanceof。
如下:
function Person (name) {if(this instanceof Person){this.name = name} else {throw new Error('未通过new调用')}
}
var person2 = Person('Hello') //抛出异常
通过上述的操作,我们就可以判断构造函数是否使用new关键字。但是它不够好,比如下面这个例子:
function Person (name) {if(this instanceof Person){this.name = name} else {throw new Error('未通过new调用')}
}
var person1 = new Person('Hello')
var person2 = Person.call(person1,'Hello') //正常执行
上述代码中使用call方法将this设为person1的实例,对于函数本身,无法通过区分Person.call还是new关键字得到Person的实例。但是通过new.target 就可以实现😍😍😍
王昱潇 --- 判断函数被调用的方法
网道 --- 实例对象与 new 命令
萌新小吉 --- 严格模式详解
本文发布于:2024-01-29 08:53:45,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170648962914130.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |