• 你不知道的 Javascript


    作用域

    词法作用域:编译阶段确定(欺骗词法作用域 eval with)

    function foo(str){
      "use strict"
      eval(str)
      console.log(a)
    }
    foo('var a = 2')
    
    function foo(obj){
      with (obj){
        a = 2
      }
    }
    var o1 = {a:3}
    var o2 = {b:3}
    foo(o1)
    foo(o2)
    

    块作用域 with try/catch let const

    for (let i=0; i<10; i++){
      console.log(i)
    }
    
    if (true) {
      var a = 1
      let b = 2
      const c = 3
    }
    console.log(a) // 1
    console.log(b) // ReferenceError
    console.log(c) // ReferenceError
    
    try{throw 2}catch(a){
      console.log(a) // 2
    }
    console.log(a) // ReferenceError
    

    提升

    定义提升 函数优先

    foo() // TypeError
    bar() // ReferenceError
    var foo = function bar(){}
    
    foo() // 1
    function foo(){
      console.log(1)
    }
    foo = function(){
      console.log(2)
    }
    
    foo() // 3
    function foo(){
      console.log(1)
    }
    foo = function(){
      console.log(2)
    }
    function foo(){
      console.log(3)
    }
    
    foo() // 2
    if (true){
      function foo(){console.log(1)}
    }else{
      function foo(){console.log(2)}
    }
    

    闭包

    将内部函数传递到所在作用域以外,它都会持有对原始定义作用域的引用,无论何处执行这个函数都会使用闭包。

    function foo(){
      setTimeout(function a(){})
    }
    
    function foo(){
      return function a(){}
    }
    var b = foo()
    b()
    
    var b = (function(){
      function foo(){}
    }())
    b.foo()
    

    循环+闭包

    for (var i=0; i<5; i++){
      setTimeout(function(){
        console.log(i) // 5
      })
    }
    
    for (var i=0; i<5; i++){
      var j = i
      setTimeout(function(){
        console.log(j) // 4
      })
    }
    
    for (var i=0; i<5; i++){
      (function(){
        var j = i
        setTimeout(function(){
          console.log(j) // 0 1 2 3 4
        })
      })()
    }
    
    for (let i=0; i<5; i++){
      setTimeout(function(){
        console.log(i) // 0 1 2 3 4
      })
    }
    
    for (var i=0; i<5; i++){
      let j = i
      setTimeout(function(){
        console.log(j) // 4
      })
    }
    
    for (var i=0; i<5; i++){
      (function(j){
        setTimeout(function(){
          console.log(j) // 0 1 2 3 4
        })
      })(i)
    }
    

    模块机制闭包的作用

    var require = (function(name){
      var modules = {}
      function define(name, deps, impl) {
        for (var i=0; i<deps.length; i++){
          deps[i] = modules[deps[i]]
        }
        modules[name] = impl.apply(impl, deps)
      }
      function get(name) {
        return modules[name]
      }
      console.log(name)
      return {
        define: define,
        get: get
      }
    }())
    
    
    require.define('foo', [], function(){
      return {
        hello: function() {console.log('hello world')},
        name:'foo'
      }
    })
    
    require.define('bar', ['foo'], function(foo){
      return {
        hello: function() {console.log('bar:' + foo.name)},
        name: 'bar'
      }
    })
    
    require.define('user', ['foo', 'bar'], function(foo, bar){
      return {
        hello: function() {console.log('user:' + foo.name +', ' + bar.name)}
      }
    })
    
    var foo = require.get('foo')
    var bar = require.get('bar')
    var user = require.get('user')
    foo.hello()
    bar.hello()
    user.hello()
    

    This

    默认绑定 隐式绑定 显式绑定(硬绑定 call apply bind) new绑定

    默认绑定

    function foo(){
      console.log(this.count) // 1
      console.log(foo.count) // 2
    }
    var count = 1
    foo.count = 2
    foo()
    
    严格模式this不会绑定到window
    function foo(){
      "use strict"
      console.log(this.count) // TypeError: count undefined
    }
    var count = 1
    foo()
    

    隐式绑定

    function foo(){
      console.log(this.count) // 2
    }
    var obj = {
      count: 2,
      foo: foo
    }
    obj.foo()
    

    别名丢失隐式绑定

    function foo(){
      console.log(this.count) // 1
    }
    var count = 1
    var obj = {
      count: 2,
      foo: foo
    }
    var bar = obj.foo // 函数别名
    bar()
    

    回调丢失隐式绑定

    function foo(){
      console.log(this.count) // 1
    }
    var count = 1
    var obj = {
      count: 2,
      foo: foo
    }
    setTimeout(obj.foo)
    

    显式绑定

    function foo(){
      console.log(this.count) // 1
    }
    var obj = {
      count: 1
    }
    foo.call(obj)
    
    var bar = foo.bind(obj)
    bar()
    

    new绑定

    function foo(a){
      this.a = a
    }
    var bar = new foo(2)
    console.log(bar.a) // 2
    

    this丢失

    function foo(){
      setTimeout(function() {
        console.log(this.count) // undefined
      })
    }
    var obj = {
      count: 2
    }
    foo.call(obj)
    

    局部变量修复

    function foo(){
      var self = this
      setTimeout(function() {
        console.log(self.count) // 2
      })
    }
    var obj = {
      count: 2
    }
    foo.call(obj)
    

    bind修复

    function foo(){
      setTimeout(function() {
        console.log(this.count) // 2
      }.bind(this))
    }
    var obj = {
      count: 2
    }
    foo.call(obj)
    

    es6绑定

    function foo(){
      setTimeout(() => {
        console.log(this.count) // 2
      })
    }
    var obj = {
      count: 2
    }
    foo.call(obj)
    

    对象

    类型 string number boolean null undefined object

    对象 String Number Boolean Object Function Array Date RegExp Error

    var str = 'hello world'
    var strObj = new String('hello world')
    console.log(strObj.length) // 11
    console.log(str.length) // 11 (string -> new String)
    

    属性描述符ES5

    var obj = {
      a: 2
    }
    Object.getOwnPropertyDescriptor(obj, 'a') // {value: 2, writable: true, enumerable: true, configurable: true}
    

    可写

    var obj = {}
    Object.defineProperty(obj, 'a', {
      value: 2,
      writable: false
    })
    obj.a = 3
    console.log(obj.a) // 2 严格模式TypeError
    

    可枚举

    var obj = {b: 1}
    Object.defineProperty(obj, 'a', {
      value: 2,
      enumerable: false
    })
    for (var key in obj){
      console.log(key) // b
    }
    

    可配置(不可配置:不能删除,能修改)

    var obj = {}
    Object.defineProperty(obj, 'a', {
      value: 2,
      configurable: false
    })
    delete obj.a
    console.log(obj.a) // 2
    

    禁止拓展属性

    var obj = {}
    Object.preventExtensions(obj)
    obj.a = 3
    console.log(obj.a) // undefined
    

    密封(禁止拓展属性+不可配置)(preventExtensions+each(configurable: false))

    var obj = {}
    Object.seal(obj)
    

    冻结(密封+不可修改属性值)(seal+each(writable:false))

    var obj = {}
    Object.freeze(obj)
    

    [[get]]获取对象属性会执行[[get]]操作,自身没有的属性会在原型链上查找,都没有返回undefined

    var obj = {}
    console.log(obj.a) // undefined 
    console.log(a) // ReferenceError
    

    [[put]] 对象赋值触发[[put]],在赋值前会检查对象属性描述,例如不可写会失败

    var obj = {
      a: 1
    }
    Object.defineProperty(obj, 'a', {
      writable: false
    })
    obj.a = 2
    console.log(obj.a) // 1
    

    [[put]] 自身存在setter方法,会优先调用setter,如果原型链上有同名setter,会调用原型链的setter

    var obj = {
      a: 1,
      set a(val){
        console.log('nothing happend')
      }
    }
    obj.a = 2
    console.log(obj.a) // undefined set方法会覆盖同名属性
    

    getter

    var obj = {
      get a(){
        return 1
      }
    }
    console.log(obj.a) // 1
    

    setter 一般使用_property_表示屏蔽属性

    var obj = {
      set a(val){
        _a_ = val*2
      },
      get a(){
        return _a_ - 1
      }
    }
    obj.a = 2
    console.log(obj.a) // 3
    

    js没有类(继承是复制,js某些部分是引用)

    类是一种设计模式,可以被模拟:混入

    // 显式混入 ($.extend)
    function mixin(sourceObj, targetObj) {
      for (var key in sourceObj) {
        if (!(key in targetObj)) { // 重名不覆盖,实现多态
          targetObj[key] = sourceObj[key]
        }
      }
      return targetObj
    }
    
    var obj = {
      a: 1,
      b: function(){console.log(2)}
    }
    
    var child = mixin(obj, {
      c:3
    })
    
    console.log(child.b.prototype) // obj.b {}
    
    // 隐式混入
    var obj = {
      add: function() {
        this.count = this.count ? this.count+1 : 1
      }
    }
    
    var child = {
      add: function() {
        obj.add.call(this)
      }
    }
    
    obj.add()
    console.log(obj.count) // 1
    child.add()
    console.log(child.count) // 2 隐式混入赋值操作在child而不是obj
    
    // 寄生继承(既是显示又是隐式)
    function obj(){
      this.a = 1
    }
    function child(){
      var o= new obj()
      o.b = 2
      return o
    }
    var c = new child()
    console.log(c.b) //2
    

    原型

    prototype

    // 原型的设置和屏蔽
    var foo = {
      a: 1
    }
    var bar = Object.create(foo)
    console.log(bar.hasOwnProperty('a')) // false 原型设置
    bar.a++
    console.log(bar.hasOwnProperty('a')) // true 原型被屏蔽
    
    // 设置原型链
    // 直接设置原型
    function foo(){this.a = 1}
    foo.prototype.b = 2
    function bar(){}
    bar.prototype = foo.prototype // bar.prototype: foo {}
    var b = new bar()
    console.log(b.a) // undefined
    console.log(b.b) // 2
    
    // 无副作用设置原型链
    function foo(){this.a = 1}
    foo.prototype.b = 2
    function bar(){}
    bar.prototype = Object.create(foo.prototype) // bar.prototype: object {}
    var b = new bar()
    console.log(b.a) // undefined
    console.log(b.b) // 2
    
    // ES6可以不抛弃原型直接赋值
    Object.setPrototypeOf(var.prototype, foo.prototype)
    
    // 常见用法但有调用构造方法的副作用
    function foo(){this.a = 1}
    foo.prototype.b = 2
    function bar(){}
    bar.prototype = new foo()
    var b = new bar()
    console.log(b.a) // 1 副作用:执行了构造函数
    console.log(b.b) // 2
    
    // 判断类关系
    function foo(){}
    var f = new foo()
    console.log(f instanceof foo) // true
    console.log(foo.prototype.isPrototypeOf(f)) // true
    
    // 如何获取原型
    function foo(){}
    var a = new foo()
    
    console.log(Object.getPrototypeOf(a) === foo.prototype) // true
    
    // __proto__ 可以获取原型的原因
    Object.defineProperty(Object.prototype, '__proto__', {
      get: function(){
        return Object.getPrototypeOf(this)
      },
      set: function(o){
        Object.setPrototype(this, o)
        return o
      }
    })
    

    行为委托

    行为委托是除了类之外,更清晰的一种继承设计模式

    // 类创建实例
    function Foo(){
      this.something = function(){}
    }
    var bar = new Foo()
    bar.something()
    
    // 委托创建实例 ES5
    var foo = {
      something: function(){}
    }
    var bar = Object.create(foo) // foo 自身也是个实例
    bar.something()
    
    // Object.create模拟
    if (!Object.create){
      Object.create = function(obj){
        function F(){}
        F.prototype = obj
        return new F()
      }
    }
    
    // 类的继承
    function Foo(){}
    Foo.prototype.say = function(){console.log(1)}
    
    function Bar(){}
    Bar.prototype = Object.create(Foo.prototype) // 或 new Foo()
    
    var b = new Bar()
    b.say() // 1
    
    // 对象关联的继承
    var Foo = {
      say: function(){console.log(1)}
    }
    var Bar = Object.create(Foo)
    
    var b = Object.create(Bar) // 或 new Bar()
    b.say() // 1
    
  • 相关阅读:
    Codeforces 754A Lesha and array splitting (搜索)
    浅入分析Linux
    MakeFile基本使用
    Mac 安装YCM
    Homebrew 配置
    虚拟机复制操作CentOS6导致eth0转为eth0以至于网络服务启动失败的解决方案
    Kickstart安装
    Linux编译安装MySQL
    Python源码读后小结
    编译原理小结
  • 原文地址:https://www.cnblogs.com/ascoders/p/5951562.html
Copyright © 2020-2023  润新知