Во-первых, вам нужно иметь четкое представление о scope
и поведении ключевого слова this
в контексте scope
.
this
& amp; scope
:
there are two types of scope in javascript. They are :
1) Global Scope
2) Function Scope
вкратце, глобальная область относится к объекту window.Variables, объявленные в глобальной области, доступны из любого места. С другой стороны, область функций находится внутри функции .variable, объявленный внутри функции, не может быть доступен из внешнего мира в обычном режиме. this
ключевое слово в глобальной области относится к объекту window. Внутренняя функция this
также относится к объекту window.So this
всегда будет ссылаться на окно до тех пор, пока мы найдем способ манипулировать this
, чтобы указать контекст по собственному выбору.
--------------------------------------------------------------------------------
- -
- Global Scope -
- ( globally "this" refers to window object) -
- -
- function outer_function(callback){ -
- -
- // outer function scope -
- // inside outer function"this" keyword refers to window object - -
- callback() // "this" inside callback also refers window object -
- } -
- -
- function callback_function(){ -
- -
- // function to be passed as callback -
- -
- // here "THIS" refers to window object also -
- -
- } -
- -
- outer_function(callback_function) -
- // invoke with callback -
--------------------------------------------------------------------------------
Различные способы управления this
внутри функций обратного вызова:
Здесь У меня есть функция-конструктор, называемая Person. Он имеет свойство, называемое name
, и четыре метода, называемые sayNameVersion1
, sayNameVersion2
, sayNameVersion3
, sayNameVersion4
. Все четыре из них имеют одну конкретную задачу. Заберите обратный вызов и вызовите его. Обратный вызов имеет конкретную задачу, которая заключается в регистрации свойства имени экземпляра функции конструктора Person.
function Person(name){
this.name = name
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
this.sayNameVersion3 = function(callback){
callback.call(this)
}
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
}
function niceCallback(){
// function to be used as callback
var parentObject = this
console.log(parentObject)
}
Теперь давайте создадим экземпляр из конструктора person и вызывать разные версии sayNameVersionX
(X относится к 1,2,3,4) методу с niceCallback
, чтобы увидеть, как много способов управления this
внутри обратного вызова ссылаться на person
.
var p1 = new Person('zami') // create an instance of Person constructor
Что нужно сделать, это создать новую функцию с ключевым словом this
, установленным на предоставленное значение.
sayNameVersion1
и sayNameVersion2
используют bind для управления this
функции обратного вызова.
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
сначала связывают this
с обратным вызовом внутри самого метода. для второго обратного вызова передается связанный с ним объект.
p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method
p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback
first argument
в call
используется как функция this
внутри функции, которая вызывается с call
, прикрепленной к ней.
sayNameVersion3
использует call
для управления this
], чтобы ссылаться на созданный нами объект person, а не на объект окна.
this.sayNameVersion3 = function(callback){
callback.call(this)
}
и он называется следующим:
p1.sayNameVersion3(niceCallback)
Как и в call
, первый аргумент apply
относится к объекту, который будет обозначен ключевым словом this
.
sayNameVersion4
использует apply
для манипулирования this
для обращения к объекту человека
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
, и он называется следующим. Просто передается обратный вызов,
p1.sayNameVersion4(niceCallback)
Вы должны фактически определить статический член где-нибудь (после определения класса). Попробуйте следующее:
class Foo { /* ... */ };
const int Foo::MEMBER;
int main() { /* ... */ }
Это должно избавиться от неопределенной ссылки.
Aaa.h
class Aaa {
protected:
static Aaa *defaultAaa;
};
Aaa.cpp
// You must define an actual variable in your program for the static members of the classes
static Aaa *Aaa::defaultAaa;
Не знаю, почему работает бросок, но Foo :: MEMBER не выделяется до тех пор, пока Foo не будет загружен, и поскольку вы никогда не загружаете его, он никогда не выделяется. Если у вас есть ссылка на Foo где-то, это, вероятно, сработает.
Проблема возникает из-за интересного столкновения новых функций C ++ и того, что вы пытаетесь сделать. Во-первых, давайте посмотрим на подпись push_back
:
void push_back(const T&)
Ожидается ссылка на объект типа T
. В старой системе инициализации такой член существует. Например, следующий код компилируется просто отлично:
#include <vector>
class Foo {
public:
static const int MEMBER;
};
const int Foo::MEMBER = 1;
int main(){
std::vector<int> v;
v.push_back( Foo::MEMBER ); // undefined reference to `Foo::MEMBER'
v.push_back( (int) Foo::MEMBER ); // OK
return 0;
}
Это потому, что есть фактический объект где-то, у которого есть это значение, хранящееся в нем. Если, однако, вы переключитесь на новый метод указания статических константных элементов, как вы уже выше, Foo::MEMBER
больше не является объектом. Это константа, несколько схожа с:
#define MEMBER 1
Но без головных болей макроса препроцессора (и с безопасностью типа). Это означает, что вектор, ожидающий ссылки, не может получить его.
(int)
) происходит в блоке трансляции с идеальной видимостью константы, а Foo::MEMBER
больше не odr-used i>. Это контрастирует с первым вызовом функции, где ссылка передается и оценивается в другом месте.
– Lightness Races in Orbit
6 October 2014 в 23:12
Что касается второго вопроса: push_ref принимает ссылку как параметр, и вы не можете иметь ссылку на static const memeber класса / struct. После вызова static_cast создается временная переменная. И ссылка на этот объект может быть передана, все работает отлично.
Или, по крайней мере, мой коллега, который разрешил это, сказал.
Стандарт C ++ требует определения для вашего статического члена константы, если определение каким-то образом необходимо.
Требуется определение, например, если используется его адрес. push_back
принимает свой параметр с помощью ссылки const, и поэтому строгому компилятору нужен адрес вашего члена, и вам нужно определить его в пространстве имен.
Когда вы явно используете константу, вы создаете временное, и это временное, которое связано с ссылкой (по специальным правилам в стандарте).
Это действительно интересный случай, и я на самом деле думаю, что стоит подняться вопрос, чтобы std был изменен на имеют одинаковое поведение для вашего постоянного члена!
Хотя, в каком-то странном виде это можно рассматривать как законное использование унарного оператора «+». В основном результат unary +
является rvalue, поэтому применяются правила привязки rvalues к ссылкам const, и мы не используем адрес нашего статического члена const:
v.push_back( +Foo::MEMBER );
push_back
была const &
. Использование члена напрямую приводило к тому, что член привязывался к ссылке, что требовало наличия адреса. Однако добавление +
создает временное значение со значением члена. Ссылка затем привязывается к этому временному, а не требует, чтобы у члена был адрес.
– Richard Corden
13 July 2018 в 10:48
С C ++ 11 приведенное выше возможно для базовых типов как
class Foo {
public:
static constexpr int MEMBER = 1;
};
Часть constexpr
создает статическое выражение в противоположность статическому variable - и это ведет себя так же, как чрезвычайно простое определение встроенного метода. Тем не менее подход оказался немного шатким с C-string constexprs внутри классов шаблонов.