7.1. JavaScript 里 new 语句做了什么

2018-11-13  本文已影响0人  牧羊少年之奇幻之旅

转自: JavaScript里new语句做了什么

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

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

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

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

这里有篇很好的文章解释了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;
}

Point.prototype.print = function () {
  console.log(this.x, this.y);
}

var p = New(Point)(10, 20);

p.print(); // expected output: 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); // expected output: 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; // expected output: true

但是,函数的prototype__proto__属性没有关系,因为

A.__proto__ === Function.prototype; // expected output: true

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

上一篇 下一篇

猜你喜欢

热点阅读