Ошибки компоновщика могут произойти, если заголовочный файл и связанная с ним общая библиотека (файл .lib) не синхронизируются. Позволь мне объяснить.
Как работают линкеры? Линкер соответствует объявлению функции (объявленному в заголовке) с его определением (в общей библиотеке) путем сравнения их подписи. Вы можете получить ошибку компоновщика, если компоновщик не найдет определение функции, которое идеально подходит.
Возможно ли получить ошибку компоновщика, даже если объявление и определение, похоже, совпадают? Да! Они могут выглядеть одинаково в исходном коде, но это действительно зависит от того, что видит компилятор. По сути, вы можете столкнуться с такой ситуацией:
// header1.h
typedef int Number;
void foo(Number);
// header2.h
typedef float Number;
void foo(Number); // this only looks the same lexically
Обратите внимание, что хотя обе декларации функций выглядят одинаково в исходном коде, но они действительно различаются в зависимости от компилятора.
Вы можете спросить, как это получается в такой ситуации? Включите пути, конечно! Если при компиляции разделяемой библиотеки путь include приводит к header1.h
, и вы в конечном итоге используете header2.h
в своей собственной программе, вы оставите царапины на своем заголовке, задаваясь вопросом, что произошло (каламбур).
Пример того, как это может произойти в реальном мире, объясняется ниже.
У меня есть два проекта: graphics.lib
и main.exe
. Оба проекта зависят от common_math.h
. Предположим, что библиотека экспортирует следующую функцию:
// graphics.lib
#include "common_math.h"
void draw(vec3 p) { ... } // vec3 comes from common_math.h
И затем вы идете вперед и включаете библиотеку в свой собственный проект.
// main.exe
#include "other/common_math.h"
#include "graphics.h"
int main() {
draw(...);
}
Boom! Вы получаете ошибку компоновщика, и вы понятия не имеете, почему она терпит неудачу. Причина в том, что общая библиотека использует разные версии одного и того же include common_math.h
(я сделал это очевидным здесь в этом примере, включив другой путь, но это может быть не всегда так очевидно. Возможно, путь include отличается в настройки компилятора).
Обратите внимание, что в этом примере компоновщик сказал бы вам, что не смог найти draw()
, когда на самом деле вы знаете, что он явно экспортируется библиотекой. Вы могли часами царапать себе голову, думая, что пошло не так. Дело в том, что компоновщик видит другую подпись, потому что типы параметров немного отличаются. В этом примере vec3
является другим типом в обоих проектах в отношении компилятора. Это может произойти из-за того, что они происходят из двух немного разных файлов include (возможно, включенные файлы поступают из двух разных версий библиотеки).
DUMPBIN - ваш друг, если вы используете Visual Studio. Я уверен, что другие компиляторы имеют другие подобные инструменты.
Процесс выглядит следующим образом:
[1] По проекту я имею в виду набор исходных файлов, которые связаны друг с другом для создания либо библиотеки, либо исполняемого файла .
РЕДАКТИРОВАТЬ 1: Переписать первый раздел, который будет легче понять. Пожалуйста, прокомментируйте ниже, чтобы сообщить мне, нужно ли что-то еще исправлять. Спасибо!
Ответ Federico Zancan верен, но вам не нужно указывать свой скрипт ID и оценивать весь ваш скрипт. Просто оцените свое имя функции и его можно вызвать.
Чтобы достичь этого в нашем проекте, мы написали прокси-функцию для вызова функции, возвращаемой внутри ответа Ajax.
function FunctionProxy(functionName){
var func = eval(functionName);
func();
}
Я решил это сегодня, поставив свой JavaScript в нижней части ответа HTML.
У меня был запрос AJAX, который возвратил кучу HTML, который был отображен в оверлее. Мне нужно было прикрепить событие click к кнопке в возвращаемом ответе HTML / overlay. На обычной странице я обернул бы свой JavaScript в «window.onload» или «$ (document) .ready», чтобы он привязал обработчик события к объекту DOM после того, как DOM для нового наложения был визуализирован, но потому что это был ответ AJAX, а не новая загрузка страницы, это событие никогда не происходило, браузер никогда не выполнял мой JavaScript, мой обработчик событий никогда не привязывался к элементу DOM, и моя новая функциональность не работала. Опять же, я решил «выполнить JavaScript в проблеме ответа AJAX», не используя «$ (document) .ready» в начале документа, но, разместив свой JavaScript в конце документа и выполнив его после HTML / DOM.
Я хотел бы добавить, что в jQuery есть функция eval, позволяющая вам глобально оценить код, который должен избавить вас от любых контекстуальных проблем. Эта функция называется globalEval () , и она отлично работает для моих целей. Его документация может быть найдена здесь здесь .
Это пример кода, предоставленного документацией jQuery API:
function test()
{
jQuery.globalEval("var newVar = true;")
}
test();
// newVar === true
Эта функция чрезвычайно полезна, когда она приходит к загрузке внешних скриптов динамически, которые вы, по-видимому, пытались сделать.
Примечание: eval () можно легко использовать неправильно, скажем, что запрос перехвачен третьей стороной и отправляет вам не доверенный код. Затем с помощью eval () вы будете запускать этот недопустимый код. См. Здесь опасности eval () .
blockquote>
Внутри возвращаемого файла HTML / Ajax / JavaScript у вас будет тег JavaScript. Дайте ему идентификатор, например runningcript . Необязательно добавлять идентификатор к этим тегам, но это необходимо для ссылки на него.
<script type="text/javascript" id="runscript"> alert("running from main"); </script>
В главном окне вызывается функция eval, оценивая только этот НОВЫЙ блок кода JavaScript (в этом case, он называется runningcript ):
eval(document.getElementById("runscript").innerHTML);
И он работает, по крайней мере, в Internet & nbsp; Explorer & nbsp; 9 и Google Chrome.
Просто помните, если вы создаете функцию ниже, используя ajax ...
function foo()
{
console.log('foo');
}
... и выполняйте ее через eval, вы, вероятно, столкнетесь с проблемой контекста. Возьмите это как функцию обратного вызова:
function callback(result)
{
responseDiv = document.getElementById('responseDiv');
responseDiv.innerHTML = result;
scripts = responseDiv.getElementsByTagName('script');
eval(scripts[0]);
}
Вы будете объявлять функцию внутри функции, поэтому эта новая функция будет доступна только в этой области.
Если вы хотите чтобы создать глобальную функцию в этом сценарии, вы можете объявить ее следующим образом:
window.foo = function ()
{
console.log('foo');
};
Но я также думаю, что вы не должны этого делать ...
Извините за любая ошибка здесь ...
С jQuery я бы сделал это с помощью getScript
Это кажется довольно странным дизайном для вашего кода - обычно имеет смысл использовать ваши функции непосредственно из файла .js, а затем извлекать данные только с помощью вызова Ajax.
Однако, я что он должен работать, вызвав eval () ответ - при условии, что это синтаксически правильный код JavaScript.
Моя обычная функция вызова ajax:
function xhr_new(targetId, url, busyMsg, finishCB)
{
var xhr;
if(busyMsg !== undefined)
document.getElementById(targetId).innerHTML = busyMsg;
try { xhr = new ActiveXObject('Msxml2.XMLHTTP'); }
catch(e)
{
try { xhr = new ActiveXObject('Microsoft.XMLHTTP'); }
catch(e2)
{
try { xhr = new XMLHttpRequest(); }
catch(e3) { xhr = false; }
}
}
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4)
{
if(xhr.status == 200)
{
var target = document.getElementById(targetId)
target.innerHTML = xhr.responseText;
var scriptElements = target.getElementsByTagName("script");
var i;
for(i = 0; i < scriptElements.length; i++)
eval(scriptElements[i].innerHTML);
if(finishCB !== undefined)
finishCB();
}
else
document.getElementById(targetId).innerHTML = 'Error code: ' + xhr.status;
}
};
xhr.open('GET', url, true);
xhr.send(null);
// return xhr;
}
Некоторое объяснение: targetId
- это идентификатор элемента (обычно div), где будет выводиться текст результата вызова ajax. url
- адрес вызова ajax. busyMsg
будет временным текстом в целевом элементе. finishCB
вызывается, когда операция ajax завершена успешно. Как вы видите в xhr.onreadystatechange = function() {...}
все элементы <script>
будут собраны из ответа ajax и будут выполняться один за другим. Кажется, он работает очень хорошо для меня. Два последних параметра являются необязательными.
Код стороны PHP Имя файла class.sendCode.php
<?php
class sendCode{
function __construct($dateini,$datefin) {
echo $this->printCode($dateini,$datefin);
}
function printCode($dateini,$datefin){
$code =" alert ('code Coming from AJAX {$this->dateini} and {$this->datefin}');";
//Insert all the code you want to execute,
//only javascript or Jquery code , dont incluce <script> tags
return $code ;
}
}
new sendCode($_POST['dateini'],$_POST['datefin']);
Теперь со страницы Html вы должны запустить функцию ajax для отправки данных.
.... <script src="http://code.jquery.com/jquery-1.9.1.js"></script> ....
Date begin: <input type="text" id="startdate"><br>
Date end : <input type="text" id="enddate"><br>
<input type="button" value="validate'" onclick="triggerAjax()"/>
Теперь в нашем локальном script.js мы определим ajax
function triggerAjax() {
$.ajax({
type: "POST",
url: 'class.sendCode.php',
dataType: "HTML",
data : {
dateini : $('#startdate').val(),
datefin : $('#enddate').val()},
success: function(data){
$.globalEval(data);
// here is where the magic is made by executing the data that comes from
// the php class. That is our javascript code to be executed
}
});
}
Если ваш сценарий AJAX занимает больше пары миллисекунд для запуска, eval () будет всегда запускаться вперед и оценивать пустой элемент ответа до того, как AJAX заполнит его сценарием, который вы пытаетесь выполнить.
Вместо того, чтобы сбрасывать тайм-аут и eval (), вот довольно простой обходной путь, который должен работать в большинстве ситуаций и, вероятно, немного более безопасен. Использование eval (), как правило, неодобрительно, потому что символы, которые оцениваются как код, легко могут быть обработаны на стороне клиента.
В этом примере я хочу добавить динамический список автозаполнения из библиотеки jquery-ui в элемент AJAX ПОСЛЕ того, как элемент был добавлен на страницу. Легко, правда?
start.php
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<!-- these libraries are for the autocomplete() function -->
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/ui-lightness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script type="text/javascript">
<!--
// this is the ajax call
function editDemoText(ElementID,initialValue) {
try { ajaxRequest = new XMLHttpRequest();
} catch (e) {
try { ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try { ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
return false;
}}}
ajaxRequest.onreadystatechange = function() {
if ( ajaxRequest.readyState == 4 ) {
var ajaxDisplay = document.getElementById('responseDiv');
ajaxDisplay.innerHTML = ajaxRequest.responseText;
}
}
var queryString = "?ElementID="+ElementID+"&initialValue="+initialValue;
ajaxRequest.open("GET", "ajaxRequest.php"+queryString, true);
ajaxRequest.send(null);
}
// this is the function we wanted to call in AJAX,
// but we put it here instead with an argument (ElementID)
function AttachAutocomplete(ElementID) {
// this list is static, but can easily be pulled in from
// a database using PHP. That would look something like this:
/*
* $list = "";
* $r = mysqli_query($mysqli_link, "SELECT element FROM table");
* while ( $row = mysqli_fetch_array($r) ) {
* $list .= "\".str_replace('"','\"',$row['element'])."\",";
* }
* $list = rtrim($list,",");
*/
var availableIDs = ["Demo1","Demo2","Demo3","Demo4"];
$("#"+ElementID).autocomplete({ source: availableIDs });
}
//-->
</script>
</head>
<body>
<!-- this is where the AJAX response sneaks in after DOM is loaded -->
<!-- we're using an onclick event to trigger the initial AJAX call -->
<div id="responseDiv"><a href="javascript:void(0);" onclick="editDemoText('EditableText','I am editable!');">I am editable!</a></div>
</body>
</html>
ajaxRequest.php
<?php
// for this application, onfocus works well because we wouldn't really
// need the autocomplete populated until the user begins typing
echo "<input type=\"text\" id=\"".$_GET['ElementID']."\" onfocus=\"AttachAutocomplete('".$_GET['ElementID']."');\" value=\"".$_GET['initialValue']."\" />\n";
?>
Я тестировал это, и он работает. В чем проблема? Просто поместите новую функцию внутри своего javascript-элемента, а затем вызовите ее. Он будет работать.
Этот код работает, а вместо eval html я собираюсь добавить скрипт в голову
function RunJS(objID) {
//alert(http_request.responseText);
var c="";
var ob = document.getElementById(objID).getElementsByTagName("script");
for (var i=0; i < ob.length - 1; i++) {
if (ob[i + 1].text != null)
c+=ob[i + 1].text;
}
var s = document.createElement("script");
s.type = "text/javascript";
s.text = c;
document.getElementsByTagName("head")[0].appendChild(s);
}