• 你不知道的 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
    
  • 相关阅读:
    Centos 7 zabbix 实战应用
    Centos7 Zabbix添加主机、图形、触发器
    Centos7 Zabbix监控部署
    Centos7 Ntp 时间服务器
    Linux 150命令之查看文件及内容处理命令 cat tac less head tail cut
    Kickstart 安装centos7
    Centos7与Centos6的区别
    Linux 150命令之 文件和目录操作命令 chattr lsattr find
    Linux 发展史与vm安装linux centos 6.9
    Linux介绍
  • 原文地址:https://www.cnblogs.com/ascoders/p/5951562.html
Copyright © 2020-2023  润新知