Function native code что за файл
Перейти к содержимому

Function native code что за файл

  • автор:

Встроенные прототипы

Свойство «prototype» широко используется внутри самого языка JavaScript. Все встроенные функции-конструкторы используют его.

Сначала мы рассмотрим детали, а затем используем «prototype» для добавления встроенным объектам новой функциональности.

Object.prototype

Давайте выведем пустой объект:

let obj = <>; alert( obj ); // "[object Object]" ?

Где код, который генерирует строку «[object Object]» ? Это встроенный метод toString , но где он? obj ведь пуст!

…Но краткая нотация obj = <> – это то же самое, что и obj = new Object() , где Object – встроенная функция-конструктор для объектов с собственным свойством prototype , которое ссылается на огромный объект с методом toString и другими.

Вот что происходит:

Другие встроенные объекты устроены аналогично. Даже функции – они объекты встроенного конструктора Function , и все их методы ( call / apply и другие) берутся из Function.prototype . Также у функций есть свой метод toString .

function f() <> alert(f.__proto__ == Function.prototype); // true alert(f.__proto__.__proto__ == Object.prototype); // true, наследует от Object

Примитивы

Самое сложное происходит со строками, числами и булевыми значениями.

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

Эти объекты создаются невидимо для нас, и большая часть движков оптимизирует этот процесс, но спецификация описывает это именно таким образом. Методы этих объектов также находятся в прототипах, доступных как String.prototype , Number.prototype и Boolean.prototype .

Значения null и undefined не имеют объектов-обёрток

Специальные значения null и undefined стоят особняком. У них нет объектов-обёрток, так что методы и свойства им недоступны. Также у них нет соответствующих прототипов.

Изменение встроенных прототипов

Встроенные прототипы можно изменять. Например, если добавить метод к String.prototype , метод становится доступен для всех строк:

String.prototype.show = function() < alert(this); >; "BOOM!".show(); // BOOM!

В течение процесса разработки у нас могут возникнуть идеи о новых встроенных методах, которые нам хотелось бы иметь, и искушение добавить их во встроенные прототипы. Это плохая идея.

Прототипы глобальны, поэтому очень легко могут возникнуть конфликты. Если две библиотеки добавляют метод String.prototype.show , то одна из них перепишет метод другой.

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

В современном программировании есть только один случай, в котором одобряется изменение встроенных прототипов. Это создание полифилов.

Полифил – это термин, который означает эмуляцию метода, который существует в спецификации JavaScript, но ещё не поддерживается текущим движком JavaScript.

Тогда мы можем реализовать его сами и добавить во встроенный прототип.

if (!String.prototype.repeat) < // Если такого метода нет // добавляем его в прототип String.prototype.repeat = function(n) < // повторить строку n раз // на самом деле код должен быть немного более сложным // (полный алгоритм можно найти в спецификации) // но даже неполный полифил зачастую достаточно хорош для использования return new Array(n + 1).join(this); >; > alert( "La".repeat(3) ); // LaLaLa

Заимствование у прототипов

В главе Декораторы и переадресация вызова, call/apply мы говорили о заимствовании методов.

Это когда мы берём метод из одного объекта и копируем его в другой.

Некоторые методы встроенных прототипов часто одалживают.

Например, если мы создаём объект, похожий на массив (псевдомассив), мы можем скопировать некоторые методы из Array в этот объект.

let obj = < 0: "Hello", 1: "world!", length: 2, >; obj.join = Array.prototype.join; alert( obj.join(',') ); // Hello,world!

Это работает, потому что для внутреннего алгоритма встроенного метода join важны только корректность индексов и свойство length , он не проверяет, является ли объект на самом деле массивом. И многие встроенные методы работают так же.

Альтернативная возможность – мы можем унаследовать от массива, установив obj.__proto__ как Array.prototype , таким образом все методы Array станут автоматически доступны в obj .

Но это будет невозможно, если obj уже наследует от другого объекта. Помните, мы можем наследовать только от одного объекта одновременно.

Заимствование методов – гибкий способ, позволяющий смешивать функциональность разных объектов по необходимости.

