Axiu Blog
原型对象。 在JavaScript中,构造器其实就是一个普通的函数。当使用 new 操作符来作用这个函数时,它就可以被称为**构造方法**(构造函数)。 要创建一个新实例,需要使用new操作符。以这种方式调用构造函数实际上会经历以下4个步骤: > (1)创建一个新对象; > (2)将构造函数的作用域赋给新对象(因此this就指向了这个对象);
首先,JavaScript并没有其他基于类的语言所定义的“方法”,只有函数(function)。在JavaScript里,任何函数都可以添加到对象上作为对象的属性。当继承的函数被调用时,this指向的是当前继承的对象,而不是继承的函数所在的原型对象。 在JavaScript中,构造器其实就是一个普通的函数。当使用 new 操作符来作用这个函数时,它就可以被称为**构造方法**(构造函数)。 要
首先,JavaScript并没有其他基于类的语言所定义的“方法”,只有函数(function)。在JavaScript里,任何函数都可以添加到对象上作为对象的属性。当继承的函数被调用时,this指向的是当前继承的对象,而不是继承的函数所在的原型对象。 在JavaScript中,构造器其实就是一个普通的函数。当使用 new 操作符来作用这个函数时,它就可以被称为**构造方法**(构造函数)。 要
JavaScript里new语句做了什么
Max

首先,JavaScript并没有其他基于类的语言所定义的“方法”,只有函数(function)。在JavaScript里,任何函数都可以添加到对象上作为对象的属性。当继承的函数被调用时,this指向的是当前继承的对象,而不是继承的函数所在的原型对象。

在JavaScript中,构造器其实就是一个普通的函数。当使用 new 操作符来作用这个函数时,它就可以被称为构造方法(构造函数)。

要创建一个新实例,需要使用new操作符。以这种方式调用构造函数实际上会经历以下4个步骤:

(1)创建一个新对象;
(2)将构造函数的作用域赋给新对象(因此this就指向了这个对象);
(3)执行构造函数中的代码(为这个新对象添加属性);
(4)返回新对象。

《JavaScript高级程序设计(第三版)》P145

这里有篇很好的文章解释了new的处理过程以及原型继承的相关内容:Javascript – How Prototypal Inheritance really works

function New (f) { var n = { '__proto__': f.prototype }; //步骤1 return function () { f.apply(n, arguments); //步骤2&3 return n; //步骤4 }; }

可以创建对象来证明以上代码有效

function Point(x, y){ this.x = x; this.y = y; } var p = New(Point)(10, 20); Point.prototype.print = function(){ console.log(this.x, this.y); } p.print(); // 10 20

看起来,new语句基本就是以上函数的一个语法糖。

构造函数的返回值

当使用new关键字时,构造函数一定会返回一个对象,默认返回的是指向this的对象。如果不给this添加属性,则返回一个“空”的对象。

注意,即使不写return,也会隐式返回指向this的对象。当然,也可以返回任意的其他对象。如果写了return false;或者return '123';之类的非对象,会被忽略,依然返回指向this的对象。

var ObjectCreator = function(){ this.name = 'This name'; var that = {}; that.name = 'That name'; return that; }

var o = new ObjectCreator(); console.log(o.name); // That name

潜在问题

在《Javascript语言精粹》B.11(鸡肋)里,作者Douglas Crockford提倡更好的策略是不使用new,原因是因为如果忘记使用new,会把this绑定到全局对象,造成全局污染,并且没有警告。但是不使用new,就需要手动指定prototype,并完成步骤1~4,如果因为某个语法一旦写错会出问题而弃用它,有些违背语法创立的初衷。诚然,造个轮子肯定能解决一些问题,并且由于只使用基础语法,看起来更强壮,但是程序员那么懒,谁喜欢多写代码呢?

prototype和__proto__

每一个函数都有一个prototype的属性,每一个由该函数实例化的对象都包含一个隐式指针(__proto__)指向该函数的prototype属性。所以,prototype属性体现的是构造函数和实例之间的关系。

而__proto__,在ES6之前至少在规范中是没有这个属性的,但是浏览器厂商自行实现了,在ES6规范中,它其实是Object.prototype对外暴露的一个访问器属性,具有[[Get]]和[[Set]]的方法,用来操作对象的原型。我们在使用对象字面量创建对象的时候,__proto__属性能够设置对象的prototype,可以用来作为Object.create()的替代方案。

function A(){} var a = new A(); a.__proto__ === A.prototype //true

但是,函数的prototype和__proto__属性没有关系,因为

A.__proto__ === Function.prototype //true

Object.create(proto[, propertiesObject])可以理解为不执行构造函数的new。

Comments