同步异步、this总结、call/apply/bind

同步异步简单了解(闭包的使用)

同步:代码的书写顺序和代码的执行顺序一样。 (大部分为同步代码)
异步:代码的书写顺序和代码的执行顺序不一样。

在JS中,异步代码仅仅是个别:
1)事件绑定
2)定时器
3)ajax


  • 每一个元素对象默认里面就有很多的属性 其中有一个叫onclick.
    给元素注册点击事件 btn叫事件源
    click叫事件类型
    funciotn 事件处理程序 事件发生时做什么
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
    let btns = document.getElementsByTagName("button");  // 数组
       //document.getElementsByTagName("button");  存储在堆中
    btns[0].onclick = function () {
        console.log(0)
    }
    //函数肯定要调用  当我们点击了第1上按钮,浏览器会帮我们调用后面的函数
    btns[1].onclick = function () {
        console.log(1)
    }
    btns[2].onclick = function () {
        console.log(2)
    }
</script>

1、

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
var btns = document.getElementsByTagName("button");   //数组容器,也是个对象
for (var i=0; i<btns.length; i++){
    btns[i].onclick = (function (i) {     //事件绑定,浏览器在执行时直接忽略掉
        return function g() {
            console.log(i)
        }
    })(i);
}
</script>

结果展示:分别点三个按钮,会出现0,1,2;

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
    var btns = document.getElementsByTagName("button");
    for (var i=0; i<btns.length; i++){
        // console.log(btns[i].abc)// 访问一个对象上不存在的属性  得到的是und
        btns[i].index = i; // 把i值赋值给对象上的index属性
        btns[i].onclick = function () {
            // console.log(i)
            // console.log(btns[i])  // 答:浏览器帮我们调用函数  浏览器帮我们调用此函数时,是得不到全局EC中的数据,
console.log(this.index)   // 解决办法:this  this表示当前的事件源

            // console.log(btns[i].index)
        }
    }
</script>

结果展示:分别点三个按钮,会出现0,1,2;
3.

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<script>
    var btns = document.getElementsByTagName("button");
    for (let i=0; i<btns.length; i++){
        btns[i].onclick = function () {
            console.log(i)
        }
    }
</script>

结果展示:分别点三个按钮,会出现0,1,2;

this相关

1)如果this出现在普通的函数中,this表示window.

  • 如果你通过window打点调用一个函数,这个函数中的this也是window。
    程序员自己调用一个函数 一个普通函数 函数中的this表示window
<button id="box">box</button>
<script>
    let box = document.getElementById("box");
    function f() {
        console.log(this);     // window
    }
    f();  
    box.onclick = f();   
</script>

结果展示:f()表示自己调用个函数

<!-- <script>
    function k() {
        console.log(this); // window
    }
    window.k();  // window打点调用
    k();         // 程序员自己调用
</script> -->

2)事件绑定,事件处理程序,事件发生时,浏览器帮我们调用这个此函数中的this表示事件源

<button id="box">box</button>
<script>
    let box = document.getElementById("box");
    box.onclick = function () {
        console.log(this);     //事件源
    }
</script>

结果展示:点击盒子按钮,显示事件源
在这里插入图片描述

3)在一个对象中,如果有方法(函数),如果通过这个对象调用方法中的this表示这个对象。一个方法中的this是谁,就看点前面是谁,是谁在调用。

<script>
    var wc = {
        name:"wangcai",         // 属性 
        age:100,   
        eat:function () {       // 叫方法(属性)
            console.log("eat...")
            console.log(this);
        }
    }
    wc.eat(); // 调用一个对象上的方法
    // 一个方法中的this是谁,就看点前面是谁。
</script>
<script>
    var fullname = "language";
    var obj = {
        fullname:"javascript",
        prop:{
            getFullName:function () {
                return  this.fullname;
            }
        }
    }
    
    console.log(obj.prop.getFullName()); // undefined
</script>

解释: 谁用了getFullName 看.前面是谁。点前面是obj.prop 说明getFullName中的this是obj.prop。obj.prop中没有fullname;访问一个对象上不存在的属性,得到undeifined

4)在IIFE中,this表示window

<script>
    (function () {
        console.log(this);
    })();     // 在非严格模式下,IIFE中的this表示window
</script>

5)前四点都是在非严格模式下。在严格模式下,调用一个普通函数,t表示undefined。IIFE中的this也表示undefined

<script>
    "use strict";    // 启用JS的严格模式
    function f() {
        console.log(this);   // undefined
    }
    f();

    (function () {
        console.log(this);   // undefined
    })();
</script>

练习题:
1.

<script>
    var num = 10;  // VO ==》 num也变成了65
    var obj = {
        num:20, // num:30
    }
    obj.fn = (function (num) {
        this.num = num*3;   // 
        num++;  //
        console.log(num)
        return function (n) {
            // EC n:5
            // EC  n:10
            this.num += n; 
            num++;
            console.log(num)
        }
    })(obj.num)
    var fn = obj.fn;
    fn(5);
    obj.fn(10);
    console.log(num,obj.num)
    console.log(window.num)
