Подтвердить что ты не робот

Ключевое слово 'this' ведет себя по-разному в Nodejs и браузере

У меня есть эта часть кода:

var obj1;
var obj2;

function x() {
    obj1 = this;
}

function y() {
    obj2 = this;
}

x();
y();

console.log(obj1 === obj2);
console.log(obj1 === this);

Я запускал этот код в NodeJS с помощью командной строки: node app.js и запускался как script в браузере Chrome

Результат: в NodeJS результат: true false Результат NodeJS

В браузере Chrome результат: true true Результат браузера

Как это могло произойти? может ли кто-нибудь объяснить, что действительно происходит под капотом?

4b9b3361

Ответ 1

В браузере, работающем в глобальной области, this всегда window в вашем примере

var obj1;
var obj2;

function x() {
    obj1 = this; // window
}

function y() {
    obj2 = this; // window
}

x();
y();

console.log(obj1 === obj2);  // window === window = true
console.log(obj1 === this);  // window === window = true

Это не то, как он работает в Node. В Node.js все модули (script файлы) выполняются в их собственном closure, в то время как браузеры выполняют все script файлы непосредственно в глобальной области.

Другими словами, практически в любом файле, запущенном в Node, this будет просто пустым объектом, так как Node обертывает код в анонимную функцию, которая вызывается немедленно, и вы должны получить доступ к глобальный охват в этом контексте с помощью GLOBAL.

Это также упоминается в документации Globals:

Некоторые из этих объектов фактически не находятся в глобальной области видимости, а в области модуля - это будет отмечено.

Однако при вызове функции без определенного контекста в Node.js, как правило, по умолчанию используется глобальный объект. Тот же GLOBAL упоминается ранее, в качестве контекста выполнения.

Таким образом, вне функций this является пустым объектом, поскольку код обернут функцией Node, чтобы создать собственный контекст выполнения для каждого модуля (файл script), а внутри функций - потому что они называются без определенного контекста выполнения, this - это объект Node GLOBAL

В Node.js вы получите

var obj1;
var obj2;

function x() {
    obj1 = this; // GLOBAL
}

function y() {
    obj2 = this; // GLOBAL
}

x();
y();

console.log(obj1 === obj2);  // GLOBAL === GLOBAL = true
console.log(obj1 === this);  // GLOBAL === {} = false

Где последний this действительно пустой объект, как описано выше


Для полноты, стоит отметить, что в строгом режиме вы получите тот же результат в браузере (true, false), что и в Node, но это потому, что переменные просто противоположны тем, что они находятся в Node

"use strict"

var obj1;
var obj2;

function x() {
    obj1 = this; // undefined
}

function y() {
    obj2 = this; // undefined
}

x();
y();

console.log(obj1 === obj2);  // undefined === undefined = true
console.log(obj1 === this);  // undefined === window = false

Это потому, что значение, переданное как this функции в строгом режиме, не принудительно превращается в объект (a.k.a. "в штучной упаковке" ).
Для нормальной функции в нестрогом режиме this всегда является объектом, и он всегда является глобальным объектом, если называется с undefined или null этим значением, то есть без конкретной контекст выполнения.

Не только автоматический бокс стоимость исполнения, но обнажение глобального объекта в браузерах является угрозой безопасности, поскольку глобальный объект обеспечивает доступ к функциям, которые "защищают" Условия JavaScript должны быть ограничены.

Таким образом, для функции строгого режима указанный this не помещается в объект в объект, а если не указано, this будет undefined внутри функций, как показано выше, но this все равно будет окном в глобальном масштабе.

То же самое происходит в строгом режиме в Node.js, где this внутри функций больше не GLOBAL, а undefined, а this вне функций все равно будет один и тот же пустой объект, и конечный результат будет true, false, но значение this будет отличаться в строгом режиме в Node.js.

Ответ 2

Node явно устанавливает this в модуль экспорта здесь:

const result = compiledWrapper.apply(this.exports, args);

То, что apply делает, явно фиксирует значение this (и параметры) - в этом случае - устанавливает значение this.exports. Например, вы можете:

(function() { console.log(this.x); }).apply({x:3}); // alerts 3

Node переопределить поведение по умолчанию. Он должен, однако, вызывать функции внутри объекта с помощью global - как это предусмотрено спецификацией JS.

Ответ 3

В контексте браузера последнее указывает на объект Windowobject, который существует в Node -Context. Поэтому последний это пустой объект. Вхождения этого в функции, однако, указывают на какой-то глобальный объект в Node -Context.

Ответ 4

Разница довольно проста

В среде node:

этот относится к module.exports или exports для краткости. но внутри функции этот ссылается на весь пакет Node.js.

вы можете увидеть его, если вы заходите на консоль следующим образом:

function test(){
    console.log('this inside a function = ',this);
}

console.log('this outside a function = ',this);
test();

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

Выполните предыдущий пример как в Node.js, так и в браузере, и вы поймете.

Ответ 5

У меня сейчас нет сервера Node.js, но я думаю, что вы можете сами изучить этот вопрос и дать ответ нам: D см. код ниже

Попробуйте запустить:

console.log(this.constructor.name+" "+obj1.constructor.name+" "+obj2.constructor.name);

А также вы можете отлаживать имя родительского класса в функции:

function x() {
    console.log("x this: "+this.constructor.name);
    obj1 = this;
}

function y() {
    console.log("y this: "+this.constructor.name);
    obj2 = this;
}

И для просмотра Объектных методов/свойств вы можете использовать что-то вроде этого:

for (a in obj2) {
    console.log("obj2." + a + " = " + obj2[a]);
}