【红宝书】第22章高级技巧

1.高级函数

1.1安全类型检测

typeof在Safari(第4版修复)老版中对正则表达式应用返回function,instanceof操作符存在多个全局作用域(像一个页面包含多个frame)会有问题,因此该两种检测类型都有一定局限

在任何值上调用Object原生的toString()方法,都会返回一个[Object NaticeConstructorName]格式的字符串。

Object.prototype.toString.call(arr) === "[object Array]"
Object.prototype.toString.call(fn) == "[object Function]"
Object.prototype.toString.call(regexp) == "[object RegExp]"

1.2作用域安全的构造函数

构造函数就是一个使用new操作符调用的函数。当使用new调用时,构造函数内用到的this对象会指向新创建的对象实例

        function Person(name, age, job) {
            this.name = name
            this.age = age
            this.job = job
        }
        let person = new Person(‘lpr‘, 23, ‘程序员‘)

问题在当没有使用new操作符时来调用改构造函数,由于this是在运行时绑定的,所以this会直接映射到全局对象window上,导致错误对象属性的意外增加

        let person = Person(‘lpr‘, 23, ‘程序员‘)
        console.log(window.name) // ‘lpr‘

解决方法是创建作用域安全的构造函数

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

该方法下使用构造函数窃取模式的继承且不使用原型链会破坏这个继承

      function Polygon(sides) {
        if (this instanceof Polygon) {
          this.sides = sides;
        } else {
          return new Polygon(sides);
        }
      }
      function Rectangle(width, height) {
        Polygon.call(this,2);
        this.width = width;
        this.height = height;
      }
      let rect = new Rectangle(5, 10);
      console.log(rect.sides); //undefined

可以使用构造函数窃取+原型链或寄生组合结合

      function Polygon(sides) {
        if (this instanceof Polygon) {
          this.sides = sides;
        } else {
          return new Polygon(sides);
        }
      }
      function Rectangle(width, height) {
        Polygon.call(this,2);
        this.width = width;
        this.height = height;
      }
      Rectangle.prototype = new Polygon();
      let rect = new Rectangle(5, 10);
      console.log(rect.sides); //2

1.3惰性载入函数

惰性载入表示函数执行的分支只会发生一次

方法1:

函数被调用时再处理函数。在第一次调用的过程中该函数会覆盖为另外一个按合适方式执行的函数,这样任何对原函数的调用都不用再经过执行的分支。

        function fn() {
            if () {
                fn = function () {
                    // doSomething
                }
            } else if () {
                fn = function () { }
            } else {
                fn = function () { }
            }
            return fn()
        }

在这个惰性载入的函数fn()中,if语句的每一个分支都会为变量fn赋值,有效覆盖了原有的函数。最后一步调用新赋的函数。下一次调用fn()的时候就会直接调用被分配的函数。

方法2:

声明函数时就指定适当函数。这样第一次调用函数时就不会损失性能,而在代码首次加载时会损失一点性能。

        let fn = (function() {
            if () {
                return function () {
                    // doSomething
                }
            } else if () {
                return function () { }
            } else {
                return function () { }
            }
        })()

该技巧就是创建一个匿名,自执行的函数,用以确定应该使用哪一个函数的实现。实际的逻辑都一样,不一样的地方就是第一行代码用let定义了函数、新增了自执行的匿名函数,另外每个分支都返回正确的函数定义,以便立即将其赋值给fn 

1.4函数绑定

函数绑定就是创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。

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

ES5为函数定义了原生bind()方法

fn.bind(context)

1.5函数柯里化

函数柯里化用于创建已经设置好一个或多个参数的函数。

2.防篡改对象

一旦被对象防篡改就无法撤销了

2.1不可扩展对象

默认情况下,所有对象都可扩展,即任何时候都可以向对象中添加属性和方法。用以下方法

阻止扩展:Object.preventExtensions(obj)

检测是否可扩展:Object.isExtensible(obj)   // true or false

2.2密封对象

密封对象不可扩展,且其已有属性的特性configurable为false,即不能删除其属性和方法,不能使用Object.defineProperty()把数据属性修改为访问器属性或者相反,但能修改值,

密封对象:Object.seal(obj)

检测是否被密封:Object.isSealed(obj) // true or false

2.3冻结对象

密封且不可修改值。congfigurable为false,writable为false。

冻结对象:Object.freeze(obj)

检测是否冻结:Object.isFrozen(obj)

3.高级定时器

js运行在单线程的环境中,定时器并不是线程,仅仅只是计划代码在未来的某个时间执行。

3.1重复的定时器

setInterval()有2个问题:1.某些间隔会被跳过;2:多个定时器的代码执行之间的间隔可能会比预期小。

假设某个事件处理程序设置一个200ms间隔的setInterval,而事件处理程序花了300ms,就会同时出现跳过间隔且连续运行定时器代码的情况。解决方法:

      setTimeout(function(
        // 处理中
        setTimeout(arguments.callee,interval)
      ),interval)

好处:在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。而且他可以保证在下一次定时器代码执行前,至少要等待指定的间隔,避免了连续的运行。

原文地址:https://www.cnblogs.com/Mijiujs/p/12254204.html

