Искажение функции JavaScript, кажется, не работает

objc_msgSend (obj, @selector (foo: bar: err :), var, var2 и & errVar);

81
задан Community 23 May 2017 в 12:10
поделиться

3 ответа

Вы должны привязать этот метод к объекту документа. Посмотрите:

>>> $ = document.getElementById
getElementById()
>>> $('bn_home')
[Exception... "Cannot modify properties of a WrappedNative" ... anonymous :: line 72 data: no]
>>> $.call(document, 'bn_home')
<body id="bn_home" onload="init();">

Когда вы делаете простой псевдоним, функция вызывается для глобального объекта, а не для объекта документа. Используйте метод, называемый закрытием, чтобы исправить это:

function makeAlias(object, name) {
    var fn = object ? object[name] : null;
    if (typeof fn == 'undefined') return function () {}
    return function () {
        return fn.apply(object, arguments)
    }
}
$ = makeAlias(document, 'getElementById');

>>> $('bn_home')
<body id="bn_home" onload="init();">

Таким образом вы не потеряете ссылку на исходный объект.

В 2012 году появился новый метод bind из ES5, который позволяет нам делать это более изящным способом:

>>> $ = document.getElementById.bind(document)
>>> $('bn_home')
<body id="bn_home" onload="init();">
39
ответ дан 24 November 2019 в 09:27
поделиться

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

>>> document.s = document.getElementById;
>>> document.s('myid');
<div id="myid">
-6
ответ дан 24 November 2019 в 09:27
поделиться

Давайте посмотрим, как насчет того, чтобы сделать абстракцию обязательной для каждого типа данных, а затем предоставить способы обобщения наших абстракций по параметрам типа? Подождите! Я только что заново изобрел CLU . Получу ли я премию Тьюринга?

Любой, кто интересуется ролью абстракции в программировании, должен изучить CLU .

интерпретатор JavaScript видит, что вы вызываете функцию getAge для объекта dave , поэтому он устанавливает this в dave и вызывает функцию getAge . getAge () правильно вернет 100 .


Возможно, вы знаете, что в JavaScript вы можете указать область действия с помощью метода apply . Давайте попробуем это.

var dave = new Person(new Date(1909, 1, 1)); //Age 100 in 2009
var bob = new Person(new Date(1809, 1, 1)); //Age 200 in 2009

dave.getAge.apply(bob); //returns 200.

В приведенной выше строке, вместо того, чтобы позволить JavaScript определять область действия, вы передаете область вручную как объект bob . getAge теперь будет возвращать 200 , даже если вы «думали», что вы вызывали getAge для объекта dave .


В чем смысл все вышеперечисленное? Функции «слабо» привязаны к вашим объектам JavaScript. Например, вы можете сделать

var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));

bob.getAge = function() { return -1; };

bob.getAge(); //returns -1
dave.getAge(); //returns 100

Пусть ' s сделать следующий шаг.

var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;

dave.getAge(); //returns 100;
ageMethod(); //returns ?????

ageMethod выполнение выдает ошибку! Что произошло?

Если вы внимательно прочтете мои пункты выше, то заметите, что метод dave.getAge был вызван с помощью dave как this объект, тогда как JavaScript мог не определять «область действия» для выполнения ageMethod . Таким образом, он передал глобальное «Окно» как «это». Теперь, поскольку окно не имеет свойства BirthDate , выполнение ageMethod завершится ошибкой.

Как это исправить? Просто,

ageMethod.apply(dave); //returns 100.

Все ли вышеперечисленное имело смысл? Если это так, то вы сможете объяснить, почему вы не можете использовать псевдоним document.getElementById :

var $ = document.getElementById;

$('someElement'); 

$ вызывается с окном как this , и если реализация getElementById ожидает , этот будет документ , он выйдет из строя.

Чтобы исправить это снова, вы можете сделать

$.apply(document, ['someElement']);

Так почему это работает в Internet Explorer?

Я не знаю внутренней реализации getElementById в IE, но комментарий в источнике jQuery (реализация метода inArray ) говорит, что в IE window == документ . В этом случае псевдоним document.getElementById должен работать в IE.

Чтобы проиллюстрировать это дальше, я создал подробный пример. Обратите внимание на функцию Person ниже.

function Person(birthDate)
{
    var self = this;

    this.birthDate = birthDate;

    this.getAge = function()
    {
        //Let's make sure that getAge method was invoked 
        //with an object which was constructed from our Person function.
        if(this.constructor == Person)
            return new Date().getFullYear() - this.birthDate.getFullYear();
        else
            return -1;
    };

    //Smarter version of getAge function, it will always refer to the object
    //it was created with.
    this.getAgeSmarter = function()
    {
        return self.getAge();
    };

    //Smartest version of getAge function.
    //It will try to use the most appropriate scope.
    this.getAgeSmartest = function()
    {
        var scope = this.constructor == Person ? this : self;
        return scope.getAge();
    };

}

Для функции Person выше, здесь '


var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias()); //Output: 100
console.log(ageSmartestAlias.apply(document)); //Output: 100

Функция ageSmartest будет использовать исходную область, если указана недопустимая область.


console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200

Вы все равно сможете передать другой объект Person в getAgeSmartest ]. :)

184
ответ дан 24 November 2019 в 09:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: