2016-12-14 8 views
1

Это учебник по магистрали. Вот код:Что делает функция «без» в коллекции?

<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="UTF-8"> 
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 
    <title>To-do App in Backbone.js</title> 

    <!-- ========= --> 
    <!-- CSS --> 
    <!-- ========= --> 
    <style type="text/css"> 
    #todoapp ul { 
     list-style-type: none; /* Hides bullet points from todo list */ 
    } 
    #todo-list input.edit { 
     display: none; /* Hides input box*/ 
    } 
    #todo-list .editing label { 
     display: none; /* Hides label text when .editing*/ 
    } 
    #todo-list .editing input.edit { 
     display: inline; /* Shows input text box when .editing*/ 
    } 
    </style> 
</head> 
<body> 
    <!-- ========= --> 
    <!-- Your HTML --> 
    <!-- ========= --> 

    <section id="todoapp"> 
    <header id="header"> 
     <h1>Todos</h1> 
     <input id="new-todo" placeholder="What needs to be done?" autofocus> 
     <div> 
     <a href="#/">show all</a> | 
     <a href="#/pending">show pending</a> | 
     <a href="#/completed">show completed</a> 
     </div> 
    </header> 
    <section id="main"> 
     <ul id="todo-list"></ul> 
    </section> 
    </section> 
    <div> 
    <p>Find the tutorial and code in <a href="http://adrianmejia.com/blog/2012/09/11/backbone-dot-js-for-absolute-beginners-getting-started/">here</a></p> 
    </div> 

    <!-- Templates --> 
    <script type="text/template" id="item-template"> 
    <div class="view"> 
     <input class="toggle" type="checkbox" <%= completed ? 'checked' : '' %>> 
     <label><%- title %></label> 
     <input class="edit" value="<%- title %>"> 
     <button class="destroy">remove</button> 
    </div> 
    </script> 

    <!-- ========= --> 
    <!-- Libraries --> 
    <!-- ========= --> 
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script> 
    <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js" type="text/javascript"></script> 
    <script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js" type="text/javascript"></script> 
    <script src="http://cdnjs.cloudflare.com/ajax/libs/backbone-localstorage.js/1.0/backbone.localStorage-min.js" type="text/javascript"></script> 

    <!-- =============== --> 
    <!-- Javascript code --> 
    <!-- =============== --> 
    <script type="text/javascript"> 
    'use strict'; 

    var app = {}; // create namespace for our app 

    //-------------- 
    // Models 
    //-------------- 
    app.Todo = Backbone.Model.extend({ 
     defaults: { 
     title: '', 
     completed: false 
     }, 
     toggle: function(){ 
     this.save({ completed: !this.get('completed')}); 
     } 
    }); 

    //-------------- 
    // Collections 
    //-------------- 
    app.TodoList = Backbone.Collection.extend({ 
     model: app.Todo, 
     localStorage: new Store("backbone-todo"), 
     completed: function() { 
     return this.filter(function(todo) { 
      return todo.get('completed'); 
     }); 
     }, 
     remaining: function() { 
     debugger; 
     return this.without.apply(this, this.completed()); 
     } 
    }); 

    // instance of the Collection 
    app.todoList = new app.TodoList(); 

    //-------------- 
    // Views 
    //-------------- 

    // renders individual todo items list (li) 
    app.TodoView = Backbone.View.extend({ 
     tagName: 'li', 
     template: _.template($('#item-template').html()), 
     render: function(){ 
     this.$el.html(this.template(this.model.toJSON())); 
     this.input = this.$('.edit'); 
     return this; // enable chained calls 
     }, 
     initialize: function(){ 
     this.model.on('change', this.render, this); 
     this.model.on('destroy', this.remove, this); // remove: Convenience Backbone's function for removing the view from the DOM. 
     }, 
     events: { 
     'dblclick label' : 'edit', 
     'keypress .edit' : 'updateOnEnter', 
     'blur .edit' : 'close', 
     'click .toggle': 'toggleCompleted', 
     'click .destroy': 'destroy' 
     }, 
     edit: function(){ 
     this.$el.addClass('editing'); 
     this.input.focus(); 
     }, 
     close: function(){ 
     var value = this.input.val().trim(); 
     if(value) { 
      this.model.save({title: value}); 
     } 
     this.$el.removeClass('editing'); 
     }, 
     updateOnEnter: function(e){ 
     if(e.which == 13){ 
      this.close(); 
     } 
     }, 
     toggleCompleted: function(){ 
     this.model.toggle(); 
     }, 
     destroy: function(){ 
     this.model.destroy(); 
     } 
    }); 

    // renders the full list of todo items calling TodoView for each one. 
    app.AppView = Backbone.View.extend({ 
     el: '#todoapp', 
     initialize: function() { 
     this.input = this.$('#new-todo'); 
     app.todoList.on('add', this.addAll, this); 
     app.todoList.on('reset', this.addAll, this); 
     app.todoList.fetch(); // Loads list from local storage 
     }, 
     events: { 
     'keypress #new-todo': 'createTodoOnEnter' 
     }, 
     createTodoOnEnter: function(e){ 
     if (e.which !== 13 || !this.input.val().trim()) { // ENTER_KEY = 13 
      return; 
     } 
     app.todoList.create(this.newAttributes()); 
     this.input.val(''); // clean input box 
     }, 
     addOne: function(todo){ 
     var view = new app.TodoView({model: todo}); 
     $('#todo-list').append(view.render().el); 
     }, 
     addAll: function(){ 
     this.$('#todo-list').html(''); // clean the todo list 
     // filter todo item list 
     switch(window.filter){ 
      case 'pending': 
      _.each(app.todoList.remaining(), this.addOne); 
      break; 
      case 'completed': 
      _.each(app.todoList.completed(), this.addOne); 
      break; 
      default: 
      app.todoList.each(this.addOne, this); 
      break; 
     } 
     }, 
     newAttributes: function(){ 
     return { 
      title: this.input.val().trim(), 
      completed: false 
     } 
     } 
    }); 

    //-------------- 
    // Routers 
    //-------------- 

    app.Router = Backbone.Router.extend({ 
     routes: { 
     '*filter' : 'setFilter' 
     }, 
     setFilter: function(params) { 
     console.log('app.router.params = ' + params); 
     window.filter = params.trim() || ''; 
     app.todoList.trigger('reset'); 
     } 
    }); 

    //-------------- 
    // Initializers 
    //-------------- 

    app.router = new app.Router(); 
    Backbone.history.start(); 
    app.appView = new app.AppView(); 

    </script> 

