资讯专栏INFORMATION COLUMN

那些被遗忘的javascript细节

CoyPan / 1210人阅读

摘要:第一章变量内置类型空值未定义布尔值数字字符串对象符号新增正确的返回结果应该是但这个由来已久在中已经存在了将近年也许永远也不会修复因为这涉及太多现有的系统修复它会产生更多的是基本类型中唯一的假值函数是的一个内置函数实际上是的一个子类型函数是

Author: bugall
Wechat: bugallF
Email: 769088641@qq.com
Github: https://github.com/bugall

第一章-变量
1.内置类型
 空值(null)
 未定义(undefined)
 布尔值(boolean)
 数字(number)
 字符串(string)
 对象(object)
 符号(symbol,ES6新增)
2.null==="object"
typeof null === "object" //true

    正确的返回结果应该是"null",但这个bug由来已久,
在javascript中已经存在了将近20年,也许永远也不会修复
因为这涉及太多现有的web系统,修复它会产生更多的bug
3.null是基本类型中唯一的假值
var a = null;
(!a && typeof a === "object"); //true
4.function(函数)是javascript的一个内置函数
实际上function是object的一个“子类型”,
函数是"可调用对象",它有一个内部属性[[Call]],
该属性使其可以被调用
5.数组是对象,是object的一个子类型
typeof [1,2,3] === "object"; //true
6.javascript中的变量没有类型,只有值才有类型
变量可以随时持有任何类型的值
7.undefined与undeclared
变量在作用域中声明但是没有复制为"undefined",
变量在作用域中未声明"undeclared"
第二章-值
1.数组可以容纳任意类型的值
2.delete操作后不会影响数组的长度
使用delete运算符可以将单元从数组中删除,
但是单元删除后数组的length属性并不会发生变化
3.稀疏数组的length受最大值影响
var a = [];
a[0] = 1;
a[2] = 3;
a[1]; //undefined
a.length; //3
4.数组中数字和字符作为索引时,数组长度只统计数字部分
var a = [];
a[0] = 1;
a["bugall"] = 2;
a.length; //1
a["bugall"] = 2;
a.bugall = 2;
5.如果字符串键值能够被强制类型转换为十进制数字的话,
它会被当做数组索引处理
var a = [];
a["13"] = 42;
a.length; //14
6.javascript只有一种数值类型:number
javascript中的数字类型是基于IEEE 754标准实现的,
该标准通常也被称为“浮点数”,javascript使用的是
"双精度"格式64位二进制
7.42.toFixed(2) //SyntaxError
42..toFixed(2) = 42.00,42.toFixed(2)
是无效语法,因为.被视为常量42.的一部分
8.0.1+0.2 === 0.3 //false
二进制浮点数中0.1和0.2并不是十分精确,它们相加的结果并非刚好等于0.3,而是一个
非常接近的数字0.3000000000000000002
9. 如何判断两个小数是否相等
function numbersCloseEnoughToEqual(n1,n2){
    return Math.abs(n1-n2)
10. 整数的安全范围
数字的呈现方式决定了“整数”的安全值范围远远小于
Number.MAX_VALUE,最大是2^53-1
11. 整形检测
Number.isInterger(42) //true
Number.isInterger(42.000) //true
Number.isInterger(42.001) //false
12.不是值的值
undefined类型只有一个值,即undefined,
null类型也只有一个值,即null,它们的名称是类型也是值
13.不是数字的数字
如果数学运算的操作不是数字类型,就无法返回一
个有效的数字,这种情况下返回值为NaN
var a = 2 / "foo"  //NaN
typeof a === "number"  //true
NaN是执行数学运算没有成功返回的结果,
NaN是一个特殊值,它和自身不相等,是唯一一个非自反的值
NaN != NaN //true
14. isNaN理解为is not a number || is NaN
前者一直是我错误的理解,正确的理解应该是is NaN,
判断数学运算是否错误,返回错误的值
var a = 2 / "foo"
var b = "foo"
a; //NaN
b; //"foo"
isNaN(a) //true
isNaN(b) //true
这是不同的结果,一个是运算出错,一个是字符串
代码中尽可能得少出现isNaN()
15. 简单值都是通过值类型传递
null,undefined,string,number,boolean
16. 复合类型-对象都是通过引用传递
我们无法更改使用值传递还是引用传递,一切根据值的类型确定
第三章 对象
1. 匿名还是在堆栈追踪中不会显示出有意义的函数名,使的调试很困难
2. 函数声明,与函数表达式
    function a(){...} //函数声明
    var a = function(){...} //函数表达式
2. 立即执行函数表达式
(function foo(){
    var a=3;
    console.log(a) //3
})()
由于函数被包含在一对()括号内部,因此成为一个函数表达式,
通过在末尾加上另一个()可以立即执行这个函数。
第一个()将函数变成表达式
3. 变量声明应该距离使用的地方越近越好
4. 最小力度的作用域,最小的作用域气泡原则
5. 变量提升
console.log(a) //undefined
var a = 3;
console.log(a) //3
6. 使用var定义变量的时候,它写在哪里都是一样的,因为它们最终都会属于外部作用域
console.log(a) //undefined
if(false){
    var a = 3;
}
7. 使用let进行声明不会在块作用域中进行提升
{
    console.log(a) //ReferenceError
    var a = 3
    console.log(a) //3
}
8. 任何声明在某个作用域内的变量,都将附属与这个作用域
9. 函数声明会被提升,但是函数表达式不会被提升
foo() //bugall
function foo(){
    console.log("bugall")
}

a() // ReferenceError
var a = foo(){
    console.log("bugall")
}
10. 函数声明和变量声明都会被提升,但是函数会首先被提升,然后才是变量
11. 闭包可以组织GC回收(GC的回收机制采用引用计数)
function a(){
    var n = "bugall"
    function b(){
        console.log(n)
    }
    return b
}
foo() //"bugall"
以为b()覆盖了a()里的变量n,所以a的资源就无法释放,而这个引用就叫做闭包
12. 作用域是基于调用栈的,而不是代码中得作用域嵌套
13. 箭头函数用当前的词法作用域覆盖了this得本来结构
var obj = {
    name = "bugall",
    sayName = function(){
        console.log(this.name)
    })
}
var name = "not bugall"
obj.cool() //bugall ,this的作用域是obj对象
setTimeount(obj.cool,100) //not bugall,this变成了当前作用域

