首页 > 代码库 > leaflet开源地图库源码研读(五)——extend、Object.create、fn.bind分析(Util.js文件)

leaflet开源地图库源码研读(五)——extend、Object.create、fn.bind分析(Util.js文件)

一、extend:扩展对象的属性

 1 var Util = { 2     extend: function (dest) { 3         var i, j, len, src; 4         for (j = 1, len = arguments.length; j < len; j++) { 5             src =http://www.mamicode.com/ arguments[j]; 6             for (i in src) { 7                 dest[i] = src[i]; 8             } 9         }10         return dest;11     }12 }

可以,看出extend方法里有2个for循环,具体的作用一看便知:第一个是拿到所有参数,第二个是遍历当前参数对象的属性并作为目标对象的属性。代码j = 1还是很明智的,减少只传一个对象时的循环。对extend如何使用举个例子:

 1 var A = { 2     name: ‘山.鬼瑶‘, 3     funA: function(){ 4         console.log(‘A‘); 5     }, 6     funB: function(){ 7         console.log(‘B‘); 8     } 9 };10 var B = {11     job: ‘web研发-js‘,12     show: function(){13         console.log(‘前端工程浩大,孜孜不倦,孜孜不倦‘);14     }15 };16 //将A、B属性扩展到C17 var C = Util.extend(A, B);18 19 C.funA(); //A20 C.funB(); //B21 console.log(C.name); //山.鬼瑶22 console.log(C.job); //web研发-js23 C.show(); //前端工程浩大,孜孜不倦,孜孜不倦

 

结果如上图所示,那么这个C扩展了A、B的属性作为自己的属性,因此,extend函数的作用有:

(1)扩展一个对象的属性和方法;

(2)在grunt压缩中,为了防止prototype被压缩丢失(因为带“”的属性,可能不会被当做引用,grunt压缩后,会存在丢失),可以采用extend(A.prototype)的形式引用一遍。

二、create:创建一个对象并赋原型,原型继承

1 create: Object.create || (function () {2         function F() {}3         return function (proto) {4             F.prototype = proto;5             return new F();6         };7     })()

create方法用了2个函数,一个是Object.create ( 即Object.create(prototype, descriptors)、另一个是及时函数(立即执行)。Object.create已经很明显了,是初始化一个带原型属性的对象。及时函数中,构建了一个F的对象,然后将外部传递的对象,作为F的原型。这个典型的应用场景就是原型继承,如下:

1 var B = {};2 B.prototype ={3     test: function(){4         console.log(‘b protoype: test‘);5     }6 };7 8 var C = Util.create(B.prototype);9 C.test(); //b protoype: test

三、bind:将指定的对象及上下文绑定到函数

首先,来看一下原生的bind:

 1 // 定义原始的函数 2 var checkNumericRange = function (value) { 3     console.log(this); 4     if (typeof value !== ‘number‘) 5         return false; 6     else 7         return value >= this.minimum && value <= this.maximum; 8 } 9 10 checkNumericRange(25); //此时,checkNumericRange是全局对象window的实例11 12 console.log(‘---------------调皮的分隔符------------------‘);13 // 取值范围对象14 var range = { minimum: 10, maximum: 20 };15 // 绑定checkNumericRange对象16 // this指向的是range17 var boundCheckNumericRange = checkNumericRange.bind(range);18 19 // 用心新的函数检测12是否在数组范围内20 var result = boundCheckNumericRange (12);21 console.log(result); //true22 console.log(boundCheckNumericRange(24)); //false

可以,看出bind可以改变函数内部的this指向,同时绑定函数。再来看一个例子,对bind理解就会更加深入了:

 1 //重新创建一个对象,包含checkNumericRange方法 2 var originalObject = { 3     minimum: 50, 4     maximum: 100, 5     checkNumericRange: function (value) { 6         console.log(this); 7         if (typeof value !== ‘number‘) 8             return false; 9         else10             return value >= this.minimum && value <= this.maximum;11     }12 }13 14 // 检测10是否在范围内,这次的this指向的是字面量originalObject15 var result = originalObject.checkNumericRange(20);16 console.log(result + " "); //false17 18 console.log(‘-------------调皮的分隔线------------------‘);19 20 var range = { 21     minimum: 10, 22     maximum: 2023 };24 // 构建一个新版的checkNumericRange25 //这次的this指向的是range26 var boundObjectWithRange = originalObject.checkNumericRange.bind(range);27 28 // 检测10是否在范围内29 var result = boundObjectWithRange(10);30 console.log(result); //true

再来看一下绑定函数作为3、4参数传递的例子:

 1 var displayArgs = function (val1, val2, val3, val4) { 2     console.log(val1 + " " + val2 + " " + val3 + " " + val4); 3 } 4  5 var emptyObject = {}; 6  7 //将12 和 a作为第一个和第二个参数传入 8 var displayArgs2 = displayArgs.bind(emptyObject, 12, "a"); 9 10 //将b c作为第三第四个参数传入11 displayArgs2("b", "c"); //12 a b c

那么问题就来了,如何写出像蓝翔挖掘机一样的bind呢?代码如下:

 1 bind: function (fn, obj) { 2         var slice = Array.prototype.slice; 3         //ES5给function增加了bind方法,没有的话就模拟bind方法 4         if (fn.bind) { 5             //slice.call(arguments, 1):拿到obj之后的参数作为数组 6             return fn.bind.apply(fn, slice.call(arguments, 1)); 7         } 8          9         var args = slice.call(arguments, 2);10         return function () {11             return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);12         };13     }

调用:

var test = Util.bind(function(){    console.log(this.a  + this.b);}, {a: 3, b:4});test(); //7

 

leaflet开源地图库源码研读(五)——extend、Object.create、fn.bind分析(Util.js文件)