</script>

结果展示:
在这里插入图片描述

<script>
    (function () {
        var a = 1;
        var obj = {
            a:10,     
            f:function () {
                a *= 2;
            }
        }
        obj.f();
        alert(obj.a+a)
    })();
</script>

结果展示:在这里插入图片描述

解释:如果要调用obj中的a:10,必须是obj.a

call/apply/bind相关

1、call相关:

作用: 1)call改变this指向,让函数中的this指向call中参数(对象)
2)让函数直接执行 调用
3)call可以让一个数据去借用一个对象上的方法

1)举例说明:为什么要修改this的指向
以往写法:
<script>
    var obj1 = { name: "wnagcai", say: function () { console.log("我是:" +this.name) } }
    var obj2 = { name: "xiaoming", say: function () { console.log("我是:" +this.name) } }
    obj1.say();
    obj2.say();
</script>
  • 因为如果原先写的话同样的函数写了两遍,占了两个堆内存
  改进一:
  <script>
     var abc = function () {
         console.log("我是" + this.name)
     }
     var obj1 = {
         name: "wangcai",
         say: abc
     }
     var obj2 = {
         name: "xiangming",
         say: abc
     }
     console.log(obj1.say === obj2.say)
     obj1.say();
     obj2.say();
</script>
  改进二:
<script>
     var abc = function () {
         console.log("我是" + this.name)
     }
     var obj1 = {
         name: "wangcai",
         say: abc
     }
     var obj2={
         name:"xioaming",
         say:abc
     }
     abc.call(obj1);
     abc.call(obj2);
</script>

结果展示:
在这里插入图片描述

解释:call的参数,让this指向obj1,改变this的指向,并且让abc进行直接执行调用

2)call可以让一个数据去借用一个对象上的方法

小案例:如何准确的得出数据类型

  • 利用typeof
console.log(typeof 1)     // number  
console.log(typeof "hello") // string  
console.log(typeof true)  // boolean 
function f(){}
console.log(typeof f)  // function  
var a;
console.log(typeof a)  // undefined  
console.log(typeof [1,2,3])  // object  
console.log(typeof {a:1})  // object  

typof的不足:检测基本数据类型OK,对于引用数据类型来说,检测function也OK,但是其它的不OK。

  • tostring可以显示数据类型,除了Object里有toString之外,其他的也有toString方法;如果自己有toString方法,在调用的时候,就调用原型的toString方法。
<script>
    let arr = [1, 2, 3];
    console.log(arr.toString());  //调用的是Array.prototype.toString()
    let obj = { name: "wc" }
     console.log(obj.toString()); //调用的是Object.prototype.toString()
    let f = function () { }
     console.log(f.toString());   //调用的是Function.prototype.toString()
</script>        
<script>
    var arr1 = [1, 2, 3];
    arr1.toString = function () {
        console.log("xxx")
    }
    console.log(arr1.toString());  //调用的是自己私有的toString方法
 </script>   
  • 直接去调用Object上面的toString方法
var arr2 = [1111];
Object.prototype.toString.call(arr2);  //arr2直接调用Object的原型对象上面的toString 
  • 利用Object.prototype.toString.call可以非常精确地检测一个数据的数据类型
<script>
    console.log(Object.prototype.toString.call(1));    //[object Number]
    console.log(Object.prototype.toString.call("hello"));//[object String]
    console.log(Object.prototype.toString.call(true));  //[object Boolean]
    console.log(Object.prototype.toString.call({}));  //[object Object]
    console.log(Object.prototype.toString.call([1, 2, 3]));  //[object Array]
    function f() { }
    console.log(Object.prototype.toString.call(f));  //[object Function]
    let d =new Date();
    console.log(Object.prototype.toString.call(d));  //[object Date]
    let r=new RegExp;
    console.log(Object.prototype.toString.call(r));   //[object RegExp]
</script>
  • 通过上面的Object.prototype.toString.call,我们确实准确的得到了他的数据类型的,但是我们想要单独显示数据类型,这就用到了.substring,进行切割选择输出的内容。

str.substring(indexStart[, indexEnd])
indexStart:需要截取的第一个字符的索引
indexEnd:可选。一个 0 到字符串长度之间的整数,以该数字为索引的字符不包含在截取的字符串内。

 <script>
        function getType(abc) {
            var rs = Object.prototype.toString.call(abc);    //得到[object ...]
            rs = rs.substr(8)     //  rs.substr(8)得到除去[object
            var len = rs.length;
            //console.log(rs.substr(0,len-1))     //rs.substr(0,len-1)  减去后面的],得到一个首字母大写的数字类型
            return rs.substr(0, len - 1).toLowerCase()    //toLowerCase()变成小写
        }
        console.log(getType(123));
        console.log(getType([]));
        console.log(getType({}));
        console.log(getType(new Date));
        console.log(getType(new RegExp));
        var f = function () { }
        console.log(getType(f));
    </script>

