when to use L.TileLayer vs L.tileLayer

允我心安 提交于 2020-07-03 03:49:29

问题


I have just been using Leaflet to build a map for a website and noticed that to add a Tile Layer at least two methods can be used, L.TileLayer() and L.tileLayer(), differing in their name only by the case of a single character.

However, while the object returned by both of these methods can be added to a map object returned by L.map() the object returned by L.TileLayer() does not seem to have the addTo() method whilst the object returned byL.tileLayer(). E.g. both

var map = L.map('map');
var tiles = new L.TileLayer(<tileUrl>, {attribution: <tileAttrib>});
map.addLayer(tiles);

and

var map = L.map('map');
var tiles = new L.tileLayer(<tileUrl>, {attribution: <tileAttrib>});
map.addLayer(tiles);

as well as

var map = L.map('map');
L.tileLayer(<tileUrl>, {attribution: <tileAttrib>}).addTo(map);

whilst

var map = L.map('map');
L.TileLayer(<tileUrl>, {attribution: <tileAttrib>}).addTo(map);

fails. Browsing the documentation of Leaflet it seems the proper method to use is L.tileLayer() so the question then is what is the use of L.TileLayer()?

Here's a full example of my code so far, to try the different alternatives simply uncomment the one to test and make sure the others are commented

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
        
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
   <head>
      <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/>
      <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
      
      <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.3/dist/leaflet.css"
            integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ=="
            crossorigin=""/>
      <script src="https://unpkg.com/leaflet@1.3.3/dist/leaflet.js"
            integrity="sha512-tAGcCfR4Sc5ZP5ZoVz0quoZDYX5aCtEm/eu1KhSLj2c9eFrylXZknQYmxUssFaVJKvvc0dJQixhGjG2yXWiV9Q=="
            crossorigin=""> </script>
   </head>
   <body onload="makeMap()">
      <script type="text/javascript">
         function makeMap() {
            var tileUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
            var tileAttrib = 'Map data &copy <a href="https://openstreetmap.org">OpenStreetMap</a> contributors'; 
            var map = L.map('map').setView([63,15],9);
            
            // using tileLayer and addLayer - this works
            var tiles = new L.tileLayer(tileUrl, {attribution: tileAttrib});
            map.addLayer(tiles);
            
            // using tileLayer and addTo - this works
//             L.tileLayer(tileUrl, {attribution: tileAttrib}).addTo(map);
            
            // using TileLayer and addLayer - this works
//             var tiles = new L.TileLayer(tileUrl, {attribution: tileAttrib});
//             map.addLayer(tiles);
            
            // using TileLayer and addTo - this fails
//             L.TileLayer(tileUrl, {attribution: tileAttrib}).addTo(map);
         }
         
      </script>
      <table border=1 style="position: absolute; top: 0; bottom: 0; left: 0; right: 0; width: 100%; height: 100%;">
         <tr style="height: 100%;">
            <td>
               <div id="map" style="width: 100%; height: 100%;"></div>
            </td>
         </tr>
      </table>
   </body>
</html>

回答1:


TL;DR:

These two are both valid and equivalent:

var foo = L.tileLayer(arguments);
var foo = new L.TileLayer(arguments);

These two are syntactically valid (because of Javascript's historical baggage) but will ultimately result in errors:

var foo = new L.tileLayer(arguments);
var foo = L.TileLayer(arguments);

to add a tilelayer at least two methods can be used, L.TileLayer() and L.tileLayer()

Well, they're not really two methods. Technically L.TileLayer is an instance of Object, and L.tileLayer is an instance of Function, which inherits the prototype of Object. And L acts as a namespace rather than a class instance.

You see, Object-Oriented Programming in Javascript is weird. You can use the new keyword with pretty much any object which has a prototype. And prototype-based inheritance is confusing to grasp to most people versed in "proper" OOP.

Nowadays, with the ES2015 standards and the fancy class keywords this is not really a problem (I'd say it's a problem, but hidden under layers of syntactic sugar). But back in the day, developers had to resort to, let's say, creative solutions for class inheritance which sometimes involves messing with the prototype chain.

Leaflet uses a combination of such methods - and as an undesired side effect, L.TileLayer becomes a Function and one can call L.TileLayer() directly and that's quite confusing.

Leaflet also uses the concept of factory functions: A function that returns an instance of a class. Quoting from one of the Leaflet tutorials:

Most Leaflet classes have a corresponding factory function. A factory function has the same name as the class, but in lowerCamelCase instead of UpperCamelCase:

function myBoxClass(name, options) {
    return new MyBoxClass(name, options);
}

This is meant just as a convenience: it saves the user from typing the new keyword back in an era where the new keyword was feared.

But this creates another undesired side effect, because in Javascript all Functions have a prototype, which means that you can do stuff like

 function myFunction() { ... }
 var wtf = new myFunction();

Therefore, new L.tileLayer() is also valid syntax (but fails at runtime).


then what is the use of L.TileLayer()?

Once again, L.TileLayer() as a function call is an undesired side effect. But L.TileLayer represents a class and it's important to have a reference to that, because of things like:

 if (layer instanceof L.TileLayer)


来源:https://stackoverflow.com/questions/51861013/when-to-use-l-tilelayer-vs-l-tilelayer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!