资讯专栏INFORMATION COLUMN

JavaScript 高级技巧——“高级函数”的注意要点

solocoder / 2883人阅读

摘要:语法如下注意这里使用的并不是的,是内部函数的。函数柯里化的基本方法是使用一个闭包返回一个函数。当函数被调用时,返回的函数还需要设置一些传入的参数。

安全的类型检测

typeof操作符

检测数据类型的结果可能会不正确;

instanceof操作符

操作符在多个全局作用域下存在问题:

var value = [];
var isArray = value instanceof Array;
console.log(isArray);

上述代码都在全局作用域,返回true;但如果value在其他frame中,则返回false。

JSON对象

该对象也难以确定是否为原生对象;

解决办法:

因为在任何值上调用Object原生的toString()方法,都返回一个[Object NativeConstructorName]格式的字符串。每个类在内部都有一个[[Class]]属性,这个属性指定了上述字符串中构造函数的函数名,如:

console.log(Object.prototype.toString()); //[object Object]
//利用call():
var value = [];
console.log(Object.prototype.toString.call(value)); //[object Array]
//进一步完善:
function whichType (value) {
    console.log(Object.prototype.toString.call(value));
}
whichType("Obj"); //[boject String]
whichType(["hello"]); //[object Array]
whichType(321); //[object Number]
//检测是否为函数:
function isFunction (value) {
    return Object.prototype.toString.call(value) == "[object Function]";
}
console.log(isFunction(Object.prototype.toString)); //true
//检测原生JSON对象:
console.log(window.JSON && Object.prototype.toString.call(JSON) == "[object JSON]");

不适用于IE中COM对象形式实现的函数

作用域安全的构造函数

当使用new调用构造函数时,构造函数内用到的this对象会指向新创建的对象实例,如:

function Person (name) {
    this.name = name;
}
var person = new Person("oliver");
console.log(person.name);

问题是当没有使用new操作符,直接调用构造函数,this会映射到全局对象window上,导致错误对象属性的意外增加:

function Person (name) {
    this.name = name;
}
var person = Person("oliver");
console.log(window.name); //oliver

解决办法是创建一个作用域安全的构造函数:

function Person(name) {
    if (this instanceof Person) { //如果this是Person的实例
        this.name = name;
    } else {
        return new Person(name); //否则调用new操作符
    }
}
var person1 = Person("oliver");
console.log(person1.name); //oliver
var person2 = new Person("troy");
console.log(person2.name); //troy
console.log(window.name); //""

但是,如果使用构造函数窃取模式的继承且不实用原型链,那么这个继承很可能被破坏如:

function Person(name) {
    if (this instanceof Person) { //如果this是Person的实例
        this.name = name;
    } else {
        return new Person(name); //否则调用new操作符
    }
}
function People (name,age) {
    Person.call(this, name);
    this.age = age;
}
var p = new People("Oliver", 18);
console.log(p.name); //undefined
console.log(p.age); //18

结合使用原型链或者寄生组合则可以解决这个问题:

function Person(name) {
    if (this instanceof Person) { //如果this是Person的实例
        this.name = name;
    } else {
        return new Person(name); //否则调用new操作符
    }
}
function People (name,age) {
    Person.call(this, name);
    this.age = age;
}
People.prototype = new Person(); //关键点
var p = new People("Oliver", 18);
console.log(p.name); //Oliver
console.log(p.age); //18
惰性载入函数

惰性函数就是函数执行的分支仅会发生一次。

第一种

就是在函数被调用时再处理函数:

function createXHR () {
    if (typeof XMLHttpRequest !== "undefined") {
        createXHR = function () { //关键点
            return new XMLHttpRequest();
        }
    } else if (typeof ActiveXObject !== "undefined") {
        createXHR = function () { //关键点
            return new ActiveXObject(["MSXML2.XMLHttp"]);
        }
    } else {
        createXHR = function () { //关键点
            throw new Error("No XHR object available.");
        }
    }
    return createXHR(); //关键点
}
第二种

就是指定适当的函数:

function createXHR () {
    if (typeof XMLHttpRequest !== "undefined") {
        return function () { //关键点
            return new XMLHttpRequest();
        }
    } else if (typeof ActiveXObject !== "undefined") {
        return function () { //关键点
            return new ActiveXObject(["MSXML2.XMLHttp"]);
        }
    } else {
        return function () { //关键点
            throw new Error("No XHR object available.");
        }
    }
    return createXHR(); //关键点
}
函数绑定

