zoukankan      html  css  js  c++  java
  • 11.15无标题1

    JS中call,apply,bind方法的区别

    call,apply,bind这三个方法其实都是继承自Function.prototype中的,属于实例方法。

     console.log(Function.prototype.hasOwnProperty('call')) //true
     console.log(Function.prototype.hasOwnProperty('apply')) //true
     console.log(Function.prototype.hasOwnProperty('bind')) //true

    1.Function.prototype.call()

     函数实例的call方法,可以指定该函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。并且会立即执行该函数。

     看个例子来好好理解这段话。

     var keith = {
     rascal: 123
     };
     var rascal = 456;
     function a() {
     console.log(this.rascal);
     }
     a(); //456
     a.call(); //456
     a.call(null); //456
     a.call(undefined); //456
     a.call(this); //456
     a.call(keith); //123

    上面代码中,a函数中的this关键字,如果指向全局对象,返回结果为456。可以看到,如果call方法没有参数,或者参数为null或undefined或者this,则等同于指向全局对象。如果使用call方法将this关键字指向keith对象,也就是将该函数执行时所在的作用域为keith对象,返回结果为123。

    call()方法可以传递两个参数。第一个参数是指定函数内部中this的指向(也就是函数执行时所在的作用域),第二个参数是函数调用时需要传递的参数。

    function keith(a, b) {
     console.log(a + b);
     }
    keith.call(null, 1, 2); //3

    第一个参数是必须的,可以是null,undefined,this,但是不能为空。设置为null,undefined,this表明函数keith此时处于全局作用域。第二个参数中必须一个个添加。而在apply中必须以数组的形式添加。

    call方法的一个应用是调用对象的原生方法。也可以用于将类数组对象转换为数组。

    var obj = {};
     console.log(obj.hasOwnProperty('toString')); //false
     obj.hasOwnProperty = function() {
     return true;
     }
     console.log(obj.hasOwnProperty('toString')); //true
     console.log(Object.prototype.hasOwnProperty.call(obj, 'toString')); //false

    上面代码中,hasOwnProperty是obj对象继承的方法,如果这个方法一旦被覆盖,就不会得到正确结果。call方法可以解决这个方法,它将hasOwnProperty方法的原始定义放到obj对象上执行,这样无论obj上有没有同名方法,都不会影响结果。要注意的是,hasOwnProperty是Object.prototype原生对象的方法,而call是继承自Function.prototype的方法。

    2.Function.prototype.apply()

    apply方法的作用与call方法类似,也是改变this指向(函数执行时所在的作用域),然后在指定的作用域中,调用该函数。同时也会立即执行该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。

    apply方法的第一个参数也是this所要指向的那个对象,如果设为null或undefined或者this,则等同于指定全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,在调用时传入原函数。原函数的参数,在call方法中必须一个个添加,但是在apply方法中,必须以数组形式添加。

    看一下call,apply的细微差别。

    function keith(a, b) {
     console.log(a + b);
     }
     keith.call(null, 2, 3); //5
     keith.apply(null, [2, 3]); //5
     

    上面代码中,第一个参数为null,指向全局作用域;第二个参数传入的形式稍稍不同。

    apply方法有以下应用。

    2.1:找出数组中的最大数

    var a = [2, 4, 5, 7, 8, 10];
    console.log(Math.max.apply(null, a)); //10
    console.log(Math.max.call(null,2, 4, 5, 7, 8, 10)); //10 

    Javascript中是没有提供找出数组中最大值的方法的,结合使用继承自Function.prototype的apply和Math.max方法,就可以返回数组的最大值。

    2.2:将数组的空元素变为undefined

    通过apply方法,利用Array构造函数将数组的空元素变成undefined。

    console.log(Array.apply(null, [1, , 3])); // [1, undefined, 3]

    空元素与undefined的差别在于,数组的forEach方法会跳过空元素,但是不会跳过undefined和null。因此,遍历内部元素的时候,会得到不同的结果。

    var a = [1, , 3];
     a.forEach(function(index) {
     console.log(index); //1,3 ,跳过了空元素。
     })
     Array.apply(null,a).forEach(function(index){
     console.log(index); ////1,undefined,3 ,将空元素设置为undefined
     })

    2.3:转换类似数组的对象

    另外,利用数组对象的slice方法,可以将一个类似数组的对象(比如arguments对象)转为真正的数组。当然,slice方法的一个重要应用,就是将类似数组的对象转为真正的数组。call和apply都可以实现该应用。

    console.log(Array.prototype.slice.apply({0:1,length:1})); //[1]
    console.log(Array.prototype.slice.call({0:1,length:1})); //[1]
    console.log(Array.prototype.slice.apply({0:1,length:2})); //[1,undefined]
    console.log(Array.prototype.slice.call({0:1,length:2})); //[1,undefined]
    function keith(a,b,c){
     return arguments;
     }
    console.log(Array.prototype.slice.call(keith(2,3,4))); //[2,3,4]

    上面代码的call,apply方法的参数都是对象,但是返回结果都是数组,这就起到了将对象转成数组的目的。从上面代码可以看到,这个方法起作用的前提是,被处理的对象必须有length属性,以及相对应的数字键。

    3.Function.prototype.bind()

    bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数。

    var keith = {
     a: 1,
     count: function() {
     console.log(this.a++);
     }
     };
     keith.count(); //1
     keith.count(); //2
     keith.count(); //3

    上面代码中,如果this.a指向keith对象内部的a属性,如果这个方法赋值给另外一个变量,调用时就会出错。

     var keith = {
     a: 1,
     count: function() {
     console.log(this.a++);
     }
     };
     var f = keith.count;
     f(); //NaN

    上面代码中,如果把count方法赋值给f变量,那么this对象指向不再是keith对象了,而是window对象。而window.a默认为undefined,进行递增运算之后undefined++就等于NaN。

    为了解决这个问题,可以使用bind方法,将keith对象里的this绑定到keith对象上,或者是直接调用。

     var f = keith.count.bind(keith);
     f(); //1
     f(); //2
     f(); //3
     keith.count.bind(keith)() //1
     keith.count.bind(keith)() //2
     keith.count.bind(keith)() //3

     当然,this也可以绑定到其他对象上。

     var obj = {
     a: 100
     };
     var f = keith.count.bind(obj);
     f(); //100
     f(); //101
     f(); //102

    同样,我们也可以给bind方法传递参数,第一个参数如果为null或者undefined或者this,会将函数内部的this对象指向全局环境;第二个为调用时需要的参数,并且传递参数的形式与call方法相同。

     function keith(a, b) {
     return a + b;
     }
     console.log(keith.apply(null,[1,4])); //5
     console.log(keith.call(null,1,4)); //5
     console.log(keith.bind(null, 1, 4)); //keith()
     console.log(keith.bind(null, 1, 4)()); //5

    上面代码中,可以看出call,apply,bind三者的区别:call和apply方法都是在调用之后立即执行的。而bind调用之后是返回原函数,需要再调用一次才行,有点像闭包的味道,

    REM响应式布局

    REM: 根据根元素html的font-size值来设置大小

    EM: 根据body元素font-size值设置大小

    REM响应式布局只做移动端 使用方法:

    1.如果html:font-size: 15px,那么 1rem=15px;

    2.如果设计稿宽为640px,则html:font-size=屏幕宽度/640*15px,dom中20px等于20/15=1.3rem;

    +function () {
    var desW = 640,
    broW = document.documentElement.clientWidth,
    main = document.querySelector("#main");
    if (broW > desW) {
    main.style.width = desW + "px";
    main.style.margin = "0 auto";
    return;
    }
    var ratio = broW / desW;
    document.documentElement.style.fontsize = ratio * 15 + "px";
    }();

  • 相关阅读:
    CSS3 target伪类简介
    不用position,让div垂直居中
    css3 在线编辑工具 连兼容都写好了
    a标签伪类的顺序
    oncopy和onpaste
    【leetcode】1523. Count Odd Numbers in an Interval Range
    【leetcode】1518. Water Bottles
    【leetcode】1514. Path with Maximum Probability
    【leetcode】1513. Number of Substrings With Only 1s
    【leetcode】1512. Number of Good Pairs
  • 原文地址:https://www.cnblogs.com/mlw1814011067/p/11867921.html
Copyright © 2011-2022 走看看