标签列表

everest33

自制力

导航

JavaScript 平时记录

1.  数组所有元素的所有组合

var context = 'a,b,c,d';
var contexts = context.split(',');

//这个for循环没有body, a.push()方法返回的是push后a的长度
for (var a = []; a.push([]) < contexts.length;);

// b的值是所有元素可能的组合情况数,如3个元素共7中组合
var b = Math.pow(2, contexts.length) - 1;
for (var i = 1; i <= b; i++) {
    var c = [];
    for (var s = i, k = 0; s > 0; s >>= 1, k++) {
        /**
         * 找出当前这种组合的序号,如i=5时,二进制101,找出两个1所在的序号0,2;
         * 左移:所有位数往左移,(左边)移出位被丢弃,右边的空位一律补0,如10左移2位:1000;
         * 右移:所有位数往右移,(右边)移出位被丢弃,左边空位补0或补符号位:
         * MSDN中明确说明,右移对于无符号类型左边空位强制补零,对于有符号类型左边空位强制补符号位。
         **/
        if (s & 1 == 1) {
            c.push(contexts[k]);
        }
    }

    a[c.length - 1].push(c.join(""));
}

console.log(a);

1,JS中的this

见下面例子,注意函数中的函数 中的this指的是window对象了!!!

    document.addEventListener('click', function (e) {
        console.log(this);//this->document,添加在谁上的事件this就是指的谁
        (function () {
            console.log(this);//this->window
        })();
    });
    var o = {
        a : function () {
            console.log(this);//this->o,this指代对象o
            var b = function () {
                console.log(this);//this->window
            }()
        }
    };
    o.a();//o['a']()

2,定时器函数 setTimeout() 函数说明 (JavaScript单线程相关)

语法:
var timeoutID = scope.setTimeout(function[, delay, param1, param2,....]);
var timeoutID = scope.setTimeout(function[, delay]);
var timeoutID = scope.setTimeout(code[, delay]);


参数说明:
  function:function 是你想要在delay毫秒之后执行的 回调函数
  code:这是一个替代语法,你可以使用字符串代替function ,在delay毫秒之后执行字符串 (使用该语法是不推荐的, 原因和使用 eval()一样,有安全风险)。
  delay: 可选延迟的毫秒数 (一秒等于1000毫秒),函数的调用会在该延迟之后发生。如果省略该参数,delay取默认值0。实际的延迟时间可能会比 delay 值长,原因请查看Reasons for delays longer than specified
  param1, ..., paramN 可选附加参数,一旦定时器到期,它们会作为参数传递给function 或 执行字符串(setTimeout参数中的code)
例子:
  这个函数有两种用法,第一个参数可以是一个函数名称,也可以是字符串形式的代码。见下面两个例子:
  setTimeout("location.reload()", 5000)//5秒之后执行代码, 刷新页面
  setTimeout(reload, 4000); //4秒之后执行reload函数
如果这么写:setTimeout(location.reload(), 5000);效果是这样的:页面一直不停刷新,不会等5秒之后才刷新。原因是:没有用字符串形式的第一个参数实际上就是立即执行此代码,即刷新页面,刷新页面后,又重新执行setTimeout()这个函数,而这个函数又一次立即执行location.reload(),如此循环....

  如果需要传参,则第一个参数需要使用匿名函数形式

深度解析JavaScript中的settimeout()和setInterval()函数: 

https://blog.csdn.net/chiuwingyan/article/details/80322289

https://www.cnblogs.com/xiaohuochai/p/5773183.html

关于JavaScript单线程的一些事

小结一下:setTimeout()比setInterval()稳定,一般不使用setInterval()而是使用链式调用setTimeout()模拟setInterval()。原因是JavaScript引擎是单线程的,主要分为主线程和事件队列。同步操作是在主线程上执行的,异步操作一般是首先放在事件队列中,等JavaScript主线程空闲了才会去事件队列中取出代码放入主线程中去执行。定时器函数属于异步事件,参数里设置的时间并不是延迟多少秒去执行回调函数,这个时间代表的是延迟多少秒把回调函数放入到异步事件队列中,等到主线程空闲再被执行。这意味着至少要等这么多时间后才会执行回调函数。

一个例子:下面的代码会输出什么结果?

 

for (var i = 0; i < 10; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
结果是打印出10个10!解释如下:setTimeout在若干毫秒后执行一个函数并且是在for循环结束后。for循环结束后,i的值为10.所以当函数被调用的时候,它会打印出10!
如果想打印出1~9,有两个方法,1,将var变成let关键词(ES6才开始支持)或者 2,使用立即执行函数捕捉每次循环的i的值。代码如下:
for (var i = 0; i < 10; i++) {
    (function(j){
        setTimeout(function () {
            console.log(j);
        }, j * 10);
    })(i);
}

 

 setInterval()函数的问题:假如设置了一个每隔100ms执行一次的定时器,第一次执行到该定时器时,会在100ms之后将回调函数加入到事件队列中,再过100ms又会将这个回调函数加入到事件队列中,而如果主线程在此期间一直没有空闲,那么事件队列中的回调函数就一直不会被拿到主线程中取执行。可能出现的情况就是主线程空闲的时候会一次性将这些回调函数同时执行而没有任何时间间隔。JavaScript引擎对此的处理办法是:当使用setInterval()定时器时,只有当事件队列中没有该定时器的任何实例时,才会将定时器中的回调函数加入到事件队列中。 这确保了最小的时间间隔,但是引发的另一个问题是可能 有些间隔 被跳过了。如果功能需求是每个定时器函数都必须执行,那么就不能满足需求了。所以一般都使用递归调用settimeout()定时器模拟setInterval()的效果。不会出现上面的两个问题。

3, html标签里写事件 传 值

<select name="type" onchange="show_sub(this.options[this.options.selectedIndex].value)">    
    <option value="0">请选择主菜名</option>    
    <option value="1">白菜</option>    
    <option value="2">萝卜</option>    
 </select> 
js代码比较简单 

<script>     
    function show_sub(v){     
        alert(v);     
    }     
</script>   

最重要的知识点是获在select onchange时获取option的value值: this.options[this.options.selectedIndex].value 

 4,JS中的"0" 是true还是false

  if ('0') alert("'0' is true");

 if ('0' == false) alert("'0' is false");结果是,两次都 alert 了!那么 '0' 到底是 true 还是 false 呢?

答案是:在js做比较的时候,有这样的三条规则: 
  • 如果比较的两者中有boolean,会把 boolean 先转换为对应的 number,即 0 和 1(false是0,1是true)
  • 如果比较的双方中有一方为number一方为string,会把string转换为数字
  • 把string直接转换为boolean的时候,空字符串‘’转换为 false,除此外的一切字符串转换为 true 

5,浏览器兼容的enter事件 

<input type="text" id="text">
<script>
    document.getElementById("text").onkeypress = function(e) {
        e = e || window.event;
        key = e.keyCode || e.which || e.charCode;
        alert("按键码: " + key + " 字符: " + String.fromCharCode(key));
    if (key == 13) {enter事件} };

6,JavaScript立即执行某个函数 深度思考  https://www.tangshuang.net/2020.html

几种方式立即执行函数

在javascript中定义一个函数,并且立即去执行它。(这个情况虽然看上去很疯狂,但是实际上一定会用到,因为函数一旦执行完,内部的局部变量会被释放,内存也释放出来。)我们可能第一种想到的方法是:

// 第一种
function a() {}
a();
没错,这个太简单不过了。

当然,还有另外一种相对高深的办法:

window.onload = function() {}
这段代码表示在网页加载完之后立即执行function中的代码,但这里面隐含了另外一层意思,也就是可以把函数赋值给变量,使变量成为一个其他语言意义上的类。

// 第二种
var a = function(){}a();
不过这也给了我们另外一个思路:

function fun() {}
var a = fun();
a();
给我们留下一个思考:

function(){}; // javascript语句中以function开始没有实际的效果
一旦某条语句以function开始,这条语句没办法赋值给某个变量去执行它(说到这里,函数名可以可以理解为一个被赋值为某个函数的变量而已)。

下面是真相的时候:

function a() {}
a();
如果函数名是一个被赋值的变量(也就是a),那么为何不将其实际的值替换掉变量名呢(也就是把a()替换为function()())?于是,上面这段代码变为:

function(){}(); // 前面加粗部分代表a
但是在前面已经提到了,function开始的语句没有实际的效果,因此,上面这个语句不会有实际效果。不仅如此,这句代码还会抛出错误提示:SyntaxError: Unexpected token。

此处括号的正确理解

造成上述这个异常的原因是,javascript对语句的结束并不是以;作为标识,在这种普通情况下,}被作为语句结束的标识,因此,上述语句被解释为:

function(){};();
因此在执行()时,会抛出表达式错误。而如果我们执行:

function(){};(1);
则不会出错。原因在于:语法正确。

我理解的(),在javascript中有两种:一种是确定优先级,另一种是分组。当然,在声明函数和函数使用的时候也会用到(),但这是一种语法,而不是运算。确定优先级就是括号内的表达式先于括号外的表达式运算,例如:

1+(2*5)和(1+2)*5或(1+2)*(2+3)

而分组一般是在正则表达式中使用的概念,例如:

/<(.*)ok(this) is myhouse(.*)>/

在进行匹配的时候,上面的小括号将匹配结果分为三组进行返回,在替换的时候,可以对每个组分别进行替换。因此,分组的概念,应该和本文没有关系。因此,本文中的(),只有两种理解,一种是运算符,一种是语法。

在上面的代码中(1);中的();很明显是一个运算符,括号内必须有表达式,否则就是语法错误。

我们在回到上面的代码,如果我们给function加上()会怎样?

(function(){});
恭喜你,你的函数初始化,虽然从结果上并没有什么卵用,而且和直接function(){}也没有什么不同,只不过是把function(){}提高了运算的优先级而已。

可是,当我们执行下面的代码的时候,情况就大不相同了:

(function(){})();
代码是从左往右执行的,就像a() || b();一样如果a()为真,就不执行b()了。同样的道理,上面的代码中,红色部分作为一个表达式,执行完毕,代表着一个函数已经初始化完毕,如果我们回到:function(){}();,也就是前文抛出错误的那个语句你就会发现,神奇的事情发生了,红色部分俨然就是我们要的a,所以整个语句合起来也就是:a();,就这样,函数被执行了。

在这条代码中,第二个()不再是运算符,而是函数的括号。而第一个(),则是一个运算符,提高了内部function的运算优先级,内部被优先执行,得到结果后,与第二个()构成函数语法,执行了函数。

我们再回头来看()运算符的作用,来看一下下面这个代码:

()();
这是一个神奇的代码,世界上不会有任何程序员这样去用,当然,它也会报错。但是我们如何正确去理解这种情况呢?世界上是否存在下面这种javascript代码:

(a+b)(c+d);
从来没有见过。如果世界上存在一种运算,就是没有任何运算,那么上面是成立的,但是,如果这种假设不成立的话,上面的代码就是错误的。我们从来没有见过(1+2)(3+4),虽然我们小学的时候写过这样的算式,但是在代码中是不存在的。

因此,我们换一个思维,不要只把它当做运算,而是运算和函数的结合呢?在你的浏览器中运行下面这段代码试试:

(1+2)(3+4);// TypeError: (1 + 2) is not a function
提示的不是语法错误,而是数据类型错误,第二个括号 前面的不是一个函数。也就是说,第二个括号前面的,如果是函数类型,就正确了!那么世界上有没有一种算法,使运算后返回值为函数呢?比如 fun1+fun2=fun3?好像我还从来没有遇到过,因此,想在第一个括号中构建一种运算使该代码成立,还需要高高手来实现。唯一的解决办法,就是在 第一个括号中委以函数,也就是(function(){})(3+4),而3+4不过仅仅是作为前面这个函数的参数予以运行。

匿名函数的立即执行

当你以为挖到宝藏的时候,下面的解释或许让你再一次开了脑洞。我们提到function开头的语句虽然初始化函数,但是函数并不被执行,其运行效果相当于什么也没发生。

为了提交它的优先级,我们再用一次()吧:

(function(){}());
这次,我们直接把函数表达式和后面的()放在一个()里面,这下子奇迹也发生了,空号内部是一个表达式,表达式的意思就是}不代表结束,所以我们前文提到的}表示语句结束的论断不起作用了。()内部必须运算完成,才能结束这次表达式运算,所以上面代码中的红色部分又再次先运算了,运算完又和()组成了a(),于是,函数又执行了。