函数绑定要创建一个函数, 可以在特定的this环境中以指定参数调用另一个函数。 该技巧常常和回调函数与事件处理程序一起使用, 以便在将函数作为变量传递的同时保留代码的执行环境。 由于代码之中存在着this变量, 而this在当前环境下指向确定的对象, 但是当更改代码的执行环境时, 就会出现问题了。 为了解决这个问题, javascript函数库中实现了一个bind() 函数来解决这个问题。

一个简单的bind() 函数接收一个函数和一个环境, 并返回一个在给定环境中调用给定函数的函数, 并且将所有参数原封不动传递过去。 语法如下:

function bind(fn, context) {
    return function() {
        return fn.apply(context, arguments);
    }
}

注意这里使用的arguments并不是bind() 的, 是内部函数的。

var handler = {
    message: "Event handled",
    handleClick: function(event) {
        alert(this.message);
    }
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler));

ECMAScript5为所有函数定义了一个原生的bind() 方法, 进一步简化了操作。

var handler = {
    message: "Event handled",
    handleClick: function(event) {
        alert(this.message);
    }
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler));

它们主要用于事件处理程序以及setTimeout() 和setInterval()。 然而被绑定函数与普通函数相比有更多的开销, 它们需要更多内存, 同时也因为多重函数调用稍微慢一些, 所以最好只在必要时使用。

函数柯里化

它用于创建已经设置好了一个或多个参数的函数。 函数柯里化的基本方法是: 使用一个闭包返回一个函数。 当函数被调用时, 返回的函数还需要设置一些传入的参数。

柯里化函数通常由以下步骤动态的创建: 调用另一个函数并为它传入要柯里化的函数和必要参数。 下面是创建柯里化函数的通用方式:

function curry(fn) {
    var args = Array.prototype.slice.call(arguments, 1);
    return function() {
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.concat(innerArgs);
        return fn.apply(null, finalArgs);
    }
}

这种变化也需要额外的开销

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78791.html

相关文章

  • JavaScript 高级技巧——“高级定时器”注意要点

    摘要:为了规避这个问题,可以使用定时器对事件处理程序进行节流。当第二次调用该函数时,它会清除前一次的定时器,并设置另一个。如果前一个定时器已经执行过了,这个操作就没有任何意义。然而如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器。 高级定时器 为了解决setInterval的一些执行问题, 下面是采用链式setTimeout的方式来规避: setTimeout(function()...

    rubyshen 评论0 收藏0
  • JavaScript 高级技巧——“防篡改对象”注意要点

    摘要:防篡改对象不可扩展对象默认情况下,所有对象都是可扩展的不可扩展可以使用这个方法严格模式下会抛出错误一旦设置防扩展,对象就无法添加新的属性和方法。已有的属性方法不受影响,这些属性方法仍然可以修改和删除。检测是否被冻结,用方法 防篡改对象 不可扩展对象 默认情况下,所有对象都是可扩展的: var person = { name: Oliver }; person.age = 18;...

    atinosun 评论0 收藏0
  • JS程序设计高级技巧

    摘要:关于定时器要记住的最重要的事情是指定的时间间隔表示何时将定时器的代码添加到队列,而不是何时实际执行代码。多个定时器之间的执行间隔会比预期的小解决办法处理中数组分块,,函数节流,实际进行处理的方法实际执行的代码初始处理调用的方法 一、高级函数 安全类型检测 Object.protitype.toString.call(value) 作用域安全的构造函数 function Pers...

    Codeing_ls 评论0 收藏0
  • 高级函数技巧-函数柯里化

    摘要:如果你对函数式编程有一定了解,函数柯里化是不可或缺的,利用函数柯里化,可以在开发中非常优雅的处理复杂逻辑。同样先看简单版本的方法,以方法为例,代码来自高级程序设计加强版实现上面函数,可以换成任何其他函数,经过函数处理,都可以转成柯里化函数。 我们经常说在Javascript语言中,函数是一等公民,它们本质上是十分简单和过程化的。可以利用函数,进行一些简单的数据处理,return 结果,...

    shixinzhang 评论0 收藏0
  • 高级函数技巧-函数防抖与节流

    摘要:封装方法也比较简单,书中对此问题也进行了处理使用定时器,让函数延迟秒后执行,在此秒内,然后函数再次被调用,则删除上次的定时器,取消上次调用的队列任务,重新设置定时器。 在实际开发中,函数一定是最实用最频繁的一部分,无论是以函数为核心的函数式编程,还是更多人选择的面向对象式的编程,都会有函数的身影,所以对函数进行深入的研究是非常有必要的。 函数节流 比较直白的说,函数节流就是强制规定一...

    whinc 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<