在JavaScript里,构造函数一般是认为用来实现实例的,JavaScript没有类的概念,可是有特殊的构造函数。经过new关键字来调用定义的否早函数,你能够告诉JavaScript你要建立一个新对象而且新对象的成员声明都是构造函数里定义的。在构造函数内部,this关键字引用的是新建立的对象。基本用法以下:javascript
function her(name, sex, height){ this.name = name; this.sex = sex; this.height = height; this.say = function(){ return this.name + ' is a ' + this.sex + ' has ' + this.height; } } var she1 = new her('Anna', 'women', '170cm'); console.log(she1.say()); // 'Anna is a Women has 170cm'
上面的例子是个很是简单的构造函数模式,可是有点小问题。首先是使用继承很麻烦了,其次output()在每次建立对象的时候都从新定义了,最好的方法是让全部Car类型的实例都共享这个output()方法,这样若是有大批量的实例的话,就会节约不少内存(这种状况在以前的文章里提到过了,能够看一下)。java
解决这个问题,咱们可使用以下方式:函数
function her(name, sex, height){ this.name = name; this.sex = sex; this.height = height; this.say = gaoHan; } function gaoHan(){ return this.name + ' is a ' + this.sex + ' has ' + this.height; }
这个方式虽然可用,可是咱们有以下更好的方式。this
JavaScript里函数有个原型属性叫prototype,当调用构造函数建立对象的时候,全部该构造函数原型的属性在新建立对象上均可用。按照这样,多个her对象实例能够共享同一个原型,咱们再扩展一下上例的代码:spa
function her(name, sex, height){ this.name = name; this.sex = sex; this.height = height; }
/*
注意:这里咱们使用了Object.prototype.方法名,而不是Object.prototype
主要是用来避免重写定义原型prototype对象
*/
her.prototype.say = function(){
return this.name + ' is a ' + this.sex + ' has ' + this.height;
}
var she1 = new her('Anna', 'women', '170cm');
console.log(she1.say()); // 'Anna is a Women has 170cm'
这里,say()单实例能够在全部Car对象实例里共享使用。另外:咱们推荐构造函数以大写字母开头,以便区分普通的函数。prototype
function her(name, sex, height){
this.name = name; this.sex = sex; this.height = height; this.say = function(){ return this.name + ' is a ' + this.sex + ' has ' + this.height; } }
//方法1:做为函数调用 her('Anna', 'women', '170cm');
//添加到window对象上 console.log(window.say());
//方法2:在另一个对象的做用域内调用 var o = new Object(); her.call(o, "Anna", "women", "170cm"); console.log(o.say());
该代码的方法1有点特殊,若是不适用new直接调用函数的话,this指向的是全局对象window,咱们来验证一下:code
// 做为函数调用 var she = her('Anna', 'women', '170cm'); console.log(typeof tom); // 'undefined' console.log(window.say());
这时候对象tom是undefined,而window.output()会正确输出结果,而若是使用new关键字则没有这个问题,验证以下:对象
// 做为函数调用 var she = her('Anna', 'women', '170cm'); console.log(typeof tom); // 'undefined' console.log(tom.say());
上述的例子展现了不使用new的问题,那么咱们有没有办法让构造函数强制使用new关键字呢,答案是确定的,上代码:blog
function Her(name, sex, height){ if( !(this instanceof her) ){ return new Car(name, sexr, height); } this.name = name; this.year = year; this.height= height; this.say = function(){ return this.name + ' is a ' + women + ' has ' + this.height; } }
var she1 = new her('Anna', 'women', '170cm');
var she2 = her('Lous', 'women', '165cm');
console.log(typeof she1); // object;
console.log(typeof she2); // object;
经过判断this的instanceof是否是Car来决定返回new Car仍是继续执行代码,若是使用的是new关键字,则(this instanceof Car)为真,会继续执行下面的参数赋值,若是没有用new,(this instanceof Car)就为假,就会从新new一个实例返回。继承
// 使用原始包装函数 var s = new String("my javascript"); var n = new Number(520); var b = new Boolean(true); // 推荐这种 var s = "my javascript"; var n = 520; var b = true;
推荐,只有在想保留数值状态的时候使用这些包装函数,关于区别能够参考下面的代码:
// 原始string var greet = "Hello there"; // 使用split()方法分割 greet.split(' ')[0]; // "Hello" // 给原始类型添加新属性不会报错 greet.smile = true; // 单无法获取这个值(18章ECMAScript实现里咱们讲了为何) console.log(typeof greet.smile); // "undefined" // 原始string var greet = new String("Hello there"); // 使用split()方法分割 greet.split(' ')[0]; // "Hello" // 给包装函数类型添加新属性不会报错 greet.smile = true; // 能够正常访问新属性 console.log(typeof greet.smile); // "boolean"
本章主要讲解了构造函数模式的使用方法、调用方法以及new关键字的区别,但愿你们在使用的时候有所注意。