Итого

  • Все встроенные объекты следуют одному шаблону:
    • Методы хранятся в прототипах ( Array.prototype , Object.prototype , Date.prototype и т.д.).
    • Сами объекты хранят только данные (элементы массивов, свойства объектов, даты).

    Задачи

    Добавить функциям метод «f.defer(ms)»

    важность: 5

    Добавьте всем функциям в прототип метод defer(ms) , который вызывает функции через ms миллисекунд.

    После этого должен работать такой код:

    function f() < alert("Hello!"); >f.defer(1000); // выведет "Hello!" через 1 секунду

    Как в JavaScript определить, является ли функция нативной

    Время от времени мне приходится проверять, является ли та или иная функция нативной — это важная часть проверки, была ли функция предоставлена браузером или это порождение постороннего шима, замаскированное под встроенный компонент. Лучший способ выполнения такой проверки — это, конечно же, оценка значения toString , возвращённого функцией.

    JavaScript

    Код, требуемый для этого, довольно прост:

    function isNative(fn) < return (/\/).test('' + fn); > 

    Вся суть состоит в том, чтобы конвертировать функцию в строчное представление и выполнить сопоставление строки с регулярными выражениями. Лучшего способа подтвердить, что это нативная функция, не существует!

    Обновление!

    Создатель библиотеки lodash, Джон-Дэвид Далтон (John-David Dalton), предложил лучшее решение:

    ;(function( ) < // Используется для разложения на составляющие внутреннего `[[Class]]` значений var toString = Object.prototype.toString; // Используется для разложения на составляющие декомпилированного // исходного кода функции var fnToString = Function.prototype.toString; // Используется для определения конструкторов среды (Safari > 4; // по сути, предназначено специально для типизированных массивов) var reHostCtor = /^\[object .+?Constructor\]$/; // Составление регулярного выражения на основе часто употребляемого // нативного метода в качестве шаблона. // Выбираем `Object#toString`, так как вполне вероятно, что он ещё не задействован. var reNative = RegExp('^' + // Применяем `Object#toString` к строке String(toString) // Избавляемся от любых специальных символов регулярных выражений .replace(/[.*+?^$<>()|[\]\/\\]/g, '\\$&') // Заменяем упоминания `toString` на `.*?`, чтобы сохранить обобщённый вид шаблона. // Заменяем `for . ` и тому подобное для поддержки окружений вроде Rhino, // которые добавляют дополнительную информацию, такую как арность метода. .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); function isNative(value) < var type = typeof value; return type == 'function' // Используем `Function#toString`, чтобы обойти собственный метод // `toString` самого значения и избежать ложного результата. ? reNative.test(fnToString.call(value)) // На всякий случай выполняем проверку на наличие объектов среды, так // как некоторые окружения могут представлять компоненты вроде // типизированных массивов как методы DOM, что может не соответствовать // нормальному нативному паттерну. : (value && type == 'object' && reHostCtor.test(toString.call(value))) || false; > // экспортируем в удобном для вас виде module.exports = isNative; >()); 

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

    Добавление кода в нативные функции

    То есть при вызове Math.pow(1,2); в консоль пишется ‘USE: Math.pow’ и возвращается 100500 . Надо сделать так, чтобы функция писала в консоль и продолжала свою «правильную» работу. Я пишу «юзерскрипт» и хочу знать какие методы использует сайт. Не все, конечно, а, например, только из Math .

    for (var i in Math ) < eval('Math.__defineGetter__( "' + i + '", function() < console.log( "USE Math.' + i + '" ); return 1; >);'); > 

    Сейчас я могу это узнать, в консоль всё пишет, но функции не работают и вызывают ошибки.
    Отслеживать
    19.1k 6 6 золотых знаков 30 30 серебряных знаков 44 44 бронзовых знака
    задан 24 июн 2015 в 13:02
    wolter_white wolter_white
    295 2 2 серебряных знака 12 12 бронзовых знаков

    1 ответ 1

    Сортировка: Сброс на вариант по умолчанию

    Простой пример с Math.pow() для демонстрации идеи:

    var savedPow = Math.pow; Math.pow = function(number, exp) < console.log('USE: Math.pow'); return savedPow(number, exp); >; console.log(Math.pow(10, 3));

    Отслеживать
    ответ дан 24 июн 2015 в 13:11
    19.1k 6 6 золотых знаков 30 30 серебряных знаков 44 44 бронзовых знака
    Спасибо 🙂 Буду делать исходя из Вашего кода!
    24 июн 2015 в 13:56

    @wolter_white на здоровье. for (var key in Math ) < . >у меня почему-то не работает, поэтому полный пример не сделаю. Единственное что могу ещё сказать — вместо передачи number и exp можно в saved передавать просто массив arguments . Пример в fiddle. Так сказать, универсальный вариант для всех функций.

    Что возвращает нам fetch и как можно им правильней пользоваться?

    Что полезного можно получить из fetch и почему, чтобы получить данные, нужно вызвать метод json , а не получать по умолчанию данные, которые уже в любом другом месте могли бы обработать через JSON.parse(data) ?
    Да и в целом, почему его назвали json, если мы получаем в итоге уже обработанный объект данных, а не сам json?

    [object Response] < arrayBuffer: function arrayBuffer() < [native code] >, blob: function blob() < [native code] >, body: [object ReadableStream] < cancel: function cancel() < [native code] >, getReader: function getReader() < [native code] >, locked: false, pipeThrough: function pipeThrough() < [native code] >, pipeTo: function pipeTo() < [native code] >, tee: function tee() < [native code] >>, bodyUsed: false, clone: function clone() < [native code] >, formData: function formData() < [native code] >, headers: [object Headers] < append: function append() < [native code] >, delete: function delete() < [native code] >, entries: function entries() < [native code] >, forEach: function forEach() < [native code] >, get: function get() < [native code] >, has: function has() < [native code] >, keys: function keys() < [native code] >, set: function set() < [native code] >, values: function values() < [native code] >>, json: function json() < [native code] >, ok: true, redirected: false, status: 200, statusText: "", text: function text() < [native code] >, type: "cors", url: "https://jsonplaceholder.typicode.com/todos/1" >
    • Вопрос задан более года назад
    • 255 просмотров

    3 комментария

    Простой 3 комментария

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *