JS的进阶技巧

2,417 阅读9分钟
原文链接: www.cnblogs.com
peiyu1988
博客园    首页    新随笔    联系    订阅 订阅    管理 随笔 - 25  文章 - 0 评论 - 67 trackbacks - 0
< 2018年5月 >
29 30 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 1 2
3 4 5 6 7 8 9

昵称:peiyu1988
园龄:1年1个月
粉丝:40
关注: 1 +加关注

搜索

   

常用链接

我的标签

随笔档案

最新评论

  • 1. Re:JS的进阶技巧
  • 强无敌
  • --webgrossmaker
  • 2. Re:Nodejs经验谈
  • 又看了一遍,不同的收获,赞楼主。
  • --webgrossmaker
  • 3. Re:Nodejs经验谈
  • @张泰峰行家呀!!!我们的智能网关就是node开发的。...
  • --peiyu1988
  • 4. Re:Nodejs经验谈
  • nodejs适合做网关之类高并发接口的东西 可以把整个公司的资源动员起来
  • --张泰峰
  • 5. Re:Nodejs经验谈
  • @影踪派嗯,nodejs不适合做逻辑复杂的应用(虽说async promise解决了套娃问题),但是做微服务,分布式服务,他真的是目前最适合的语言。前几天与朋友(阿里员工)吃饭,他说阿里已经解决了no......
  • --peiyu1988

阅读排行榜

评论排行榜

推荐排行榜

JS的进阶技巧

前言

你真的了解JS吗,看完全篇,你可能对人生产生疑问。

typeof

typeof运算符,把类型信息当做字符串返回。

//正则表达式 是个什么 ?

typeof /s/     // object

//null

typeof null   // object

正则表达式并不是一个‘function’,而是一个object。在大多数语言中,null 代表的是一个空指针(0x00),但是在js中,null为一个object。

instanceof

instanceof运算符,用来测试一个对象在其原型链中是否存在一个构造函数:prototype

//语法 object instanceof constructor 

function Person(){};
var p =new Person();
p instanceof Person;  //true

[] instanceof window.frames[0].Array  // false

因为 Array.prototype !== window.frames[0].Array.prototype ,因此,我们必须使用Array.isArray(obj)或者Object.prototype.toString.call(obj) === "[object Array]" 来判断obj是否为数组。

Object.prototype.toString

根据上面提到的,可以使用该方法获取对象类型的字符串。

//call的使用可以看博主前面的文章。(使用apply亦可)

var toString = Object.prototype.toString;

toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
toString.call(/s/); // [object RegExp]
toString.call([]); // [object Array]
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]

作用域安全与构造函数

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

function Dog(name, age){
    this.name = name;
    this.age = age;
}

let dog = new Dog("柴犬", 5);

dog.name // 柴犬

如果我们没有使用new又会如何?

let dog = Dog("柴犬", 5);

dog.name // undefined
window.name // 柴犬

这是因为在没有使用new关键字时,this在当前情况被解析成window,所以属性就被分配到window上了。

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

let dog1 = new Person("柴犬", 5);
dog1.name // 柴犬

let dog2 = Dog("柯基犬", 20);
dog2 .name // 柯基犬

使用上面的方法,就可以再不使用new的情况下,正常构造函数。

惰性载入函数

一个函数如下:

function foo(){
    if(a != b){
        console.log('111') //返回结果1
    }else{
        console.log('222') //返回结果2
    }
}

a和b是不变的,那么无论执行多少次,结果都是不变的,但是每一次都要执行if判断语句,这样就造成了资源浪费

而惰性载入函数,便可以解决这个问题。

function foo(){
    if(a != b){
        foo = function(){
            console.log('111')
        }
    }else{
        foo = function(){
            console.log('222')
        }
    }
    return foo();
}
var foo = (function foo(){
    if(a != b){
        return function(){
            console.log('111')
        }
    }else{
        return function(){
            console.log('222')
        }
    }
})();

如上函数所示:第一次执行后便会对foo进行赋值,覆盖之前的函数,所以再次执行,便不会在执行if判断语句。

fun.bind(thisarg[,arg1[,arg2[,....]]])绑定函数

thisarg:当绑定函数被调用时,该参数会作为原函数运行时的this指向。当使用new时,该参数无效。

arg:当绑定时,这些参数将传递给被绑定的方法。

例子:

let person = {
   name: 'addone',
   click: function(e){
       console.log(this.name)
   }
}

let btn = document.getElementById('btn');
EventUtil.addHandle(btn, 'click', person.click);

这里创建了一个person对象,然后将person.click方法分配给DOM,但是当你按按钮时,会打印undefied,原因是this指向了DOM而不是 person。

解决方法,当时是使用绑定函数了:

 EventUtil.addHandle(btn, 'click', person.click.bind(person));

函数柯里化

柯里化是把接受多个参数的函数转变成接受单一参数的函数。

//简单例子,方便你明白柯里化
function add(num1, num2){
    return num1 + num2;
}
function curryAdd(num2){
    return add(1, num2);
}
add(2, 3) // 5
curryAdd(2) // 3

下面是柯里化函数的通用方法:

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

Array.prototype.slice.call(arguments, 1)来获取第一个参数后的所有参数。在函数中,同样调用 Array.prototype.slice.call(arguments)让innerArgs存放所有的参数, 然后用 contact将内部外部参数组合起来,用apply传递函数。

function add(num1, num2){
    return num1 + num2;
}
let curryAdd1 = curry(add, 1);
curryAdd1(2); // 3

let curryAdd2 = curry(add, 1, 2);
curryAdd2(); // 3

不可扩展对象

默认情况下对象都是可扩展的,无论是扩展属性或是方法。

let dog = { name: '柴犬' };
dog.age = 5;

如第二行,我们为dog扩展了age属性。

使用Object.preventExtensions()可以阻止扩展行为。

let dog = { name: '柴犬' };
Object.preventExtensions(dog);
dog.age = 20;

dog.age // undefined

还可以使用 Object.isExtensible()来判断对象是否支持扩展。

let dog = { name: 'addone' };
Object.isExtensible(dog); // true

Object.preventExtensions(dog);
Object.isExtensible(dog); // false。

密封的对象

密封后的对象不可扩展,且不能删除属性和方法。

使用Object.seal()来进行密封。

let dog = { name: '柴犬' };
Object.seal(dog);

dog.age = 20;
delete dog.name;

dog.age // undefined
dog.name // 柴犬

当然也有Object.isSealed()来判断是否密封

let dog = { name: '柴犬' };
Object.isExtensible(dog); // true
Object.isSealed(dog); // false

Object.seal(dog);
Object.isExtensible(dog); // false
Object.isSealed(dog); // true

冻结对象

冻结对象为防篡改级别最高的,密封,且不能修改。

使用Object.freeze()来进行冻结。

let dog= { name: '柴犬' };
Object.freeze(dog);

dog.age = 20;
delete dog.name;
dog.name = '吉娃娃'

dog.age // undefined
dog.name // 柴犬

当然也有Object.isFrozen()来判断是否冻结

let dog = { name: '柴犬' };
Object.isExtensible(dog); // true
Object.isSealed(dog); // false
Object.isFrozen(dog); // false

Object.freeze(dog);
Object.isExtensible(dog); // false
Object.isSealed(dog); // true
Object.isFrozen(dog); // true

数组分块

浏览器对长时间运行的脚本进行了制约,如果运行时间超过特定时间或者特定长度,便不会继续执行。

如果发现某个循环占用了大量的时间,那么就要面对下面两个问题:

1.该循环是否必须同步完成?

2.数据是否必须按顺序完成?

如果是否,那么我们可以使用一种叫做数组分块的技术。基本思路是为要处理的项目创建一个列队,然后使用定时取出一个要处理的项目进行处理,以此类推。

function chunk(array, process, context){
    setTimeout(function(){
        // 取出下一个项目进行处理
        let item = array.shift();
        process.call(item);
        
        if(array.length > 0){
            setTimeout(arguments.callee, 100);
        }
    }, 100)
}

这里设置三个参数,要处理的数组,处理的函数,运行该函数的环境。

节流函数

节流函数目的是为了防止某些操作执行的太快,比如onresize,touch等事件。这种高频率的操作可能会使浏览器崩溃,为了避免这种情况,可以采用节流的方式。

function throttle(method, context){
    clearTimeout(method.tId);
    method.tId = setTimeout(function(){
        method.call(context);
    }, 100)
}

这里接收两个参数,要执行的函数,和执行的环境。执行时先clear之前的定时器,然后将当前定时器赋值给方法的tId,之后调用call来确定函数的执行环境。

function resizeDiv(){
    let div = document.getElementById('div');
    div.style.height = div.offsetWidth + "px";
}

window.onresize = function(){
    throttle(resizeDiv);
}
posted on 2018-05-16 09:32 peiyu1988 阅读(13) 评论(0) 编辑 收藏 刷新评论刷新页面返回顶部 注册用户登录后才能发表评论,请 登录注册访问网站首页。
  • 【推荐】超50万VC++源码: 大型组态工控、电力仿真CAD与GIS源码库!
  • 【活动】2050 大会 - 年青人因科技而团聚(5.26-5.27 杭州·云栖小镇)
  • 【活动】缺钱怎么办?5万内你尽管花!
  • 【推荐】华为云DevCloud精彩活动集结,重磅福利,免费领取!
  • 【活动】腾讯云云服务器新购特惠,5折上云
  • 【大赛】2018首届“顶天立地”AI开发者大赛
  • 腾讯云0509 最新IT新闻:
    · 亚马逊与初创公司Kaleido合作 正式进军区块链领域
    · 唯品会大跌近20% FANNG五大科技巨头齐下挫
    · 2017年平均工资出炉 IT业超13万元居首
    · OPPO官微曝光新产品形态 将推红蓝手机
    · 微软宣布Surface Hub 2,支持4屏无缝拼接
    » 更多新闻... 最新知识库文章:
    · 评审的艺术——谈谈现实中的代码评审
    · 如何高效学习
    · 如何成为优秀的程序员?
    · 菜鸟工程师的超神之路 -- 从校园到职场
    · 如何识别人的技术能力和水平?
    » 更多知识库文章... Copyright ©2018 peiyu1988 Powered by: 博客园 模板提供:沪江博客