《JavaScript设计模式与开发》笔记 3.call和apply

Posted SmarTom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《JavaScript设计模式与开发》笔记 3.call和apply相关的知识,希望对你有一定的参考价值。

  •  1.改变this指向
  •  2.Function.prototype.bind
  •  3.借用其他对象方法
    • 1.借用实现继承
    • 2.实现恶心的
      • Array.prototype.push.call
      • Array.prototype.join.call
      • Array.prototype.slice.call
      • Object.prototype.toString.call

1.改变this指向

var obj1 = {
    name:"Bob marley"
};
var obj2 = {
    name:"Bob Dylan"
};
var name = "David Bowie";
var getName = function(){
    console.log(this.name);
}
getName();  //输出undefined
getName.call(obj1); //输出Bob marley
getName.call(obj2); //输出Bob Dylan

 


在实际开发中,经常会遇到this指向被不经意改变的场景:例如:

document.getElementById(‘div1‘).onclick=function(){
    alert(this.id);         //输出div1
    var func = function(){
        alert(this.id);     //输出undefined
    }
    func();
};

 

使用call来修复func函数内的this,使其指向div

document.getElementById(‘div1‘).onclick=function(){
    alert(this.id);
    var func = function(){
        alert(this.id);
    }
    func.call(this);
};
再如:

var name = "SmarTom";
var func = function(){
    console.log(this.name);
}
func();

 

使用call来修复func函数内的this,使其指向div 再如:

var obj ={
    name : "SmarTom"
}
var func = function(){
    console.log(this.name);
}
func.call(obj);

 


2.Function.prototype.bind

大部分浏览器都实现了内置的Function.prototype.bind,用来指定函数内部的this指向 即使没有原生的Function.prototype.bind实现,也可以模拟一下,例如:

//在一些浏览器中可以忽略 bind函数
Function.prototype.bind = function(context){
    var _self = this;
    return function(){
        return _self.apply(context,arguments);
    }
}
var obj = {
    name :"SmarTom"
}
var func = function(){
    console.log(this.name);
}.bind(obj);            //进行绑定
func();

 

 

3.借用其他对象的方法【实现继承】

1.借用实现继承

var A = function(name){                 //父类 A
    this.name = name;
}
var B = function(){                     //子类 B 继承父类A
    A.apply(this,arguments);
}
B.prototype.getName = function(){       //B方法
    return this.name;
}
var b = new B(‘asdfasdfasdf‘);
console.log(b.getName());

 

2.实现

Array.prototype.push.call
Array.prototype.join.call
Array.prototype.slice.call
Object.prototype.toString.call()


1. Array.prototype.push.call
Array.prototype.push.call(obj,arguments)
相当于var html = []; html.push(那一大堆)
<script type="text/javascript">
    (function () {
        var customService = function () {

        };
        customService.prototype = {
            open: function () {
               contents: this._getHtml(),
            },
            close: function () {

            },
            _getHtml: function () {
                var html = [];
                Array.prototype.push.call(html,
                    ‘<div class=\"content\">‘,
                        ‘<div>1、</div>‘,
                        ‘<div>2、<\/div>‘,
                        ‘<div>3、<\/div>‘,
                        ‘<div>4、<\/div>‘,
                    ‘<\/div>‘
                );
                return html.join(‘‘);
            }
        };
        window.CustomService = new customService();
    })();
</script>

2.Array.prototype.join.call
//arguments就相当于一个对象数组
Array.prototype.join.call(arguments,‘,‘)
就类似于window.join方法.apply,call不会改变scope,可参考finally里的内容
<script type="text/javascript">
var join = function () {
    for (var i = 0, b = ‘‘; i < this.length ; i ++) {
        if (i) b+= arguments[0];
        b += this[i];
    }
    return b;
};
 
var show = function () {
    //new Array(arguments)).join(‘_‘);
    //try
    try {
        alert(
            Array.apply(null, arguments).join(‘_‘)
        );
        return join.call(arguments, ‘-‘); //Array.prototype.join就类似于window.join方法.apply,call不会改变scope,可参考finally里的内容
    } finally {
        var func = function () {
            alert(a);
        };
 
        void function () {
            var a = 1;
            try {
                func.call(this);
            } catch (exp) {
                alert(exp.message);
            }
        }();
    }
};
 
alert(show(1, 2, 3, 5));
</script>


3.Array.prototype.slice.call
var a={length:2,0:‘first‘,1:‘second‘};
Array.prototype.slice.call(a);//  ["first", "second"]
var a={length:2};
Array.prototype.slice.call(a);//  [undefined, undefined]
可能刚开始学习js的童鞋并不是很能理解这句为什么能实现这样的功能。
比如我就是一个,所以,来探究一下。
首先,slice有两个用法,一个是String.slice,一个是Array.slice,
第一个返回的是字符串,第二个返回的是数组,这里我们看第2个。
Array.prototype.slice.call(arguments)能够将arguments转成数组,那么就是arguments.toArray().slice();
到这里,是不是就可以说Array.prototype.slice.call(arguments)的过程就是先将传入进来的第一个参数转为数组,再调用slice?


4.Object.prototype.toString.call
使用Object.prototype上的原生toString()方法判断数据类型,使用方法如下:

Object.prototype.toString.call(value)

1.判断基本类型:

Object.prototype.toString.call(null);//”[object Null]”
Object.prototype.toString.call(undefined);//”[object Undefined]”
Object.prototype.toString.call(“abc”);//”[object String]”
Object.prototype.toString.call(123);//”[object Number]”
Object.prototype.toString.call(true);//”[object Boolean]”
2.判断原生引用类型:

函数类型
Function fn(){console.log(“test”);}
Object.prototype.toString.call(fn);//”[object Function]”
日期类型
var date = new Date();
Object.prototype.toString.call(date);//”[object Date]”
数组类型
var arr = [1,2,3];
Object.prototype.toString.call(arr);//”[object Array]”
正则表达式
var reg = /[hbc]at/gi;
Object.prototype.toString.call(arr);//”[object Array]”
自定义类型
function Person(name, age) {
    this.name = name;
    this.age = age;
}
var person = new Person("Rose", 18);
Object.prototype.toString.call(arr); //”[object Object]”
很明显这种方法不能准确判断person是Person类的实例,而只能用instanceof 操作符来进行判断,如下所示:
console.log(person instanceof Person);//输出结果为true
3.判断原生JSON对象:

var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON);
console.log(isNativeJSON);//输出结果为”[object JSON]”说明JSON是原生的,否则不是;

注意:Object.prototype.toString()本身是允许被修改的,而我们目前所讨论的关于
Object.prototype.toString()这个方法的应用都是假设toString()方法未被修改为前提的。

 

以上是关于《JavaScript设计模式与开发》笔记 3.call和apply的主要内容,如果未能解决你的问题,请参考以下文章

《JavaScript设计模式与开发》笔记 4.闭包

JavaScript设计模式与开发实践---读书笔记

JavaScript设计模式与开发实践---读书笔记 迭代器模式

《JavaScript设计模式与开发》笔记 5.关于正确写一个闭包

《JavaScript设计模式与开发》笔记 6.高阶函数

javascript设计模式与开发实践 阅读笔记