Javascript - застосувати функцію обрізки до кожного рядка в масиві


77

Хочете обрізати кожен рядок у масиві, наприклад, заданий

x = [' aa ', ' bb '];

вихід

['aa', 'bb']

Моє перше випробування -

x.map(String.prototype.trim.apply)

Він отримав "TypeError: Function.prototype.apply був викликаний невизначеним, що є невизначеним, а не функцією" в хромі.

Тоді я спробував

x.map(function(s) { return String.prototype.trim.apply(s); });

Це працює. Яка різниця?

Відповіді:


100

String.prototype.trim.applyє Function.prototype.applyметодом без прив'язки trim.mapбуде викликати його за допомогою рядка, індексу та масиву як аргументи та нічого ( undefined) для thisArg - однак, applyочікується , що його будуть викликати функції:

var apply = String.prototype.trim.apply;
apply.call(undefined, x[0], 0, x) // TypeError

Що ви можете зробити, це передати trimфункцію як контекст для call:

[' aa ', ' bb '].map(Function.prototype.call, String.prototype.trim)
// ['aa', 'bb']

Що тут відбувається

var call = Function.prototype.call,
    trim = String.prototype.trim;
call.call(trim, x[0], 0, x) ≡
      trim.call(x[0], 0, x) ≡
            x[0].trim(0, x); // the arguments don't matter to trim

1
Розумію. Я думав, що це funбуде мати те саме значення function(x) { return fun(x); }.
нейронт

Це не буде працювати на IE8: String.prototype.trim не працює з IE8.
Sachin Kainth

1
@SachinKainth: Питання не в обробці, OP вважає, що вона доступна. Якщо ви хочете спробувати фрагменти в IE8, вам, очевидно, потрібно буде обробляти trimі map.
Бергі

96

Або це можна вирішити за допомогою функцій стрілок:

x.map(s => s.trim());

9
Я пропоную:let trimedArr = oldArr.map(str => str.trim());
Flame_Phoenix

@Dominic Я використовую це, але коли я зменшую свій js того часу, це видасть помилку, яку я використовую сайт javascript-minifier.com для мініфікації js
Sachin Sarola

1
@SachinSarola виглядає так, що цей мініфікатор застарів із сучасним синтаксисом JS. Краще все-таки побудувати та зменшити свій JS як частину
Домінік

28

Якщо ви використовуєте JQuery, то кращий спосіб зробити це, оскільки він буде працювати і з IE8 (мені потрібно підтримати IE8), це:

$.map([' aa ', ' bb ', '   cc '], $.trim);

33
@ DenysSéguret "Якщо" - це ключове слово тут.
спалення

24

Простий варіант без залежностей:

 for (var i = 0; i < array.length; i++) {
     array[i] = array[i].trim()
 }

Варіант ES6:

const newArray = oldArray.map(string => string.trim())

Варіант функції ES6:

const trimmedArray = array => array.map(string => string.trim())

15

По-перше, зробіть це просто:

x.map(function(s) { return s.trim() });

Тоді, причина, по якій перший не працює, полягає в тому, що рядок передається як аргумент зворотного виклику, а не як контекст. Коли ви не передаєте жодного аргументу apply, ви отримуєте те саме повідомлення, що і з вами

var f = String.prototype.trim.apply; f.call();

Тепер, в основному для розваги, припустимо, ви не задоволені тим, що mapвикористовуєте зворотний виклик таким чином, і ви хочете мати можливість передавати функцію, використовуючи контекст, а не аргумент.

Тоді ви можете зробити це:

Object.defineProperty(Array.prototype, "maprec", {
  value: function(cb){
      return this.map(function(v){ return cb.call(v) })
  }
});
console.log([' aa ', ' bb '].maprec(String.prototype.trim)); // logs ["aa", "bb"]

Я сказав "в основному для розваги", оскільки модифікація об'єктів, якими ви не володієте (прототип Array тут), широко розглядається як погана практика. Але ви також можете зробити утилітарну функцію, приймаючи як аргумент як масив, так і зворотний виклик.


Ви маєте на увазі те саме повідомлення, яке ви отримали б, правда String.prototype.trim.apply.call()?
Butt4cak3

5

Я щойно порівняв деякі способи обрізки масиву рядків, щоб отримати найкоротший і швидкий метод. Кому цікаво, ось тест продуктивності на jsperf: http://jsperf.com/trim-array-of-strings

var chunks = "  .root  ,  .parent  >  .child  ".split(',')
var trimmed1 = chunks.map(Function.prototype.call, String.prototype.trim);
var trimmed2 = chunks.map(function (str) { return str.trim(); });
var trimmed3 = chunks.map(str => str.trim());
var trimmed4 = $.map(chunks, $.trim);

Примітка: jQuery тут, щоб порівняти кількість символів, що вводиться;)



3

Впливаючи на ідеальну відповідь Бергі, я хотів би лише додати, що для тих методів, які не беруть thisаргументів, ви можете виконати таку ж роботу, як показано нижче;

var x = [' aa ', ' bb '],
    y = x.map(Function.prototype.call.bind(String.prototype.trim))

Працювали дуже добре!
Санджай

1
var x = [" aa ", " bb "];
console.log(x); // => [" aa ", " bb "]

// remove whitespaces from both sides of each value in the array
x.forEach(function(value, index){
  x[index] = value.trim();
});

console.log(x); // => ["aa", "bb"]

Всі основні браузери підтримують forEach(), але зверніть увагу, що IEвін підтримує лише починаючи з версії 9.


-1

Ще одна альтернатива ES6

const row_arr = ['a ', ' b' , ' c ', 'd'];
const trimed_arr = row_arr.map(str => str.trim());
console.log(trimed_arr); // <== ['a', 'b', 'c', 'd']

array_map не є власною функцією JS і тут не визначена. => не працює.
musemind

@Greg перша версія цієї відповіді включала невизначений array_map()метод
musemind

@musemind Моя помилка - я мав би поглянути на редагування
Грег

-1
    ### Code
    <!-- language: lang-js -->

     var x=  [' aa ', ' b b ', '   c c ']
var x = x.split(",");
            x = x.map(function (el) {
                return el.trim();
                console.log(x)

    ### Output
    <!-- language: lang-none -->
        ["aa", "b b", "c c"]     

2
Будь ласка, розміщуйте свою відповідь завжди в контексті, а не просто вставляйте код. Детальніше див. Тут .
gehbiszumeis

1
Ви впевнені в цьому? Під час спроби використати ваш код виникає така помилка:TypeError: x.split is not a function
Ніко Хаасе,

### Спробуйте один раз цей код .... var x = ['aa', 'bb', 'cc'] var x = x.split (","); x = x.map (function (el) {return el.trim (); console.log (x)
koteswararao pv

### СПРОБУЙТИ var x = x.split (","); x = x.map (function (el) {return el.trim (); console.log (x)
koteswararao pv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.