可以看到⽗窗⼝的判断是正确的,⽽⼦窗⼝的判断是false,因此⼀个变量明明是Array,但却不是Array,这是为什么呢?既然这个是⽗⼦
这次返回了true,然后再变换⼀下其它的判断,如上图,最后可以知道根本原因是上图最后⼀个判断:
Array !== window.parent.Array
它们分别是两个函数,⽗窗⼝定义了⼀个,⼦窗⼝⼜定义了⼀个,内存地址不⼀样,内存地址不⼀样的Object等式判断不成⽴,⽽window.structor返回的是⽗窗⼝的Array,⽐较的时候是在⼦窗⼝,使⽤的是⼦窗⼝的Array,这两个Array不相等,所以导致判断不成⽴。
那怎么办呢?
由于不能使⽤Object的内存地址判断,可以使⽤字符串的⽅式,因为字符串是基本类型,字符串⽐较只要每个字符都相等就好了。ES5提供了这么⼀个⽅法String,我们先⼩试⽜⼑,试⼀下不同变量的返回值:
也就是说这个函数的返回值是“[object ”开头,后⾯带上变量类型的名称和右括号。因此既然它是⼀个标准语法规范,所以可以⽤这个函数安全地判断变量是不是数组。
可以这么写:
String.call([1, 2, 3]) ===
"[object Array]"
注意要使⽤call,⽽不是直接调⽤,call的第⼀个参数是context执⾏上下⽂,把数组传给它作为执⾏上下⽂。
有⼀个⽐较有趣的现象是ES6的class也是返回function:
所以可以知道class也是⽤function实现的原型,也就是说class和function本质上是⼀样的,只是写法上不⼀样。
本页⾯的变量还是可以那是不是说不能再使⽤instanceof判断变量类型了?不是的,当你需要检测⽗页⾯的变量类型就得使⽤这种⽅法,本页⾯的变量还是可以使⽤instanceof或者constructor的⽅法判断,只要你能确保这个变量不会跨页⾯。因为对于⼤多数⼈来说,很少会写iframe的代码,使⽤instanceof或者constructor的⽅法判断
所以没有必要搞⼀个⽐较⿇烦的⽅式,还是⽤简单的⽅式就好了。
2. 惰性载⼊函数
有时候需要在代码⾥⾯做⼀些兼容性判断,或者是做⼀些UA的判断,如下代码所⽰:
//UA的类型
getUAType: function() {
let ua = window.navigator.userAgent;
if (ua.match(/renren/i)) {
return 0;
}
else if (ua.match(/MicroMessenger/i)) {
return 1;
}
else if (ua.match(/weibo/i)) {
return 2;
}
return -1;
}
这个函数的作⽤是判断⽤户是在哪个环境打开的⽹页,以便于统计哪个渠道的效果⽐较好。
这种类型的判断都有⼀个特点,就是它的结果是死的,不管执⾏判断多少次,都会返回相同的结果,例如⽤户的UA在这个⽹页不可能会发⽣变化(除了调试设定的之外)。所以为了优化,才有了惰性函数⼀说,上⾯的代码可以改成:
//UA的类型
getUAType: function() {
let ua = window.navigator.userAgent;
if(ua.match(/renren/i)) {
return 0;
}
else if(ua.match(/MicroMessenger/i)) {
return 1;
}
else if(ua.match(/weibo/i)) {
return 2;
}
return -1;
}
在每次判断之后,把getUAType这个函数重新赋值,变成⼀个新的function,⽽这个function直接返回⼀个确定的变量,这样以后的每次获取都不⽤再判断了,这就是惰性函数的作⽤。你可能会说这么⼏个判断能优化多少时间呢,这么点时间对于⽤户来说⼏乎是没有区别的呀。确实如此,但是作为⼀个有追求的码农,还是会想办法尽可能优化⾃⼰的代码,⽽不是只是为了完成需求完成功能。并且当你的这些优化累积到⼀个量的时候就会发⽣质变。我上⼤学的时候C++的⽼师举了⼀个例⼦,说有个系统⽐较慢她去看⼀下,其中她做的⼀个优化是把⼩数的双精度改成单精度,最后是快了不少。
但其实上⾯的例⼦我们有⼀个更简单的实现,那就是直接搞个变量存起来就好了:
let ua = window.navigator.userAgent;
let UAType = ua.match(/renren/i) ? 0 :
ua.match(/MicroMessenger/i) ? 1 :
ua.match(/weibo/i) ? 2 : -1;
连函数都不⽤写了,缺点是即使没有使⽤到UAType这个变量,也会执⾏⼀次判断,但是我们认为这个变量被⽤到的概率还是很⾼的。
我们再举⼀个⽐较有⽤的例⼦,由于Safari的⽆痕浏览会禁掉本地存储,因此需要搞⼀个兼容性判断:
Data.localStorageEnabled = true;
// Safari的⽆痕浏览会禁⽤localStorage
try{
SetData = 1;
} catch(e) {
Data.localStorageEnabled = false;
}
setLocalData: function(key, value) {
if (Data.localStorageEnabled) {
window.localStorage[key] = value;
}
else {
util.setCookie("_L_" + key, value, 1000);
}
}
在设置本地数据的时候,需要判断⼀下是不是⽀持本地存储,如果是的话就⽤localStorage,否则改⽤cookie。可以⽤惰性函数改造⼀下:
setLocalData: function(key, value) {
if(Data.localStorageEnabled) {
util.setLocalData = function(key, value){
return window.localStorage[key];
}
} else {
util.setLocalData = function(key, value){
Cookie("_L_" + key);
}
}
return util.setLocalData(key, value);
}
这⾥可以减少⼀次if/else的判断,但好像不是特别实惠,毕竟为了减少⼀次判断,引⼊了⼀个惰性函数的概念,所以你可能要权衡⼀下这种引⼊是否值得,如果有三五个判断应该还是⽐较好的。
3. 函数绑定
有时候要把⼀个函数当作参数传递给另⼀个函数执⾏,此时函数的执⾏上下⽂往往会发⽣变化,如下代码:
class DrawTool {
constructor() {
this.points = [];
}
handleMouseClick(event) {
this.points.push(event.latLng);
}
init() {
$('click', this.handleMouseClick);js arguments
}
}
click事件的执⾏回调⾥⾯this不是指向了DrawTool的实例了,所以⾥⾯的this.points将会返回undefined。第⼀种解决⽅法是使⽤闭包,先把this缓存⼀下,变成that:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。