JS高级技巧笔记

使用Object.prototype.toString.call(value)区分数据类型

使用typeof检测,只能区分基本类型的具体类型,而对于引用类型只能统一返回object。而使用Object.prototype.toString.call(value)能够确切返回基本、引用类型的数据的具体类型,只要这个数据的构造函数是原生而非自定义的。
官方文档中对这个方法的描述是:

When the toString method is called, the following steps are taken:
If the this value is undefined, return “[object Undefined]“.
If the this value is null, return “[object Null]“.
1. Get the [[Class]] property of this object.
2. Compute a string value by concatenating the three strings “[object “, Result (1), and “]”.
3. Return Result (2)

每个类内部都有一个class属性,就是原生构造函数名。调用这个方法的时候会去查找这个属性。

作用域安全的构造函数

在对对象的属性进行任何更改之前,首先确定this是否指向正确的对象,如果不是,则创建一个新的实例并返回。这样做的目的在于如果没有使用new 调用构造函数,那么this指向window,构造函数中的属性名可能会和window对象的属性同名而造成覆盖:

function Person(name,age,gender){
    if(this instanceof Person){
        this.name=name;
        this.age=age;
        this.gender=gender
    }else{
        return new Person(name,age,gender);
    }
}

这样,用下面两种方式调用,都可以得到想要的结果:

var person1=new Person('mike',20,'male');
alert(person1.name);//mike
var person2=Person('lily',10,'female');
alert(person2.name);//ily

避免了意外向全局对象上设置属性。
但是这样的方式在使用构造函数继承的时候会出现问题,但是搭配原型链继承就不会了(instanceof对祖先类进行检测也是返回true)。

function Chinese(province,name,age,gender){
    if(this instanceof Chinese){
        Person.call(this,name,age,gender); //构造函数继承
        this.province=province;
    }else{
        return new Chinese(province,name,age,gender);
    }

}
Chinese.prototype=new Person();  //原型链继承

var c1 = new Chinese("sichuan","lily",10,"female");
alert(c1 instanceof Chinese);  //true
alert(c1 instanceof Person);  //true

再来回顾一遍原型和构造函数组合的继承方式是什么样的过程:
下面是一幅原型继承的图解:
这里写图片描述

通过原型链继承,子类的原型对象就是一个父类的实例,它可以拿到父类实例中的所有属性,包括:

指向父类原型对象的prototype指针—>构成原型链
父类的实例属性

而通过构造函数继承,子类获得了实例属性,包括:

父类的实例属性—>覆盖掉通过原型方式继承的父类实例属性

这样,再加上子类自己的原型属性(方法)和实例属性(方法),就得到了一个完整的子类。

需要注意的一点是通过原型继承,SubType.prototype.constructor==SuperType,可以进行更改:
SubType.prototype.constructor==SubType

惰性载入函数

充分利用函数名也是一个指针,在第一次运行的时候就指向真确的if判断分支,下次再运行的时候就不必再进行一次if判断,而是直接执行分支中的内容。

函数绑定

就是想在某个this环境中持有另一个this环境中的变量,也就是说在某个A- this所在的代码环境中的某一段,要更改this为B-this。
一种方法是利用闭包屏蔽掉外部函数的this,但闭包层次多了代码不好理解。还有一种方法是使用bind来保持this上下文。
函数绑定的用途:函数作为参数传递,同时函数又必须在特定的环境中执行,常用于事件处理程序和setTimeout等函数中。

ar handler={
    message:"event handler",
    handlerClick:function(event){
       alert(this.message);
    }
}

btn.addEventListener('click',handler.handlerClick.bind(handler));

函数柯里化

首先看一个概念,函数的内置对象arguments并不是一个真正的数组对象,使用:

Array.prototype.slice.call(arguments,0)

可将具有length属性的对象转换为数组对象。直接使用arguments.slice会报错。
函数柯里化就是一个函数内部返回一个闭包,并且返回的函数在调用的时候还需要传入一些参数。形式如下:

function curry(fn){
    var args=Array.prototype.slice.call(arguments,1);

    return function(){
        var innerArgs=Array.prototype.slice.call(arguments,0);
        var finnalArgs=args.concat(innerArgs);
        return fn.apply(null,finnalArgs); //还未制定特定的环境
    }
}

JS的bind方法也实现了柯里化,只需在参数this之后传入别的参数就行。这常用于给事件处理程序传入除了event之外的参数。

函数柯化有什么用呢,查看了张鑫旭大牛的博客,上面总结了三个好处:

  • 参数复用
    在调用curry函数的时候传入一个统一的参数,返回的函数可以在后面调用的时候根据自己的需要传入各种各样的参数。
  • 提前返回
    在跨浏览器的事件绑定函数中,要做if判断,但是每次调用都做判断就会降低效率,其实一次判断就可以了;并且不同的浏览器需要不同的参数,可以在返回函数中实现。这样很适合用柯里化:
var addEvent = (function(){
    if (window.addEventListener) {
        return function(el, sType, fn, capture) {
            el.addEventListener(sType, function(e) {
                fn.call(el, e);
            }, (capture));
        };
    } else if (window.attachEvent) {
        return function(el, sType, fn, capture) {
            el.attachEvent("on" + sType, function(e) {
                fn.call(el, e);
            });
        };
    }
})();
  • 延迟执行
    不断的柯里化,累积传入的参数,最后执行。
    bind函数就是一个延迟执行的函数,它内部的实现就是一个柯里化:
Function.prototype.bind = function(context) {
    var _this = this,
    _args = Array.prototype.slice.call(arguments, 1);
    return function() {
        return _this.apply(context, _args.concat(Array.prototype.slice.call(arguments)))
    }
}

自定义事件

取得自定义的属性值使用getAttribute(),而元素内置的属性,例如style、id等就直接使用ele.arrName来获取。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值