小知识手册

一、JS 原始类型

js的原始类型有6种:

  • boolean
  • null
  • undefined
  • number
  • string
  • symbol

原始类型是值,故而原始类型没有函数可以使用。

  • 问:那么为什么'1'.toString()可以正常使用呢?
    • 答:此时'1'已经变成了String类型(对象)
  • 问2:Number类型相加,存在0.1 + 0.2 !== 0.3
    • 答:解决方式:1) 将数字转成整数   2) 用第三方库 mathjs.org/
  • null是不是对象?
    • 答:null不是对象,虽然 typeof null 会输出 object,但是将null识别成对象是js的历史遗留问题。在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object

二、 类型转换

js中只存在三种类型转换:

  • 转换为布尔值
  • 转换为数字
  • 转换为字符串

2.1 转Boolean

在条件判断时,除了 undefined, null, false, NaN, '', 0, -0,其他所有值都转为true,包括所有对象。

2.2 对象转原始类型

对象在转换类型的时候,会调用内置的 [[ToPrimitive]] 函数,

算法逻辑为:

  • 如果已经是原始类型了,那就不需要转换了
  • 如果需要转字符串类型就调用 x.toString(),转换为基础类型的话就返回转换的值。不是字符串类型的话就先调用 valueOf,结果不是基础类型的话再调用 toString
  • 调用 x.valueOf(),如果转换为基础类型,就返回转换的值
  • 如果都没有返回原始类型,就会报错

2.3 四则运算符

加法运算符不同于其他几个运算符,它有以下几个特点:

  • 运算中其中一方为字符串,那么就会把另一方也转换为字符串
  • 如果一方不是字符串或者数字,那么会将它转换为数字或者字符串
1 + '1' // '11'
true + true // 2
4 + [1,2,3] // "41,2,3"
'a' + + 'b' // -> "aNaN"   +'b'等于NaN,故变成了字符串拼接

对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字

4 * '3' // 12
4 * [] // 0
4 * [1, 2] // NaN

比较运算符

  • 如果是对象,就通过 toPrimitive 转换对象
  • 如果是字符串,就通过 unicode 字符索引来比较

 

三、this指针

2.1 基本判断

function foo() {
  console.log(this.a)
}
var a = 1
foo()

const obj = {
  a: 2,
  foo: foo
}
obj.foo()

const c = new foo()
  • 对于直接调用 foo 来说,不管 foo 函数被放在了什么地方,this 一定是 window
  • 对于 obj.foo() 来说,我们只需要记住,谁调用了函数,谁就是 this,所以在这个场景下 foo函数中的 this 就是 obj 对象
  • 对于 new 的方式来说,this 被永远绑定在了 c 上面,不会被任何方式改变 this

2.2 箭头函数

箭头函数中的 this 只取决包裹箭头函数的第一个普通函数的this

function a() {
  return () => {
    return () => {
      console.log(this)
    }
  }
}
console.log(a()()())

// 此时箭头函数的this指向了window

2.3 使用bind()改变上下文关系

  • bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
  • 不管我们给函数 bind 几次,this 永远由第一次 bind 决定
// 多个bind,this指向第一次绑定
let a = {}
let fn = function () { console.log(this) }
fn.bind().bind(a)() // => Window


let a = { name: 'yck' }
function foo() {
  console.log(this.name) // => 'yck'
  console.log(this) // => a
}
foo.bind(a)()

2.4 优先级

多个规则同时出现的情况,这时候不同的规则之间会根据优先级最高的来决定 this 最终指向哪里。

箭头函数的 this 一旦被绑定,就不会再被任何方式所改变。

  • new 的方式优先级最高
  • 接下来是 bind 这些函数
  • 然后是 obj.foo() 这种调用方式,
  • 最后是foo 这种调用方式

 

四、== 和 === 的区别

对于 == 来说,若对比双方的类型不一致,会进行类型转换。而 === 则是判断类型和值是否相同

 

五、变量提升

提升存在的根本原因就是为了解决函数间互相调用的情况。将变量和函数都提升到文件顶部

5.1 什么是变量提升

例子中发现,虽然变量还没有被声明,但是我们却可以使用这个未被声明的变量

原因是变量被提升到了头部,这就叫做变量提升

console.log(a) // undefined
var a = 1

// 实际:
var a;
console.log(a); // undefined
a = 1;

5.2 暂时性死区

而使用 let 或者 const, 则会报错

console.log(a) // js会报错,意识使用了未定义的变量a
let a = 1

ES6规定,let/const 命令会使区块形成封闭的作用域。若在声明之前使用变量,就会报错。这也叫做暂时性死区

5.3 函数提升

提升存在的根本原因就是为了解决函数间互相调用的情况,若没有函数提升,则无法实现函数互相调用。

function test1() {
    test2()
}
function test2() {
    test1()
}
test1()

5.4 总结

  • 函数提升优先于变量提升,函数提升会把整个函数挪到作用域顶部,变量提升只会把声明挪到作用域顶部
  • var 存在提升,我们能在声明之前使用。letconst 因为暂时性死区的原因,不能在声明前使用
  • var 在全局作用域下声明变量会导致变量挂载在 window 上,其他两者不会,但 let 和 const 依然会存在全局作用域中,可以被当作全局对象使用
  • let 和 const 作用基本一致,但是后者声明的变量不能再次赋值

 

六、模块化

6.1 好处

  • 解决命名冲突
  • 提供复用性
  • 提高代码可维护性

6.2 使用立即执行函数

(function(param){
   globalVariable.test = function() {}
   // ... 声明各种变量、函数都不会污染全局作用域
})(globalVariable)

使用立即执行函数,可以做到:

  • 不必为函数重命名,避免污染全局变量
  • 形成独立的作用域,可以封装一些外部无法读取的私有变量

著名面试题:

<body>
    <ul id="list">
        <li>公司简介</li>
        <li>联系我们</li>
        <li>营销网络</li>
    </ul>
    <script>
       var list = document.getElementById("list");
      var li = list.children;
      for(var i = 0 ;i<li.length;i++){
       ( function(param){
            li[param].onclick = function(){
              alert(param);
          })(i); 把实参i赋值给形参param
        }
      }
     </script>  
</body>

6.3 CommonJS

CommonJS是nodejs也就是服务器端广泛使用的模块化机制。
该规范的主要内容是,模块必须通过module.exports 导出对外的变量或接口,通过 require() 来导入其他模块的输出到当前模块作用域中。

特点:

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序

一般CommonJS用于nodejs的服务器端,前端要使用的话需要额外引入require.js

 

6.4 ES Module

ES6正式提出了内置的模块化语法,我们在浏览器端无需额外引入requirejs来进行模块化。

ES6中的模块有以下特点:

  • 模块自动运行在严格模式下
  • 在模块的顶级作用域创建的变量,不会被自动添加到共享的全局作用域,它们只会在模块顶级作用域的内部存在;
  • 模块顶级作用域的 this 值为 undefined
  • 对于需要让模块外部代码访问的内容,模块必须导出它们

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值