构造函数使用

构造函数具有两个特点,

  1. 第一首字母大写,
  2. 第二内部使用this关键字,调用时必须通过new命令调用生成实例。

new的作用

调用构造函数生成一个实例对象,有点类似于工厂模式,每个实例拥有构造函数的方法与属性。

使用new时可以不加"()",

 

new Foo; 

不过阅读方便这里推荐加上,构造函数可以接受参数,与普通函数一样。

 

function Foo(name) {
    this.name = name;
}
var a = new Foo();
var a = new Foo;

 

new 调用构造函数生成实例步骤分为四步

  1. 生成一个对象,代表要返回的实例对象;
  2. 将生成对象的原型指向构建函数的prototype;
  3. 将内部this指向生成的对象;
  4. 执行函数内部的代码。

如果忘记加上new命令会怎么样呢?

 

function Foo() {
    this.name = 10;
}
Foo();    //undefined
name;    //10;

因为Foo()未指定函数返回值,这里默认为返回undefined,

this在全局环境下调用默认为全局对象,这里是浏览器环境this指向window,生成了一个window.name并赋值为10。

 

如何避免调用忘记不加new方法调用?

  1. 在函数内部使用严格模式,严格模式下,this的默认指向为undefined,为undefined添加属性会报错。

 

function Foo() {
'use strict';
    this.name = 10;
}
Foo();
//annot set property 'name' of undefined

 

  1.  在函数体内通过判断
function Foo(name) {
    if (!(this instanceof Foo)) {
        return new Foo(name);
    }
    this.name = name;
}
var a = Foo(123);

 在全局下this指向全局对象,而使用newthis指向实例对象,

通过instanceof来判断构造函数的原型链上是否存在实例对象。

 

  1. 通过new.target属性判断

如果是使用new调用构造函数,那么newtarget属性指向构造函数,否则返回undefined。

 

function Foo(name) {
    if (!new.target) {
        return new Foo(name);
    }
    this.name = name;
}
var a = Foo(123);

 

构造函数也可以自己指定返回值, 但是返回值必须是一个对象,如果不是则忽略返回值,返回this对象,通过指定返回值返回的对象,内部this执行的语句会被忽略。

function Foo(name ,age) {
    this.name = name;
    this.age = age;
    return 123;
}
var a = new Foo('zhangsan' ,18);
//Foo {name: "zhangsan", age: 18}

function Foo(name ,age) {
    this.name = name;
    this.age = age;
    return {obj : 123};
}
var a = new Foo('zhangsan' ,18);
//{obj: 123}

 可以看到上面两个例子有一个共同点,总是返回一个对象,

 

但是如果使用new命令,而函数内部没有this会怎么样呢?

function Foo() {
    return 123;
}
var a = new Foo();
console.log(a);
//Foo{}

 

这里返回一个空对象,原型指向构造函数Foo.prototype,之所以这样是因为this指向实例对象a,在Foo内部并没有this,所以就是一个空对象。

 

构建函数的缺点

比如下面和这个例子,

假设一个构造函数内部age是输出一个特定的值,在多个实例中重复出现,这样的话不仅浪费内存,而且因为实例对象不同,每个age方法的内存地址也不同,修改age的方法不能做到全部实例更新。

 

function Foo(name , value) {
    this.name = name;
    this.value = value;
    this.age = function() {
        console.log('重复的一个调用');
    }
}
var a = new Foo('yang' ,20);
var b = new Foo('liu' ,11);
console.log(a.age === b.age);//false

 

每个函数都有一个prototype(原型)属性,对于构造函数来说,实例对象的原型就指向他。

我们可以在构造函数的prototype对象上定义一些共有的方法或者属性,来实现实例对象共享属性或者方法。

 

function Foo(name , value) {
    this.name = name;
    this.value = value;
};
Foo.prototype.age = function() {
    console.log('重复的一个调用');
};
var a = new Foo('yang' ,20);
var b = new Foo('liu' ,11);
console.log(a.age === b.age);//true

 

因为原型链查找规则,我们也可以在实例自身上定制跟构造函数相同的方法或者属性。

 

function Foo(name) {
    this.name = name;
}
Foo.prototype.color = 'yellow';
var a = new Foo('yang');
var b = new Foo('liu');
console.log(a.color ,b.color);//yellow yellow
a.color = 'bolor';
console.log(a.color ,b.color);//bolor yellow
Foo.prototype.color = 'a';
console.log(a.color ,b.color);//bolor a

这样就做到了自身和构造函数不同行为。

转载于:https://www.cnblogs.com/boses/p/9586207.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值