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 = 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属性扩展到C
17 var C = Util.extend(A, B);
18 
19 C.funA(); //A
20 C.funB(); //B
21 console.log(C.name); //山.鬼瑶
22 console.log(C.job); //web研发-js
23 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指向的是range
17 var boundCheckNumericRange = checkNumericRange.bind(range);
18 
19 // 用心新的函数检测12是否在数组范围内
20 var result = boundCheckNumericRange (12);
21 console.log(result); //true
22 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         else
10             return value >= this.minimum && value <= this.maximum;
11     }
12 }
13 
14 // 检测10是否在范围内,这次的this指向的是字面量originalObject
15 var result = originalObject.checkNumericRange(20);
16 console.log(result + " "); //false
17 
18 console.log(‘-------------调皮的分隔线------------------‘);
19 
20 var range = { 
21     minimum: 10, 
22     maximum: 20
23 };
24 // 构建一个新版的checkNumericRange
25 //这次的this指向的是range
26 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

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。