polyfill,shim,shiv之间有什么区别?

什么是polyfill和shim

搜索了一下:在JavaScript的世界里,有两个词经常被提到,shim和polyfill.它们指的都是什么,又有什么区别?一个shim是一个库,它将一个新的API引入到一个旧的环境中,而且仅靠旧环境中已有的手段实现;一个polyfill就是一个用在浏览器API上的shim.我们通常的做法是先检查当前浏览器是否支持某个API,如果不支持的话就加载对应的polyfill.然后新旧浏览器就都可以使用这个API了。

皓眸大前端开发学习

理解

一个shim就是一个库,它将一个新的API引入到一个旧的环境中,而且仅靠旧环境中已有的手段实现。
比如ES5-shim, github地址:http://github.com/es-shims/es5-shim/

这几天看了一下shiv,它的作用是使得不支持HTML5标签的浏览器诸如ie6-8, 支持html5标签。这也是我在看html语义化规范的时候看到的,觉得很有必要做一下。目前使用IE8的用户还是占据一部分比例的,所以为了兼容ie8,同时能使用像header、section、nav、footer这些语义化标签,我们可以采用shiv库来实现。
著名的HTML5兼容库html5shiv,Github地址:https://github.com/aFarkas/html5shiv

关于polyfill,据说来自于Polyfilla,Polyfilla是一个英国产品,在美国称之为Spackling Paste(译者注:刮墙的,在中国称为腻子),把旧的浏览器想象成为一面有了裂缝的墙,这些polyfill会帮助我们把这面墙的裂缝抹平。

其实一个polyfill的意思就是,比如开发者想要一个格式化时间的函数,然后现有的api都没有,于是作者自创一个stringDate的方法,那么这个方法就成为一个polyfill。

问题

注意在实现polyfill的时候,最好不要在一些原生对象的原型上添加方法,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (!Array.prototype.find) {
Array.prototype.find = function (predicate) {
if (this === null)
throw new TypeError('Array.prototype.find called on null or undefined');
if (typeof predicate !== 'function')
throw new TypeError('predicate must be a function');
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list))
return value;
}
}
}

在IE下面有个bug,就是在使用 for in 这种循环的时候,ie下会遍历输出原型链上的方法,比如:

1
2
3
4
5
6
7
8
var a = [1,2];
for(var i in a){
console.log(i);
}
//output
1
2
find

这就会导致bug。
查了一下can1use:

1
2
3
4
As the specification includes many JavaScript features, un-numbered partial support varies widely and is shown in detail on the ECMAScript 5 compatibilty tables by Kangax.
Does not support parseInt() ignoring leading zeros.
Does not support Strict mode
IE8 has virtually no ES5 support, but does support Object.defineProperty, Object.getOwnPropertyDescriptor, JSON parsing & Property access on strings

也就是说,在IE8下面支持Object.defineProperty这个方法,这个方法是直接给一个对象添加一个属性, 关键是可以控制是否能在for…in循环中遍历出来或在Object.keys中列举出来。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Object.defineProperty(obj, prop, descriptor)将属性添加到对象,或修改现有属性的特性。
参数:
obj:目标对象
prop:需要定义的属性或方法的名字。
descriptor:目标属性所拥有的特性。
可供定义的特性列表:
value:属性的值
writable:如果为false,属性的值就不能被重写。
get: 一旦目标属性被访问就会调回此方法,并将此方法的运算结果返回用户。
set:一旦目标属性被赋值,就会调回此方法。
configurable:如果为false,则任何尝试删除目标属性或修改属性以下特性(writable, configurable, enumerable)的行为将被无效化。
enumerable:是否能在for...in循环中遍历出来或在Object.keys中列举出来。
try{
var a = {};
Object.defineProperty(a,"bloger",{get:function(){return "司徒正美",value:"这是不可改变的默认值" ,writable: false}});
alert(a.bloger)
}catch(e){
alert("你的游览器不支持Object.defineProperty ")
}

所以我们可以通过这个方式修改Array.prototype,简单的实现方式:

1
Object.defineProperty(Array.prototype,"findT",{value:function(){return 1;}});

参考es5-shim中有一个自定义的defineProperties方法,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var defineProperties = (function (has) {
// Define configurable, writable, and non-enumerable props
// if they don't exist.
var defineProperty;
if (supportsDescriptors) {
defineProperty = function (object, name, method, forceAssign) {
if (!forceAssign && (name in object)) { return; }
$Object.defineProperty(object, name, {
configurable: true,
enumerable: false,
writable: true,
value: method
});
};
} else {
defineProperty = function (object, name, method, forceAssign) {
if (!forceAssign && (name in object)) { return; }
object[name] = method;
};
}
return function defineProperties(object, map, forceAssign) {
for (var name in map) {
if (has.call(map, name)) {
defineProperty(object, name, map[name], forceAssign);
}
}
};
}(ObjectPrototype.hasOwnProperty));

其实Object也是有defineProperties函数的,只是ie8不支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Object.defineProperties 函数 (JavaScript)
将一个或多个属性添加到对象,并/或修改现有属性的特性。
Object.defineProperties(obj, {
newDataProperty: {
value: 101,
writable: true,
enumerable: true,
configurable: true
},
newAccessorProperty: {
set: function (x) {
document.write("in property set accessor" + newLine);
this.newaccpropvalue = x;
},
get: function () {
document.write("in property get accessor" + newLine);
return this.newaccpropvalue;
},
enumerable: true,
configurable: true
}});

谢谢!

转载请注明出处:http://www.haomou.net/2016/10/22/2016_polyfill_shim/
欢迎关注皓眸学问公众号(扫描左侧二维码),每天好文、新技术!任何学习疑问或者工作问题都可以给我留言、互动。T_T 皓眸大前端开发学习 T_T