结果:
在这里插入图片描述
解释:通过上面的一个简单函数,去进行查看一些数据的数据类型

3)call的常见用法

1.如何把字符串中的数字进行翻转

<script>
    var str = "123456789";
    var newstr = "";
    for (var i = str.length - 1; i >= 0; i--) {
        newstr += str[i];
    }
    console.log(newstr);  //987654321
</script>
  • 了解数组中有一个可以翻转的方法:reverse()
<script>
    var arr = [1, 2, 3, 4, 5]
    console.log(arr.reverse());//[5,4,3,2,1]
</script>
  • 利用数组的方法让字符串的翻转
 <script>
    //一步一步的,先转化,后翻转,再转化
    var str = "123456789";
    console.log(str.split(""));   //["1", "2", "3", "4", "5", "6", "7", "8", "9"]
    console.log(str.split("").reverse());  //["9", "8", "7", "6", "5", "4", "3", "2", "1"]
    console.log(str.split("").reverse().join());  //9,8,7,6,5,4,3,2,1
    console.log(str.split("").reverse().join(""));  //987654321
</script>

结果显示:

  • 利用call进行整合
 <script>
    var str = "123456789";
    console.log(Array.prototype.reverse.call(str.split("")).join("")); // 987654321
</script>

2.如何把伪数组转化成一个真正的对象

伪数组:不是真正的数组;本质是对象,没有数组原型对象上的方法
真正的数组:[1,2,3][“a”,“b”,“c”]
伪数组:{0:“a”,1:“b”,2:“c”}

常见的伪数组:
1)通过doucment.getElementsByTagName获得的元素集合就是伪数组
2)函数内部的arguments

代码解释伪数组:

<span>1</span><span>2</span><span>3</span>
<script> 
        var spans = document.getElementsByTagName("span");
        console.dir(spans)
        //此时spans不是数组,仅仅长的像数组罢了
</script>
<script>
        // arguemnts是函数内部的一个对象  用来收集实参
        function f(a, b) {
            console.log(a);
            console.log(b);
            // 函数调用时,不只把实参给了形参,也把实参给了augments,arguments会收集实参
            console.dir(arguments);    // 伪数组
        }
        f(1, 2);
        //console.log(arguments);     // 报错ReferenceError,函数外部是不能访问arguments的
</script>
  • 把一个伪数组(对象)转化成真正的数组
<span>1</span><span>2</span><span>3</span>
<script>
    var spans = document.getElementsByTagNam("span");
    var arr = [];
    for (let i = 0; i < spans.length; i++) {
        arr.push(spans[i]);
    }
    console.log(arr);
</script>
  • 借用slice方法:方法返回一个新的数组对象,
<span>1</span><span>2</span><span>3</span>
    <script>
        var spans=document.getElementsByTagName("span");
        //console.log(Array.isArray(spans));  //false
        //借用slice方法:返回一个新的数组对象,
        console.log(Array.prototype.slice.call(spans));   
        console.log(Array.isArray(Array.prototype.slice.call(spans)));  //true
    </script>

结果展示:
在这里插入图片描述

3.call方法里面可以有多个参数

<script>
        function f(a,b){
            return a+b;
        }
        var obj={};
        //f.call(obj); //让f执行,
        //f(1,2);  //自己调用f参数,并进行传递参数
        console.log(f.call(obj,4,5));   
    </script>

解释:call方法里面可以有多个参数,第一个参数表示谁去借用这个方法 ,后面的参数都是给这个方法传递的参数

2、apply相关:

和call的用法一样,唯一就是传递参数有区别
代码展示:

<script>
    function f(a, b) {
       // console.log("f...")
        return a + b;
    }
    var obj={};
    console.log(f.apply(obj,[1,2]));  //让obj借的函数,传参传的是个数组
</script> 
小案例:

** 获取数组中最大值 ,利用Math类**

<script>
        console.log(Math.max(2,4,1,6));

        var arr = [2, 3, 4, 5, 6, 9, 10, 29, 3, 0];
        console.log(Math.max.call(arr,1,2,3,4,6,5,8));
        console.log(Math.max.apply(arr,[1,2,3,4,6,5,8]));
        console.log(Math.max.apply(arr,arr));

        console.log(Math.max.apply({},arr));
        console.log(Math.max.apply("", arr));
        console.log(Math.max.apply(null, arr));
        console.log(Math.max.apply("abc", arr));
</script> 

3、bind相关:

bind:绑定的意思,改变this的方向,但是函数不执行
代码展示:

<script>
    function f(a, b) {
            //console.log("f...")
            return a + b;
        }
        var obj = {};
        let k = f.bind(obj);
        console.log(k(1, 2));
</script> 

总结

call 改变了this指向 并让函数执行,传递参数一个个传递
apply 改变了this指向 并让函数执行,传送参数必须是数组
bind 改变了this指向 函数不执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值