前言

你真的了解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) //
curryAdd(2) //

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

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); // let curryAdd2 = curry(add, 1, 2);
curryAdd2(); //

不可扩展对象

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

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);
}

JS的进阶技巧的更多相关文章

  1. 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制

    [原创]分布式之数据库和缓存双写一致性方案解析(三)   正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...

  2. JS处理事件小技巧

    今天,就分享一下我自己总结的一些JS的小技巧: ①防止鼠标选中事件 <div class="mask" onselectstart="return false&qu ...

  3. JS 一些常用技巧

    记录 JS 常用的技巧 1. 生成随机数 2. 解决浮点数问题 3. 无路可走时,看看是不是 事件 冒泡了...

  4. js基础进阶--关于setTimeout的思考

    欢迎访问我的个人博客:http://www.xiaolongwu.cn 先热身 看看下面的额代码会打印出什么? for (var i = 0; i < 5; i++) { setTimeout( ...

  5. js基础进阶--图片上传时实现本地预览功能的原理

    欢迎访问我的个人博客:http://www.xiaolongwu.cn 前言 最近在项目上加一个图片裁剪上传的功能,用的是cropper插件,注意到选择本地图片后就会有预览效果,这里整理一下这种预览效 ...

  6. 《前端之路》之 JavaScript 进阶技巧之高阶函数(下)

    目录 第二章 - 03: 前端 进阶技巧之高阶函数 一.防篡改对象 1-1:Configurable 和 Writable 1-2:Enumerable 1-3:get .set 2-1:不可扩展对象 ...

  7. Chrome JS断点调试技巧

    Chrome调试折腾记_(2)JS断点调试技巧 技巧一:格式化压缩代码 技巧二:快速跳转到某个断点的位置 技巧三:查看断点内部的作用范围[很实用] 技巧4:监听事件断点 技巧5:DOM及 XHR监听跳 ...

  8. 14条最佳JS代码编写技巧

    http://gaohaixian.blog.163.com/blog/static/123260105201142645458315/写任何编程代码,不同的开发者都会有不同的见解.但参考一下总是好的 ...

  9. SQL优化之SQL 进阶技巧(下)

    上文( SQL优化之SQL 进阶技巧(上) )我们简述了 SQL 的一些进阶技巧,一些朋友觉得不过瘾,我们继续来下篇,再送你 10 个技巧 一. 使用延迟查询优化 limit [offset], [r ...

随机推荐

  1. C语言中sizeof与strlen区别

    本文转载自:http://www.2cto.com/kf/201109/105100.html 1. 以字符串形式出现的,编译器都会为该字符串自动添加一个0作为结束符,如在代码中写"abc& ...

  2. Leetcode_34_Search for a Range

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/44021767 Given a sorted array o ...

  3. Leetcode_121_Best Time to Buy and Sell Stock

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/43024967 Say you have an array ...

  4. 【一天一道LeetCode】#6 ZigZag Conversion

    一天一道LeetCode系列 (一)题目 The string "PAYPALISHIRING" is written in a zigzag pattern on a given ...

  5. Unix - ls命令的简要实现

    #include <dirent.h> 是POSIX.1标准定义的unix类目录操作的头文件,包含了许多UNIX系统服务的函数原型,例如opendir函数.readdir函数. opend ...

  6. HBase运维经验

    http://www.qconbeijing.com/download/Nicolas.pdf 重点看了下facebook做了哪些改进以及他们的运维经验,比较重要的有以下几点: 改进: 1 加强了行级 ...

  7. SharePoint 2013配置启用搜索服务

    1.安装完毕SharePoint 2013,新建网站集,点击搜索,出现如下错误(因为没配置,别激动). 2.尝试启动服务器场中的服务之SharePoint Server Search,提示新建搜索应用 ...

  8. ruby读取源代码自身的一种方法

    我们知道ruby中如果源代码中一行开头(必须在行的开头)有__END__标示,则表示下面的都是数据行,可以用IO对象DATA来访问这些行.但是如果我们用DATA.rewind一下的话,就可以将文件流指 ...

  9. 服务端搭建——腾讯云通信(IM)

    前言 在手机app中因为需要即时聊天功能,在项目采用腾讯云通信服务.如下流程图: 当手机端拿到签名后,就可登录IM,使用im提供的sdk收发信息. 准备工作 1.在腾讯云注册获取appid 2.申请开 ...

  10. spring是如何管理 事务的

    Spring提供的事务管理可以分为两类:编程式的和声明式的.编程式的,比较灵活,但是代码量大,存在重复的代码比较多:声明式的比编程式的更灵活方便.  1.传统使用JDBC的事务管理  以往使用JDBC ...