Js говорят о новых принципах и реализации

внешний интерфейс JavaScript
Js говорят о новых принципах и реализации

Это 8-й день моего участия в августовском испытании обновлений.Подробности о событии:Испытание августовского обновления

определение

newПримеры примера Оператор для создания пользовательского типа объекта или встроенные объекты, имеющие конструктор.

использоватьnew [constructor]

newВызов оператора является конструктором, а неnewФункция, вызываемая оператором, является нормальной функцией.

Таким образом, конструкторы также могут иметь возвращаемые значения, но это приводит кnewрезультаты разные.

Нет возвращаемого значения

function Person(name) {
  this.name = name;
}

let obj = new Person("Jalenl");
console.log(obj);

Видимо, что печатает{name:'Jalenl'}

возвращаемый объект

function Person(age) {
  this.age = age;
  return { name: "Jalenl" };
}

let obj = new Person(18);
console.log(obj);

печать{name:'Jalenl'}, то естьreturnВсе предыдущие определения перезаписываются. здесьreturnявляется объектом, что, если он возвращает примитивный тип?

Вернуть не объект

function Person(age) {
  this.age = age;
  return 1;
}

let obj = new Person(18);
console.log(obj);

вернуть{age:21},такreturnНеудача, следующаяreturnтот же результат, если неthisПривязать внутренние свойства, вернуться к базовому типу данных?

function Person(){
    return 1
}
new Person()

{}, Ожидал.

Таким образом, только конструкторreturnВозвращение - это тип объекта, чтобы изменить начальные результаты.

Различные типы конструкторов

Конструктор — это обычная функция

ECMA-262 3rd. Edition SpecificationСоздание экземпляра объекта описано в:

13.2.2 [[Construct]]

When the [[Construct]] property for a Function object F is called, the following steps are taken:

  1. Create a new native ECMAScript object.
  2. Set the [[Class]] property of Result(1) to "Object".
  3. Get the value of the prototype property of F.
  4. If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).
  5. If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as described in 15.2.3.1.
  6. Invoke the [[Call]] property of F, providing Result(1) as the this value and providing the argument list passed into [[Construct]] as the argument values.
  7. If Type(Result(6)) is Object then return Result(6).
  8. Return Result(1).

Подвести итог:

  1. Создайте новый объект в памяти.
  2. внутри этого нового объекта[[Prototype]]Атрибут присваивается конструкторуprototypeАтрибуты.
  3. внутри конструктораthisприсваивается этому новому объекту (т.е.thisуказать на новый объект).
  4. Выполнить код внутри конструктора (добавить свойства в новый объект).
  5. Если конструктор возвращает объект, верните этот объект, в противном случае верните только что созданный новый объект (пустой объект).

Пятый шаг уже объяснил, что разные конструкторы вызываютnewПричина разных результатов.

Следующее взято изMDNобъяснение:

При выполнении кода new Foo(…) происходит следующее:

  1. Создается новый объект, наследуемый от Foo.prototype.
  2. Указанные параметры вызывают конструктор Foo, который привязывается к вновь созданному объекту. новый Foo эквивалентен новому Foo(), то есть не указан список аргументов, ситуация Foo без параметров вызова.
  3. 由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。 (В обычных условиях конструктор не возвращает значение, но пользователь может активно возвращать объект, чтобы переопределить обычные шаги создания объекта.)

prototypeconstructor

function Person(){
    this.age = 18;
}
Person.prototype
/**
{
    constructor: ƒ Foo()
    __proto__: Object
}
**/

Когда вы создаете стрелочную функцию, движок ее не создаст.prototypeсвойства, стрелочные функции неconstructorдляnewЗвоните, так что используйтеnewВызов стрелочной функции вызовет ошибку!

const Person = ()=>{}
new Person()//TypeError: Foo is not a constructor

рукописный новый

В общем, знакомоnewПосле принципа работы мы можем реализовать низкопрофильную версию самостоятельно.new, ключ к достижению:

  1. Разрешить экземпляру иметь доступ к закрытым свойствам;
  2. Сделать экземпляр доступным для конструктора-прототипа (constructor.prototype
function _new(constructor, ...args) {
    // 构造函数类型合法判断
    if(typeof constructor !== 'function') {
      throw new Error('constructor must be a function');
    }
    // 新建空对象实例
    let obj = new Object();
    // 将构造函数的原型绑定到新创的对象实例上
    obj.__proto__ = Object.create(constructor.prototype);
    // 调用构造函数并判断返回值
    let res = constructor.apply(obj,  args);
    let isObject = typeof res === 'object' && res !== null;
    let isFunction = typeof res === 'function';
    // 如果有返回值且返回值是对象类型,那么就将它作为返回值,否则就返回之前新建的对象
    return isObject || isFunction ? res : obj;
};

newРеализация может использоваться для создания экземпляра пользовательского класса, но не поддерживает встроенные объекты, в конце концовnewОн принадлежит оператору, а базовая реализация более сложна.