用this的形式
var obj = {
    name = "bugall",
    sayName = function(()=>{
        console.log(this.name)
    })
}
var name = "not bugall"
obj.cool() //bugall ,this的词法作用域是obj
setTimeount(obj.cool,100) //bugall, this的词法作用域没有变
14. 匿名函数无法指向自身
function foo(){
    foo.count = 4; //foo指向自身
}

setTimeout(function(){
    //匿名函数因为没有名字,无法指定在堆栈上得确定位置,所以不能引用自身
})
15. 函数的this默认绑定是全局
function foo(){
    console.log(this.a)
}
var a = 2
foo() //2
16. 使用严格模式下,不能使用全局对象用于默认绑定
function foo(){
    "use strict"
    console.log(this.a)
}
var a = 2
foo() //TypeError: this is undefined
17. 对象引用链中,只有最后一层在调用位置中起作用
function foo(){
    console.log(this.a)
}
var obj2 = {
    a:42,
    foo:foo
}
var obj1 = {
    a:2,
    obj2:obj2
}
obj1.obj2.foo() //42
18. call || apply实现this的显示绑定
function foo(){
    console.log(this.a)
}
var obj = {
    a:2
}
foo.call(obj) //2
我们在调用foo的时候强制把它的this绑定到obj上
19. bind 返回一个硬编码的新函数
function foo(something){
    console.log(this.a,somethis)
    return this.a + something
}
var obj = {
    a:2
}
var bar = foo.bind(obj)
var b = bar(3) // 2 3
console.log(b) //5
bind(...)会返回一个硬编码的新函数,
它会把你指定的参数设置为this的上下文并调用原始函数
20. javascript中的new
在javascript中,构造函数只是一些使用new操作符
时被调用的函数,他们并不会属于某个类,也不会实例化一个类,
实际上它们甚至都不能说是一个特殊的函数类型,他们只是
被new操作符调用的普通函数而已。
使用new来调用函数的时候,会自动执行下面的操作
1. 创建(或者说构造)一个全新的对象
2. 这个新对象会被执行[[prototype]]连接
3. 这个新对象会被绑定到函数调用的this
4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象
function foo(a){
    this.a=a
}
var bar = new foo(2)
console.log(bar.a) //2
21. 隐式绑定与显示绑定,显示绑定优先级最高
function foo(){
    console.log(this.a)
}
var obj1 = {
    a:2,
    foo:foo
}
var obj2 = {
    a:3,
    foo:foo
}
obj1.foo() //2
obj2.foo() //3
obj1.foo.call(obj2) //3
obj2.foo.call(obj1) //2
22. new绑定与隐式绑定,new绑定优先级高于隐式绑定
function foo(somethis){
    this.a = somethis
}
var obj1 = {
    foo:foo
}
var obj2 = {}
obj1.foo(2)
console.log(obj1.a)//2

