第三层:构造函数——实例工厂

构造函数简称构造器,帮助生成对象。相当于其他语言中的类。
构造函数是通过new操作符调用的函数。
按照约定,构造函数的名字是以大写字母开头。

function Person(name) {
    this.name = name;
}
Person.prototype.sayHello = function() {
    console.log('Hello, '+ this.name);
};
var lin = new Person('lin');
lin.sayHello();	//Hello, lin

我们可以把Person看做普通函数。它只有通过new调用时,草变成构造函数。new操作符执行步骤如下:

  • 首先设置行为:创建一个新的对象,其原型为Person.prototype。
  • 然后设置数据:Person接受对象作为隐式参数this,并添加实例属性。
    在这里插入图片描述
1.JS中new操作符的实现

手动实现new操作符,实现大致如下:

// 手动实现new操作符
function newOperator(Constr, args) {
    var thisValue = Object.create(Constr.prototype);
    var result = Constr.apply(thisValue, args);
    //  new的另一个特性:可以从构造函数返回一个任意的对象
    //	如果构造函数有它自身的返回值,切为对象的话,可以直接返回,如果为其他的话返回新的原型对象
    if (typeof result === 'object' && result !== null) {
        return result;
    }
    return thisValue;
}
var run = newOperator(Person, ['Run']);
run.sayHello();	//Hello, Run
2.术语:两个原型

不幸的是,在JS的术语,prototype使用意义模糊不清:

  • 原型一:原型关系
    一个对象可以是另一个对象的原型:
> var proto = {};
> var obj = Object.create(proto);
> Object.getPrototypeOf(obj) === proto
true

这里的例子,proto是obj的原型

  • 原型二:prototype属性的值
    每个构造函数C都有一个prototype属性,它指向一个对象。该对象成为构造函数C的所有实例的原型:
> function C() {}
> Object.getPrototypeOf(new C()) === C.prototype
true

因此,我们称后者(每一个构造函数特有的prototype属性)为实例原型更为贴切。

3.实例的constructor属性

默认每个函数C都包含一个C.prototype的实例原型对象,它的constructor属性指回C:

> function C() {}
> C.prototype.constructor === C
true

因为每个实例都从原型实例中继承了属性,也包括constructor属性,所以可以使用它得到实例的构造函数:

> function C() {}
> var o = new C()
> o.constructor === C
true
  • constructor属性的用例
    • 切换对象的构造函数
    • 确定对象的构造函数名
    o.constructor.name
    
    • 创建相似对象
    > function C() {};
    > var a = new C();
    > var b = new a.constructor();
    console.log(b instanceof C);	//true
    
    • 指向父构造函数(superconstructor)

最佳实践
每个函数function f() {}都有一个f.prototype对象,应该避免修改这个对象,而是只为它增加属性:

C.prototype.sayHello = function (...) { ... }

如果想替换C.prototype的对象,则应该手动把正确的赋值给constructor:

C.prototype = {
	constructor: C,
	sayHello: function (...) { ... }
}
4.instanceof运算符
value instanceof Constr

它是检验Constr.prototype是否在value的原型链上。所以和下面的等价:

Constr.prototype.isPrototypeOf(value)

所以基本值对于instanceof总是false(基本值:波尔、字符串、数字、null、undefined)

  • 大多数对象都是Object的实例,但除了原型链的末端。eg:Object.prototype、Object.create(null)
  • 缺陷:跨域
    在Web中,每一个帧和窗口都拥有自己的域,具有独立的全局变量。对于跨域的对象,不可使用instanceof。例如:
if (myvar instanceof Array) ...	//Doesn't always work

原因是如果myvar是来源于另外一个域,它就属于另外一个域的Array,而非当前域的Array。(可以用ES5的Array.isArray)
解决方法有:
1.避免跨域:浏览器有postMessage()方法,它可以把对象复制到另外一个域,而非传递引用。
2.检测实例构造函数的名字
3.使用prototype属性标记实例属于的类型T。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值