何时使用 L.TileLayer 与 L.tileLayer

2022-01-12 00:00:00 leaflet javascript

我刚刚使用 Leaflet 为网站构建地图,并注意到添加 Tile Layer 至少可以使用两种方法,L.TileLayer()L.tileLayer(),名称的区别仅在于单个字符的大小写.

但是,虽然这两种方法返回的对象都可以添加到 L.map() 返回的地图对象中,但 L.TileLayer() 似乎没有 addTo() 方法,而 L.tileLayer() 返回的对象.例如.两者都有

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

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

还有

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

同时

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

失败.浏览 Leaflet 的文档,似乎使用正确的方法是 L.tileLayer() 那么问题是 L.TileLayer() 的用途是什么?p>

到目前为止,这是我的代码的完整示例,要尝试不同的替代方案,只需取消注释要测试的代码并确保其他代码已被注释

解决方案

TL;DR:

这两个都是有效且等价的:

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

这两个在语法上是有效的(因为 Javascript 的历史包袱)但最终会导致错误:

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


<块引用>

要添加一个 tilelayer,至少可以使用两种方法,L.TileLayer()L.tileLayer()

嗯,它们并不是真正的两个方法.技术上L.TileLayerObject的实例,L.tileLayerFunction的实例,继承Object 的原型.并且 L 充当命名空间而不是类实例.

你看,Javascript 中的面向对象编程是奇怪.您可以使用 new关键字 几乎包含任何具有原型的对象.而 基于原型的继承 让大多数人难以理解精通适当";哎呀.

如今,对于 ES2015 标准和花哨的 class 关键字,这并不是真正的问题(我会说这是一个问题,但隐藏在语法糖层之下).但在过去,开发人员不得不求助于,比如说,类继承的创造性解决方案 有时涉及弄乱原型链.

Leaflet 使用了这些方法的组合 - 作为一种不希望的副作用,L.TileLayer 变成了一个 Function 并且可以调用 L.TileLayer() 直接,这很混乱.

Leaflet 还使用了工厂函数的概念:返回类实例的函数.引用 传单教程之一:

<块引用>

大多数 Leaflet 类都有相应的工厂函数.工厂函数与类同名,但使用 lowerCamelCase 而不是 UpperCamelCase:

function myBoxClass(name, options) {返回新的 MyBoxClass(名称,选项);}

这只是为了方便:它使用户免于输入 new 关键字回到 害怕 关键字的时代>.

但这会产生另一个不受欢迎的副作用,因为在 Javascript 中,所有 Function 都有一个原型,这意味着您可以执行类似的操作

 函数 myFunction() { ... }var wtf = new myFunction();

因此,new L.tileLayer() 也是有效的语法(但在运行时失败).


<块引用>

那么L.TileLayer()有什么用呢?

再一次,L.TileLayer() 作为函数调用是一个不受欢迎的副作用.但是 L.TileLayer 代表一个类,因此引用它很重要,因为:

 if (layer instanceof L.TileLayer)

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>

解决方案

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)

相关文章