个人主页:学习前端的小z个人专栏:JavaScript 精粹
本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结,欢迎大家在评论区交流讨论!
文章目录
- 💯JavaScript 中的小 tips
- 📧1 严格模式
- 💞1.1 "use strict" 严格模式
- 💞1.2 开启严格模式
- 💞1.3 全局变量显式声明
- 💞1.4 静态绑定
- 💞1.5 增强的安全措施
- 💞1.6 禁止删除变量
- 💞1.7 显式报错
- 💞1.8 重名错误
- 💞1.9 禁止八进制表示法
- 💞1.10 arguments对象的限制
- 💞1.11 函数必须声明在顶层
- 💞1.12 保留字
- 📧2 值在各种场景的转换规则
- 📧3 错误类型
- 📧4 空值合并运算符 '??'
- 💞4.1 与 || 比较
- 💞4.2 优先级
- 💞4.3 注意:
- 📧5 ===
- 📧6 CONSOLE 控制台输入
- 💞6.1 Console.assert()
- 💞6.2 Console.clear()
- 💞6.3 Console.count()
- 💞6.4 Console.countReset()
- 💞6.5 Console.debug()
- 💞6.6 Console.dir()
- 💞6.7 Console.dirxml()
- 💞6.8 打印信息
- 💞6.9 打印树状结构
- 💞6.10 Console.table()
- 💞6.11 定时器
- 💞6.12 Console.trace()
- 💞6.13 占位符
💯JavaScript 中的小 tips
📧1 严格模式
严格模式是ES5引入
严格模式主要有以下限制:
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用with语句
- 不能对只读属性赋值,否则报错
- 不能使用前缀0表示八进制数,否则报错
- 不能删除不可删除的属性,否则报错
- 不能删除变量delete prop,会报错,只能删除属性delete global[prop]
- eval不会在它的外层作用域引入变量
- eval和arguments不能被重新赋值
- arguments不会自动反映函数参数的变化
- 不能使用arguments.callee
- 不能使用arguments.caller
- 禁止this指向全局对象
- 不能使用fn.caller和fn.arguments获取函数调用的堆栈
- 增加了保留字(比如protected、static和interface)
💞1.1 “use strict” 严格模式
“use strict” 是ES5 中的新指令(ECMAScript version 5)。
"严格模式"体现了Javascript更合理、更安全、更严谨的发展方向,包括IE 10在内的主流浏览器,都已经支持它,许多大项目已经开始全面拥抱它。
💞1.2 开启严格模式
针对脚本
针对函数
function strict(){ "use strict"; return "这是严格模式。"; }
优化形式
//因为第一种调用方法不利于文件合并,所以更好的做法是,借用第二种方法,将整个脚本文件放在一个立即执行的匿名函数之中。 (function (){ "use strict"; // some code here })();
💞1.3 全局变量显式声明
在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,全局变量必须显式声明。
"use strict"; v = 1; // 报错,v未声明 for(i = 0; i < 2; i++) { // 报错,i未声明 }
💞1.4 静态绑定
Javascript语言的一个特点,就是允许"动态绑定",即某些属性和方法到底属于哪一个对象,不是在编译时确定的,而是在运行时(runtime)确定的。
严格模式对动态绑定做了一些限制。某些情况下,只允许静态绑定。也就是说,属性和方法到底归属哪个对象,在编译阶段就确定。这样做有利于编译效率的提高,也使得代码更容易阅读,更少出现意外。
具体来说,涉及以下几个方面。
(1)禁止使用with语句
因为with语句无法在编译时就确定,属性到底归属哪个对象。
"use strict"; var v = 1; with (o){ // 语法错误 v = 2; }
(2)创设eval作用域
正常模式下,Javascript语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。
正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部。
"use strict"; var x = 2; console.info(eval("var x = 5; x")); // 5 console.info(x); // 2
💞1.5 增强的安全措施
(1)禁止this关键字指向全局对象
function f(){ return !this; } // 返回false,因为"this"指向全局对象,"!this"就是false function f(){ "use strict"; return !this; } // 返回true,因为严格模式下,this的值为undefined,所以"!this"为true。
因此,使用构造函数时,如果忘了加new,this不再指向全局对象,而是报错。
function f(){ return !this; } // 返回false,因为"this"指向全局对象,"!this"就是false function f(){ "use strict"; return !this; } // 返回true,因为严格模式下,this的值为undefined,所以"!this"为true。
(2)禁止在函数内部遍历调用栈
function f1(){ "use strict"; f1.caller; // 报错 f1.arguments; // 报错 } f1();
💞1.6 禁止删除变量
严格模式下无法删除变量。只有configurable设置为true的对象属性,才能被删除。
"use strict"; var x; delete x; // 语法错误 var o = Object.create(null, {'x': { value: 1, configurable: true }}); delete o.x; // 删除成功
💞1.7 显式报错
正常模式下,对一个对象的只读属性进行赋值,不会报错,只会默默地失败。严格模式下,将报错。
"use strict"; var o = {}; Object.defineProperty(o, "v", { value: 1, writable: false }); o.v = 2; // 报错
严格模式下,对一个使用getter方法读取的属性进行赋值,会报错。
"use strict"; var o = { get v() { return 1; } }; o.v = 2; // 报错
严格模式下,对禁止扩展的对象添加新属性,会报错。
"use strict"; var o = {}; Object.preventExtensions(o); o.v = 1; // 报错
严格模式下,删除一个不可删除的属性,会报错。
"use strict"; delete Object.prototype; // 报错
💞1.8 重名错误
严格模式新增了一些语法错误。
(1)对象不能有重名的属性
正常模式下,如果对象有多个重名属性,最后赋值的那个属性会覆盖前面的值。严格模式下,这属于语法错误。
"use strict"; var o = { p: 1, p: 2 }; // 语法错误
(2)函数不能有重名的参数
正常模式下,如果函数有多个重名的参数,可以用arguments[i]读取。严格模式下,这属于语法错误。
"use strict"; function f(a, a, b) { // 语法错误 return ; }
💞1.9 禁止八进制表示法
正常模式下,整数的第一位如果是0,表示这是八进制数,比如0100等于十进制的64。严格模式禁止这种表示法,整数第一位为0,将报错。
"use strict"; var n = 0100; // 语法错误
💞1.10 arguments对象的限制
arguments是函数的参数对象,严格模式对它的使用做了限制。
(1)不允许对arguments赋值
"use strict"; arguments++; // 语法错误 var obj = { set p(arguments) { } }; // 语法错误 try { } catch (arguments) { } // 语法错误 function arguments() { } // 语法错误 var f = new Function("arguments", "'use strict'; return 17;"); // 语法错误
(2)arguments不再追踪参数的变化
function f(a) { a = 2; return [a, arguments[0]]; } f(1); // 正常模式为[2,2] function f(a) { "use strict"; a = 2; return [a, arguments[0]]; } f(1); // 严格模式为[2,1]
(3)禁止使用arguments.callee
这意味着,你无法在匿名函数内部调用自身了。
"use strict"; var f = function() { return arguments.callee; }; f(); // 报错
💞1.11 函数必须声明在顶层
将来Javascript的新版本会引入"块级作用域"。为了与新版本接轨,严格模式只允许在全局作用域或函数作用域的顶层声明函数。也就是说,不允许在非函数的代码块内声明函数。
"use strict"; if (true) { function f() { } // 语法错误 } for (var i = 0; i < 5; i++) { function f2() { } // 语法错误 }
💞1.12 保留字
为了向将来Javascript的新版本过渡,严格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。
使用这些词作为变量名将会报错。
function package(protected) { // 语法错误 "use strict"; var implements; // 语法错误 }
此外,ECMAscript第五版本身还规定了另一些保留字(class, enum, export, extends, import, super),以及各大浏览器自行增加的const保留字,也是不能作为变量名的。
📧2 值在各种场景的转换规则
值 字符串操作环境 数字运算环境 逻辑运算环境 对象操作环境 undefined “undefined” NaN false Error null “null” 0 false Error 非空字符串 不转换 字符串对应的数字值 True 空字符串 不转换 0 false String 0 “0” 不转换 false Number NaN “NaN” 不转换 false Number Infinity “Infinity” 不转换 true Number Number.POSITIVE_INFINITY “Infinity” 不转换 true Number Number.NEGATIVE_INFINITY “-Infinity” 不转换 true Number Number.MAX_VALUE “1.7976931348623157e+308” 不转换 true Number Number.MIN_VALUE “5e-324” 不转换 true Number 其他所有数字 “数字的字符串值” 不转换 true Number true “true” 1 不转换 Boolean false “false” 0 不转换 Boolean 对象 toString() value()或toString()或NaN true 不转换 📧3 错误类型
ECMA-262规范指出了7种错误类型。当不同的错误条件发生时,这些类型在JavaScript引擎中都有用到,当然我们也可以手动创建它们。
- Error
所有错误的基本类型。实际上引擎从来不会抛出该类型的错误。
- EvalError
通过eval()函数执行代码发生错误时抛出。
- RangError
一个数字超出他的边界时抛出,例如:试图创建一个长度为-20的数组( new Array(-20) )。该错误在正常代码执行中非常罕见。
- ReferenceError
期望的对象不存在时抛出,例如:试图在一个null对象引用上调用一个函数。
- SyntaxError
给eval()函数传递的代码中有语法错误时抛出。
- TypeError
变量不是期望的类型时抛出,例如:new 10或者"prop" in true。
- URIError
给encodeURI()、encodeURICommonent()、decodeURI()或者decodeURIComponent()等函数传递个是非法的URI字符串时抛出。
📧4 空值合并运算符 ‘??’
空值合并运算符 ?? 提供了一种简短的语法,用来获取列表中第一个“已定义”的变量(译注:即值不是 null 或 undefined 的变量)。
a ?? b 的结果是:
- a,如果 a 不是 null 或 undefined,
- b,其他情况。
所以,x = a ?? b 是下面这个表达式的简写:
x = (a !== null && a !== undefined) ? a : b;
下面是一个更长一点的例子。
假设,我们有一个用户,变量 firstName、lastName 和 nickName 分别对应用户的名字、姓氏和昵称。如果用户决定不输入任何值,那么这些变量都可能是未定义的。
我们想要显示用户的名称:显示这三个变量中的一个,如果都没有设置值,则显示 “Anonymous”。
让我们使用 ?? 运算符选择第一个已定义的变量:
let firstName = null; let lastName = null; let nickName = "Supercoder"; // 显示第一个不是 null/undefined 的值 alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder
💞4.1 与 || 比较
或运算符 || 可以与 ?? 运算符以同样的方式使用。正如 上一章 所讲的,我们可以用 || 替换上面示例中的 ??,也可以获得相同的结果。
重要的区别是:
- || 返回第一个 真 值。
- ?? 返回第一个 已定义的 值。
当我们想将 null/undefined 与 0 区别对待时,这个区别至关重要。
例如,考虑下面这种情况:
height = height ?? 100;
如果 height 未定义,则将其赋值为 100。
让我们将其与 || 进行比较:
let height = 0; alert(height || 100); // 100 alert(height ?? 100); // 0
在这个例子中,height || 100 将值为 0 的 height 视为未设置的(unset),与 null、undefined 以及任何其他假(falsy)值同等对待。因此得到的结果是 100。
height ?? 100 仅当 height 确实是 null 或 undefined 时才返回 100。因此,alert 按原样显示了 height 值 0。
哪种行为更好取决于特定的使用场景。当高度 0 为有效值时,?? 运算符更适合。
💞4.2 优先级
优先级要在复杂表达式中使用 ?? 进行取值,需要考虑加括号:
因此,?? 在大多数其他运算之后,但在 = 和 ? 之前进行运算。
如果我们需要在复杂表达式中使用 ?? 进行取值,需要考虑加括号:
let height = null; let width = null; // 重要:使用括号 let area = (height ?? 100) * (width ?? 50); alert(area); // 5000
否则,如果我们省略了括号,* 的优先级比 ?? 高,会优先执行。
运算过程将等同于下面这个表达式:
// 可能不正确的 let area = height ?? (100 * width) ?? 50;
这里还有一个相关的语言级别的限制。
出于安全原因,禁止将 ?? 运算符与 && 和 || 运算符一起使用。
下面的代码会触发一个语法错误:
let x = 1 && 2 ?? 3; // Syntax error
这个限制无疑是值得商榷的,但是它被添加到语言规范中是为了避免编程错误,因为人们开始使用 ?? 替代 ||。
可以明确地使用括号来解决这个问题:
let x = (1 && 2) ?? 3; // 起作用 alert(x); // 2
💞4.3 注意:
-
空值合并运算符 ?? 提供了一种简洁的方式获取列表中“已定义”的值。
它被用于为变量分配默认值:
// 当 height 的值为 null 或 undefined 时,将 height 的值设置为 100 height = height ?? 100;
-
?? 运算符的优先级非常低,只略高于 ? 和 =。
-
如果没有明确添加括号,不能将其与 || 或 && 一起使用。
📧5 ===
在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:
- 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而true 转换为 1;
- 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
- 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类型值按照前面的规则进行比较;
这两个操作符在进行比较时则要遵循下列规则。
-
null 和 undefined 是相等的。
-
要比较相等性之前,不能将 null 和 undefined 转换成其他任何值。
-
如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。 重要提示:即使两个操作数都是 NaN,相等操作符也返回 false;因为按照规则, NaN 不等于 NaN。
-
如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,
则相等操作符返回 true;否则,返回 false。
表达式 值 null==undefined true “NaN”==NaN false 5==NaN false NaN==NaN false false==0 true true==1 true true==2 false undefined==0 false null==0 false null == undefined 会返回 true,因为它们是类似的值;但 null === undefined 会返回 false,因为它们是不同类型的值。
📧6 CONSOLE 控制台输入
Console对象提供浏览器控制台的接入,不同浏览器是不一样的,这里介绍普遍存在的
💞6.1 Console.assert()
判断第一个参数是否为真,false的话抛出异常并且在控制台输出相应信息
💞6.2 Console.clear()
清空控制台
💞6.3 Console.count()
非标准
以参数为标记记录调用的次数,调用时在控制台打印标识以及调用次数
可以带一个参数
💞6.4 Console.countReset()
重置指定标签的计数器,若没有参数,就重置defaul
这里是接着上面的
💞6.5 Console.debug()
控制台打印“debug”级别的日志消息 注:chrome58之后,只有打开了Verbose才看得到
💞6.6 Console.dir()
非标准
在控制台中显示指定JavaScript对象的属性,并通过类似文件树样式的交互列表显示。
💞6.7 Console.dirxml()
非标准
显示一个明确的XML/HTML元素的包括所有后代元素的交互树.如果无法作为一个element被显示,那么会以JavaScript对象的形式作为替代
💞6.8 打印信息
- console.log() 向控制台输出一条信息
- console.info() 向web控制台输出一个通知信息
- console.error() 向控制台输出一条错误信息
- console.warn() 向控制台输出一条警告信息
这4种用法都是一样的
- 打印多个对象 console.log({first:“Bob”},{last:“Tony”})
- 使用字符串替换(有点像c语言一样)
%o 或 %O 打印js对象 %d 或 %i 打印整数 %s 打印字符串 %f 打印浮点数 Chrome不支持精确格式化
-
%c 定义打印样式 这里的样式应该是按照,css来写的
💞6.9 打印树状结构
-
Console.group()
打印树状结构,配合groupCollapsed以及groupEnd方法;
-
Console.groupCollapsed()
同Console.group(),但是默认是折叠的
-
Console.groupEnd()
结束当前Tree
💞6.10 Console.table()
将数据以表格形式显示,数组,对象,类数组对象都可以打印; console.table(data[,columns]);
💞6.11 定时器
console.time(“name”),带参就是定时器的名字,开始计时,不带参就是默认的defaul console.timeEnd(“name”),结束“name”计时器
注:该方法在使用时不会将输出的时间返回到js,它只能用于控制台调试.请勿将该方法作为普通计时器或性能数据收集器的一部分.
💞6.12 Console.trace()
向控制台输出堆栈跟踪
💞6.13 占位符
占位符,是用某种特定规则的符号替代真正的内容来占位,看代码。
console.log('%d年%d月%d日',2020,03,30); // 2020年3月30日
这里的 %d(还有%i) 代表整数,它还支持字符串(%s)、浮点数(%f)和对象(%o)。
let person = { name:'idea', age:18 } console.log("%o可以用来创建人的类",person); // {name: "idea", age: 18}可以用来创建人的类
占位符跟函数中的参数作用差不多,方便了数据的引用和操作。
什么?你说的是那个样式吗?对,是那个样式~
语法是:console.log("%c内容",样式)
这里%c起到了关键作用,它的功能是根据提供的样式代码对输出内容进行格式化。
console.log("%c3D Text"," text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:5em");
控制台里就能看到如下炫酷的效果:
有点意思吧,不过这个效果是拿来做试验的,略显招摇,没有实际用途,如果你想自定义输出的字体,改个字号和颜色就好。
参考 : http://bclary.com/log/2004/11/07/#a-11.9.3
-
-
- 使用字符串替换(有点像c语言一样)
-
-
- URIError
- TypeError
- SyntaxError
- ReferenceError
- RangError
- EvalError
还没有评论,来说两句吧...