Удивительный образец реализации - новое ключевое слово, используемое в функции-обертке - PullRequest
0 голосов
/ 19 ноября 2018

Работая над библиотекой Paper.js, я обнаружил в базе кода способ создания экземпляра класса, который раньше никогда не использовал. Например, здесь используется для создания экземпляра класса Shape.
Этот образец реализации может быть упрощен до следующего: дан класс Ball и метод createBall(), который его создает:

function Ball() {}
function createBall() {return new Ball()}

Конечно, мы можем получить экземпляр шара, позвонив по номеру:

var ball = createBall();

Но что более удивительно, мы также можем получить экземпляр ball, вызвав (обратите внимание на ключевое слово new):

var ball = new createBall();

Или как более абстрактный способ:

var ball = new function() {return new Ball()};

Поскольку createBall() возвращает экземпляр Ball, создается впечатление, что мы создаем экземпляр класса Ball, используя ключевое слово new для его экземпляра.

Но, как видно из следующего кода, это не разрешено и выдает ошибку, если мы делаем это вручную:

var ball1 = new Ball();
var ball2 = new ball1();
// error: ball1 is not a constructor

Может кто-нибудь объяснить мне, что за этим стоит?

Вот сравнительный пример различных методов создания экземпляров:

// Class
function Ball() {}

// Method creating an instance of the class
function createBall() {
  // Instantiate the class
  var ball = new Ball();
  // Return the instance
  return ball;
}

// Expected: instantiating directly works
var ball1 = new Ball();
console.log('ball1', ball1 instanceof Ball); // outputs true

// Expected: instantiating through the creation method works
var ball2 = createBall();
console.log('ball2', ball2 instanceof Ball); // outputs true

// Unexpected: instantiating like this surprisingly works
var ball3 = new createBall();
console.log('ball3', ball3 instanceof Ball); // outputs true

// Expected: instantiating like this throws an error
var ball4 = new ball1();
// error: ball1 is not a constructor

Редактировать

Прочитав комментарий @ robert-zigmond, я обнаружил еще один вводящий в заблуждение случай:

function Dog() {}

function Ball() {
  return new Dog();
}

var instance = new Ball();

console.log('is instance a Ball ?', instance instanceof Ball); // false
console.log('is instance a Dog ?', instance instanceof Dog); // true

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

когда new Function вызывается

  1. Создается новый объект, наследующий от Function.prototype
  2. , вызывается конструктор, и это связано с новым объектом на первом этапе.создал.
  3. если ничего не возвращено, то этот объект будет возвращен или вы можете вернуть новый объект, как ваш пример

function createBall() { console.log('origin this', this); return new Ball(); } , когда вызывается new createBall(), он создаетновый объект, который наследуется от createFoo.prototype this, если ничего не возвращено, то этот объект становится результатом new createBall(), но здесь вы возвращаете new Ball(), поэтому объект this изменился на new Foo() и вернул

0 голосов
/ 19 ноября 2018

ball1 даже не функция, поэтому вы получаете ошибку там.

Любая функция в Javascript может быть вызвана с использованием оператора new - по сути, это заставляет ее создавать новый объект, который берется как ссылка this для функции, и возвращает его (но только если функция не возвращает объект уже - если это так, построенный объект выбрасывается).

Смотрите здесь точно, что делает оператор new: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new#Description

Ваш «другой вводящий в заблуждение случай» поначалу кажется странным, потому что instance еще определен как new Ball(), но instance instanceof Ball возвращает false. Это связано с тем, что, как я уже говорил выше, «функция конструктора» возвращает только что созданный объект, если в противном случае возвращает значение, которое вообще не является объектом. В большинстве функций, предназначенных для использования в качестве конструкторов, на самом деле явного возвращаемого значения не существует - поэтому возвращаемое значение неявно undefined, и поэтому вновь созданный объект возвращается.

Но в этом примере функция иначе вернула бы объект, который является экземпляром Dog - так что этот объект заканчивается как instance. Хотя он был создан с помощью new Ball(), это было несколько косвенно, на самом деле было создано путем вызова new Dog(), и, таким образом, Dog.prototype находится в цепочке прототипов, а не Ball.prototype. Это объясняет поведение наблюдаемого вами оператора instanceof.

...