《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()方法未被修改为前提的。
时间: 2024-10-15 16:33:27

《JavaScript设计模式与开发》笔记 3.call和apply的相关文章

《JavaScript设计模式与开发实践》读书笔记之观察者模式

1.<JavaScript设计模式与开发实践>读书笔记之观察者模式 观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知. JavaScript中通常采用事件模型替代传统的观察者模式 1.1 逐步实现观察者模式 以客户看房为例 首先指定谁充当发布者,如售楼处 然后给发布者添加一个缓存列表,用于存放回调函数以便通知订阅者.这里为了让订阅者只接收自己感兴趣的消息,增加一个标识key 最后发布消息时候,发布者遍历缓存列表,依次触发里面存放的订阅者的回

JavaScript 设计模式与开发实践读书笔记 http://www.open-open.com/lib/view/open1469154727495.html

JavaScript 设计模式与开发实践读书笔记 最近利用碎片时间在 Kindle 上面阅读<JavaScript 设计模式与开发实践读书>这本书,刚开始阅读前两章内容,和大家分享下我觉得可以在项目中用的上的一些笔记. 我的 github 项目会不定时更新,有需要的同学可以移步到我的 github 中去查看源码: https://github.com/lichenbuliren/design-mode-notes 1.currying 函数柯里化 currying 又称 部分求值 .一个 cu

JavaScript设计模式与开发实践 – 观察者模式 http://web.jobbole.com/87809/

概述 观察者模式又叫发布 – 订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个目标对象(为了方便理解,以下将观察者对象叫做订阅者,将目标对象叫做发布者).发布者的状态发生变化时就会通知所有的订阅者,使得它们能够自动更新自己. 观察者模式的使用场合就是:当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式. 观察者模式的中心思想就是促进松散耦合,一为时间上的解耦,二为对象之间的解耦.让耦合的

【读书】JavaScript 设计模式与开发实践

2016.08.30 <JavaScript 设计模式与开发实践> 曾探 人民邮电出版社 2016年5月第1版 p13 找到变化的部分并封装之,以使得容易替换:而剩下的就是不变的部分. P49 函数柯里化(currying)的作用是多次收集参数,然后作为数组传给处理函数再一次执行. 其意义在于预处理--将预处理的流程放到一个函数里会更为清晰可控. P57 惰性加载函数 在函数内部重写引用函数的外部变量的引用,从而在第一次"调用"此变量后,此变量就指向新的正确的函数. p84

【摘】JavaScript设计模式与开发实践--单例模式

本文章所有内容均摘自<Javascript设计模式与开发实践>一书(有兴趣的可以购买),加入了一点点自己的理解,写这篇文章的目的是,加强自身对设计模式的理解,以及对于没有接触过这一块的入门者的参考. 阅读本章内容,需要具备Javascript面向对象的知识,否则阅读起来可能会些许困难. 设计模式 单例模式 策略模式 代理模式 迭代器模式 发布-订阅模式 命令模式 组合模式 模板方法模式 享元模式 职责链模式 中介者模式 装饰者模式 状态模式 适配器模式 单例模式 单例模式的定义:保证一个类仅有

JavaScript设计模式与开发实践——JavaScript的多态

"多态"一词源于希腊文polymorphism,拆开来看是poly(复数)+ morph(形态)+ ism,从字面上我们可以理解为复数形态. 多态的实际含义是:同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果.换句话说,给不同的对象发送同一个消息的时候,这些对象会根据这个消息分别给出不同的反馈. 从字面上来理解多态不太容易,下面我们来举例说明一下. 主人家里养了两只动物,分别是一只鸭和一只鸡,当主人向它们发出"叫"的命令时,鸭会"嘎嘎嘎&q

JavaScript设计模式与开发实践 – 观察者模式

概述 观察者模式又叫发布 – 订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个目标对象(为了方便理解,以下将观察者对象叫做订阅者,将目标对象叫做发布者).发布者的状态发生变化时就会通知所有的订阅者,使得它们能够自动更新自己. 观察者模式的使用场合就是:当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式. 观察者模式的中心思想就是促进松散耦合,一为时间上的解耦,二为对象之间的解耦.让耦合的

JavaScript设计模式与开发实践【第一部分】

今天开始阅读<JavaScript设计模式与开发实践>,对于设计模式的学习一直渴望已久. 设计模式的定义是:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案. 其实平时在工作中不知不觉在使用某些设计模式,只是我们不知道而已. 动态类型语言和静态类型语言 静态类型语言在编译时便已确定变量的类型,而动态类型语言的变量类型要到程序运行的时 候,待变量被赋予某个值之后,才会具有某种类型. 静态类型语言的优点首先是在编译时就能发现类型不匹配的错误,编辑器可以帮助我们提前 避免程序在运行期间有可

javascript设计模式与开发实践阅读笔记(3)——高阶函数的其他应用

高阶函数的其他应用 1.currying 函数柯里化,又称部分求值,一个currying 的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来.待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值. var cost = (function(){ var args = []; return function(){ if ( arguments.length === 0 ){ var money =

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

前言 设计模式的定义是:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案. 从某些角度来看,设计模式确实有可能带来代码量的增加,或许会把系统的逻辑搞的更复杂.但软件开发的成本并非全部在开发阶段,设计模式的作用是让人们写出可复用和可维护性高的程序. 所有设计模式的实现都遵循一条原则,即“找出程序中变化的地方,并将变化封装起来”. 不变和稳定的部分是非常容易复用的. 分辨模式的关键是意图而不是结构 模式只有放在具体的环境下才有意义,辨别模式的关键是这个模式出现的场景,以及为我们解决的问题.