OK,我们现在终于get到了终点:表达式必须运行完成,才会结束表达式。这简直就是天一样的玄机,牢牢记住表达式这个概念之后,我们再来看下面的几个代码:

!function(){}();
+function(){}();
-function(){}();
~function(){}();
……
没错,上面的!+-~,全部代表表达式,!表示非,~表示按位非。你可以想出全部的表达式符号(当然必须得考虑运行是否合法,比如/0就不合法,分母不能为0),从而实现上面的这个效果。

于是,我们看到几乎所有的插件,都会用上面的其中一种方式来定义整个代码。

正是因为这个原因,上面的所有代码,都可以让function(){}内部的代码立即执行。

遗留问题:第二个括号内的参数

在多数插件中,我们可以看到如下的代码:

!function(){}(jQuery);
基本上我们都看懂了,但是第二个括号内有个jQuery代表什么意思呢?

你想一下下面这个用法:

function a(var) {}
a(1);
然后把第二行的a替换为function(var){},结果就变成了function(var){}(1);

没错,第二个括号内的值,是原本函数的特定参数。所以,上面那个jQuery的,我们可以将它还原为:

var fun = function(a) {}
fun(jQuery);
就是这样了。但是,jQuery是什么呢?是一个对象啊!所以下面的代码就来了:

!function($){
  // 在function中,$实际上就是jQuery,所以用$尽情玩耍吧。
}(jQuery);
难道你以为到此就结束了吗?不,看看下面的代码:

!function(fun){}(function($){});
什么鬼?你以为我想表达什么?其实,这是很多插件中的一种写法,用以兼容不同的加载模式(CommonJS、CMD、CMD),具体是这样的:

!function(fun){
  "use strict";
  if(typeof define === 'function' && define.amd) {   
    define(['jquery'], fun)
  } else {
    fun((typeof(jQuery) != 'undefined') ? jQuery : window.Zepto) 
  }
}(function($){
  "use strict";
  // 真正的插件代码都在这里
});
这是一个双重传值的过程。第一重,第一个function(fun)中的fun是第二个function($),因此,在第一个function中的代码中fun($)和第二个function($)是等效的。第二重,第二个function($)中的$参数,是在第一个函数中进行传递过来的,第一个函数中,define(['jquery'],fun)和fun(jQeury)实际上在执行第二个函数,既然如此,真正的插件代码就应该在第二个函数中去写,第一个函数仅仅是通过多个判断,返回正确的调用模式而已。

实际上,了解了上述之后,本文的题目是为了立即执行某个函数,在实践中,还有很多做法可以在申请一个函数后立即执行它,比如:

(function(){}).call();
好了,这个问题就阐述到这里,可能也有一些不足的地方,欢迎大家指正。
View Code 无法点开时,点开F12,去除用于隐藏代码的那个 类 即可显示

7, JavaScript中的数组或对象 循环方法总结

1, 普通for循环 [数组,对象] //注意,将长度赋给一个变量,防止每次循环都要算一下长度。for (var i=0, len=arr.length; i < len; i++){}

2, for in 【数组,对象】//注意 for (var i in arr){} 中的i类型始终是string类型的,有时候需要int类型时要注意。

3, array.forEach(function(value, index){})【数组】// ES5推出的数组自带的循环,主要功能是遍历数组,实际性能比for 还弱。forEach这种方法也有一个小缺陷:你不能使用break语句中断循环,也不能使用return语句返回到外层函数

4,array.map(functino(value, index){})【数组】//也是ES5推出的,支持return 语句

5,for ... of 【数组】//ES6新增功能

6,jQuery的静态方法$.each(array/obj, function(index, value){})

7, underScoreJS中的方法:_.each(array/obj, function(index, value){})

8, 关于 jQuery的 tmpl 模板插件的说明

 

var html = $("#menu_tmpl").tmpl({data:retval.data}).outerHTML();
$("#phpNav").html(html);
使用tmpl()方法时,一定要用对象模式,不容易出问题! (本身这里的参数只能是对象格式,而不能是数组)

 

5

5

5

5

5

5

5

5

posted on 2017-09-27 11:04  everest33  阅读(346)  评论(0编辑  收藏  举报