obj1.foo.call(obj2,3)
console.log(obj2.a) //3

var bar = new obj1.foo(4)
console.log(obj1.a) //2
console.log(bar.a) //4
bar被绑定到obj1上,但是new bar(3)并没有像我们预期的那样把obj1.a修改为3
相反,new修改了硬绑定(到obj1的)调用bar(...)中的this,因为使用了new绑定得到
一个名字为baz的新对象,并且baz.a的值是3
23. call apply bind的区别
call,apply属于显示绑定
bind属于硬绑定,硬绑定属于显示绑定的一种

24. 硬绑定的缺点
硬绑定会降低函数的灵活性,使用硬绑定之后就
无法使用隐式绑定或是显式绑定来修改this
25. 如果判断this绑定
1. 函数是否在new中调用(new绑定),如果是的话this绑定的是新创建的对象
var bar = new foo()

2. 函数是否通过call,apply(显示绑定)或者硬绑定调用,
如果是的话,this绑定的是指定的对象
var bar = foo.call(obj2)

3. 函数是否在某个上下文对象中调用(隐式绑定),如果是的话,this绑定的是那个上下文对象
var var = obj1.foo()

4. 如果都不是的话,使用默认绑定,如果在严格模式下,就绑定到undefined,否则绑定到全局对象
var bar = foo()
25. 当null,undefined作为this的绑定对象传入call,apply,bind的时候,实际应用的是默认绑定

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

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

相关文章

  • 〔总结〕容易遗忘JS知识点整理

    摘要:命名函数的赋值表达式另外一个特殊的情况是将命名函数赋值给一个变量。这是由于的命名处理所致,函数名在函数内总是可见的。当需要向回调函数传递参数时,可以创建一个匿名函数,在函数内执行真实的回调函数。 1.hasOwnProperty相关 为了判断一个对象是否包含自定义属性而不是原型链上的属性,我们需要使用继承自 Object.prototype 的 hasOwnProperty方法。has...

    explorer_ddf 评论0 收藏0
  • “信息瓶颈”理论揭示深度学习本质,Hinton说他要看1万遍

    摘要:认为,深度神经网络根据一种被称为信息瓶颈的过程在学习,他和两位合作者最早在年对这一过程进行了纯理论方面的描述。另外一些研究人员则持怀疑态度,认为信息瓶颈理论不能完全解释深学习的成功。 利用深度神经网络的机器已经学会了交谈、开车,在玩视频游戏和下围棋时击败了世界冠军,还能做梦、画画,帮助进行科学发现,但同时它们也深深地让其发明者困惑,谁也没有料到所谓的深度学习算法能做得这么好。没有基本的原则指...

    wuyumin 评论0 收藏0
  • 难以置信!LSTM和GRU解析从未如此清晰

    摘要:作为解决方案的和和是解决短时记忆问题的解决方案,它们具有称为门的内部机制,可以调节信息流。随后,它可以沿着长链序列传递相关信息以进行预测,几乎所有基于递归神经网络的技术成果都是通过这两个网络实现的。和采用门结构来克服短时记忆的影响。 短时记忆RNN 会受到短时记忆的影响。如果一条序列足够长,那它们将很难将信息从较早的时间步传送到后面的时间步。 因此,如果你正在尝试处理一段文本进行预测,RNN...

    MrZONT 评论0 收藏0
  • 知其所以然之永不遗忘算法

    摘要:也就是说我们只是知其然,并没有知其所以然。相反,那些牛人就不会忘记自己设计的算法。刘未鹏在知其所以然三为什么算法这么难中探索了编码的思维历程,值得一看。之后,将当前入栈,更新栈内的递增序列。 原文地址 相信大部分同学曾经都学习过快速排序、Huffman、KMP、Dijkstra等经典算法,初次学习时我们惊叹于算法的巧妙,同时被设计者的智慧所折服。于是,我们仔细研读算法的每一步,甚至去证...

    B0B0 评论0 收藏0
  • 深度学习:远非人工智能全部和未来

    摘要:绝大多数人忽略了深度学习只占机器学习领域的,而机器学习又只占到了人工智能领域的。一个深度学习专家无法与人工智能专家划上等号。但是,深度学习并不是人类可以创造的人工智能科技的终点。深度学习的公正性并非来自其自身,而是人类筛选和准备的数据。 人工智能的这一波热潮毫无疑问是由深度学习引发的,自吴恩达等人 2011 年发表「识别猫」研究后,深度学习及其引发的技术已经在图像识别、游戏等任务中超越人类,...

    hedzr 评论0 收藏0

发表评论

0条评论

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