</body> 
</html> 

Что эта линия делает:

remaining: function() { 
     return this.without.apply(this, this.completed()); 
     } 

Что это делает?

without от underscore, но что такое apply? Кроме того, я поставил отладчик выше этой линии внутри анонимной функции, и это была ошибка:

this.apply(this, this.copmleted()); 

Почему не работает? Что такое apply?

ответ

3

Без

Backbone Collection's underscore methods

Backbone proxies to Underscore.js to provide 46 iteration functions on Backbone.Collection.

this.without такая же, как _.without применяется на самой коллекции.

Подробнее detailed answer об этом.

Применить

apply является функцией от прототипа Function (в спецификации JavaScript). Он принимает контекст как первый аргумент (в этом случае) и объект типа массива, определяющий аргументы, с которыми должна вызываться функция.

контексте - значение this внутри функции; это объект, по которому функция будет выполнять свою логику.

this.completed() возвращает массив, но this.without нуждается в каждом аргументе, переданном отдельно. Например:

this.without(1, 2, 3, 4, 6, 78); 

Раскатать массив, возвращаемый this.completed() в списке аргументов, .apply могут быть использованы:

this.without.apply(this, [completedModel1, completedModel2, /* etc. */]); 
+0

является основной причиной применить здесь, чтобы вызвать метод 'without' с отдельными аргументами ? Является ли этот контекст избыточным? – Jwan622

+0

@ Jwan622 да, это точно цель 'apply'. Вы часто увидите трюки, которые используют 'apply' для использования массива в качестве аргументов функций. 'this' выглядит излишним, но' apply' переопределяет контекст, поэтому, если вы передадите 'null' в качестве контекста,' this' не будет сборкой. –