时间: 2024-10-10 10:20:25

【红宝书】第22章高级技巧的相关文章

OPENGL 红宝书实验笔记

第一个程序triangles的配置过程,原文链接. OpenGL的东西快忘光了,把角落的第八版红宝书拿出来复习一下 从书中的地址下了个示例代码结果新系统(Win10+VS2015)各种跑不起来,懊恼之后在网上疯狂搜索资料终于跑起来了,记录一下 一.环境搭建指南 书中的地址 http://www.opengl-redbook.com/ 去这里打包下载OpenGL红宝书的示例代码,解压后是这样 虽然没有第一章的代码但第一章的内容好歹算一个完整的例子,网上各种环境搭建教程也都以第一章的代码为例,我们就

熬了多少个夜晚,大家期待的《网络工程师思科华为华三实战案例红宝书》即网工必备技术命令大全版本1完书

熬了多少个夜晚,最近也没空更新博客.军哥编写的大家期待的<网络工程师思科华为华三实战案例红宝书>即网工必备技术命令大全版本1完书,一本融合了思科华为华三的实战型辅导书(辅助乾颐堂QCNA课程的).不多说上图 目录关于作者 2本书读者和笔者心语 3本书内容和结构 4第1部分 网络实施基础 15案例0 模拟器的部署和连接管理 16学习利器模拟器简书 160.1 华为模拟器Ensp部署 160.2 思科模拟器EVE部署 310.3 部署SecureCrt管理网络设备 400.3.1 部署终端管理软件

【转载】关于在vs2013中配置opengl红宝书第八版环境

 本文为转载 原文地址 http://blog.csdn.net/qq821869798/article/details/45247241 本人刚开始学习opengl,买了一本opengl红宝书第八版, 第一个例子研究了一段时间终于可以运行了,不知道有没有童鞋跟我遇到一样的问题. 下面说说我怎么配置的: 首先去 http://www.opengl-redbook.com/ 下载红宝书的源代码,解压得到这个 然后打开vs2013新建一个空的win32控制台项目, 然后点项目右键属性,点击vc++目

VS2012通过makefile编译OpenGL红宝书的示例代码

> 通过创建新VC项目,然后设置一堆属性,对于懒人来说还是太复杂了.既然它自带了makefile,可以尝试下使用nmake. 需要注意的是VS2012的安装目录里面已经没有GL的头文件和库文件.这个改动应该在VS2010或者更早就已经采用了. 现在有了VS SDK.VS2010自动的SDK目录是C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A,更高的版本可能使用v8.0.v8.0A,反正都在这个目录下面.这个目录下面有include.lib文

[OpenGL红宝书]第一章 OpenGL概述

第一章 OpenGL概述 标签(空格分隔): OpenGL 第一章 OpenGL概述 1 什么是OpenGL 2 初识OpenGL程序 3 OpenGL语法 4 OpenGL渲染管线 41 准备向OpenGL传输数据 42 将传输数据到OpenGL 43 顶点着色 44 细分着色 45 几何着色 46 图元装配 47 剪切 48 光栅化 49 片元着色 410 逐片元的操作 5 第一个程序深入分析 51 进入main函数 52 OpenGL的初始化过程 初始化顶点数组对象 分配顶点缓存对象 将数

【红宝书】第8章.BOM

浏览器对象模型,用于访问浏览器的功能.W3C为了把浏览器中JS最基本的部分标准化,已将BOM的主要方面纳入HTML5规范. 8.1 window对象 BOM的核心,表示浏览器实例.在浏览器中,window对象即是通过JS访问浏览器窗口的一个接口,又是ECMAScript规定的Global对象. 8.1.1全局作用域 由于window对象扮演着ECMAScript中的Global对象,所有在全局作用域中声明的变量.函数都会变成window对象的属性和方法. 全局变量不能通过delete操作符删除,

【红宝书】第6章.面向对象的程序设计

面向对象(Object-Oriented,OO) 类 6.1理解对象 创建Object的实例,然后添加属性和方法 let person = new Object(); person.name = "AAA"; person.sayName = function() {}; 对象字面量模式 let person = { name: "AAA", sayName: function() {} }; 6.1.1属性类型 用特性(attribute)描述属性(propert

【红宝书】第7章.函数表达式

定义函数的方法两种 函数声明 function fnName(arg0, arg1, arg2) { //函数体 } 重要特征:函数声明提升 函数表达式 let fnName = function(arg0, arg1, arg2) { //函数体 } 即创建一个匿名函数(因为function关键字后面没有标识符)赋值给变量fnName 使用前必须先赋值 7.1递归 递归函数是一个函数通过名字调用自身的情况下构成的 function fn(num) { if (num <= 1) { retur

【红宝书】第21章Ajax与Comet

AJAX是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术 XMLHttpRequest对象 1.1XHR的用法 let xhr = new XMLHttpRequest() open()方法不会真正发送请求,而只是启动一个请求以备发送,接收3个参数:要发送的请求类型.请求URL.是否异步发送请求 xhr.open("get","example.php",false) 发送特定请求,调用send()方法.接收1个参数,即要作为请求主体发送的数据.若没有数据