你不知道的JS(上)

1 作用域

  • referenceERROR, 会在strict模式下,LHS查询全局作用域不能找到抛出,非严格模式下则会创建; 还有在RHS查询一个未声明的变量时
  • RHS查询完成后,如果对其进行不合理操作,那么就会报typeError错误(比如非函数类型做函数调用,引用null或者undefine值中的属性)c:果然是有静态分析的

2 词法作用域

2.1 词法阶段

  • 查找,不知道vuex的store中的命名空间是怎样的实现?

2.2 欺骗词法

  • 这eval()不是方便XSS吗…..
  • with,非严格模式下,如果没有在自己特定作用域,所处函数作用域,全局作用域LHS都没找到,然后就自己创建了一个全局变量

3 函数作用域与块作用域

  1. 隐藏内部实现

  2. 函数作用域function和(function有着不同的作用, 后者作为函数表达式, 不需要显式地调用函数名。

  3. 匿名与具名

    1. 前者可以等同于具名函数表达式命名
  4. 立即执行函数表达式

    1. IIFE
    2. 两种写法(function(){}) (), (function(){}())

4 提升

  1. 变量和函数的声明会被提前, 而赋值和逻辑运算则会停在原地, 有时候会出现奇怪的错误; 函数提升优先级更高

5 闭包

定义: 函数, 在定义时的语法作用域以外的地方被调用; 访问定义时的词法作用域
闭包域作用域, 例子非常有意思; var, let
模块模式的两个必要条件:

  1. 必须有外部的封闭函数, 函数必须被调用一次(每次调用会产生新的实例
  2. 封闭函数必须返回至少一个内部函数,形成闭包并提供状态的作用接口

单例模式,IIFE即可完成;
命名公共API返回的对象
感觉和Java的类,实例,匿名类一个机制

1 关于this

  1. 不是调用自身而是调用

2 this全面解析

从调用位置来理解

绑定规则

  1. 默认绑定

    • 默认绑定,严格模式下会无法绑定到全局变量中
  2. 隐式绑定

    • 自适应绑定,类似同名变量在作用域中的覆盖;这里this绑定也会随着调用位置的被覆盖
    • 参数赋值是一种隐性赋值,传入对象.函数,仅仅是传入函数,相当于是默认绑定
  3. 显式绑定

    • call(其实现会通过强制转换为对象,this绑定到obj中)
    • apply
    • API调用上下文:通过添加一个参数来增加一个绑定对象(本质同call和apply)
  4. new绑定

    1. 不存在构造函数,只有对函数的“构造调用”
  5. 优先级

    1. bind()的实现,会先检测是否被new调用?替换掉旧的硬绑定:维持不可修改的特性;为什么?因为需要传递调用时添加的参数给下层函数。
  6. 例外

    1. apply(null,[2,3])为了传递参数,null会默认
    2. 柯里化
    3. 创建DMZ对象,创建空对象作为this的空间;Object.create(null)
    4. 间接引用,默认绑定
    5. 软绑定,给内置bind包装了成了自适应类似DMZ的方法
  7. this

    1. 箭头函数会从函数作用域寻找,this的绑定
    2. 作用域和箭头函数, 和传统的this机制

3 对象

  1. type

    1. object type
  2. 属性和方法

    1. 函数永远不会“属于”一个对象; 虽然有些会有this绑定,但这是另一回事
  3. 数组:数值下标/值对

  4. 对象复制,c:vue-admin-template中有deepClone是通过键值对的拷贝,const;

    1. 翻译有失误,浅拷贝,深复制
    2. 浅拷贝的assign:将enumerable自有键复制到目标对象,使用=赋值
  5. 属性描述符: 所有属性都具备了属性描述符

  6. 不变性:

    1. 对象常量
    2. 禁止扩展
    3. seal:调用2并,设置configable:false;
    4. freeze:调用3并设置writable:false;大概是最高级别的不可变,引用的对象可以遍历引用对象,全部freeze
  7. get 一个undefined确实够有趣的;put应用依然不太明白;(名称:_a_只是命名惯例)

  8. 存在性:in和hasproperty区;in是属性是否存在对象极其原型链(c:in的多义颇有*在c中的1/100风采)

  9. Symbol.iterator 与内置的@@iterator(一个迭代器函数对象的汉顺),for of 的本质和改写;

  10. 为什么永不结束就会挂起

混合对象“类”

类也只是一种基础设计模式
JS只是模拟类的
C:编程和建筑非常像….似乎的确如此

这里的多态解释:继承链中不同层次的一个方法名被多次定义,调用方法时会自动选择合适的定义

JS中类与构造函数,与真正的类有所不同

方法继承和重写(多态)取决于你在哪个类的实例中使用;重写不会影响到父类,子类只是一个副本;继承的本质是复制。

多重继承…..好吧我对面向对象实在很不熟悉。

**JS中只有对象,通过关联来连接 **。

多态

  1. 通过call来将this绑定当前context,实现显式的多态
  2. 先复制,再进行特殊化覆盖….c:真是朴素的方法. 函数的引用问题怎么解决呢?共享一个函数
  3. 寄生继承:完全没明白

复制对象引用,而不能复制对象本身

5 原型链

  1. Object.prototype原型链的最终节点
  2. 底层会覆盖上层的同名,选择最近,

只存在上层prototype的三种情况:

  1. 默认,直接添加到当前对象,屏蔽属性
  2. writable:false ,strict 会报错,非~会被忽略(禁用父类的属性“继承”,但是可以通过defineProperty
  3. 上层存在且有setter,那么会调用setter

隐式屏蔽,obj.a++ ==> obj.a = obj.a + 1 会调用[[put]]

“类”

  1. 调用new Foo()创建 的每个对象将最终被[[prototype]]链接到Foo.prototype对象;并非直接关联到对象,而是通过关联到其他对象的新对象
  2. 原型继承(c:容易造成语义上的误解)
  3. 继承no => 通过委托访问属性和函数
  4. new 的机制很有意思,即便new一个普通函数,也会出现构造函数的效果,或者说new 时,函数调用会变成构造函数调用
  5. 所以constructor只是属性名,空白对象没有(可以自己定义),最终会沿着prototype到Object中
  6. 这里直接通过Object.create(obj.prototype)新建对象来关联期待的对象……这个真的很奇怪
    1. 两种错误示范写法:Bar.prototype = Foo.prototype 直接引用了Foo,任何修改都会同步到Foo
    2. Bar.prototype = new Foo() new作为构造函数的触发关键词,会有造成构造函数的副作用
  7. ES6可以直接修改prototype – Object.setPrototypeOf( source.prototype, target.prototype)
  8. 检查实例的继承祖先(内省、反射); isPrototypeOf ES5: proto 的奇怪属性(应该是getter+setter

对象关联

  1. Object.create(null)对象无法进行委托,instance of 检测不到原型链

行为委托

原型链的本质就是对象之间的关联关系

OLOO

  1. 最好将状态保存到委托者,而不是委托目标
  2. 避免同名函数,不是面向对象重写
  3. 在本身找不到时会使用委托

的确在理解了JS的原型链机制后,再用它来写java风格,就很奇怪….

两张图就很清晰了

C: 其实这种语言特性在业务开发中,表面上不懂也没事,常用的框架将关注点集中到了解决问题上,只需要按照需求填入内容即可,做出的能用,但是一旦出现性能瓶颈,框架考虑范围外的事情(这里其实涉及到泛用性和专用,自由度等的取舍博弈),这时候就会有对底层原理(相对问题而言)理解有所要求。经验和原理同样重要,两者都需要花费时间成本,大量的练习,才能相互印证真正理解why。

C:DRY其实也包含工作内容,当融会贯通,然后继续重复就毫无意义(边际成本)

蓝图设计(设计文档)果真就能反应设计的好坏,最起码清晰,层次分明

  1. 类语法糖,让JS看起来真像那么回事儿;但还是有之前的问题,只是语法上更加友好了
  2. 委托轻松了很多,但是命名该怎么解决呢?每一次都换名吗?

构造和初始化分离

两种风格的比较:委托更像是灵活的组合

ES6更好的语法:

  1. class减少使用’,’,简洁声明方法减少function
  2. 可以轻便地关联对象–setPrototypeOf()
  3. 简洁方法的副作用,默认返回匿名函数
    1. 没太明白匿名函数递归是怎么回事?

instanceof 内省, 它的表面含义与实际语言机制的不同,尽管结果是符合表面含义

鸭子类型,JS真是欢乐之源; Promise

A

优点:

  1. 通过extend,扩展了对象类型
  2. class中只能声明方法,减少了犯错的可能
  3. 构造函数问题解决

缺点

  1. 本质上仍然是prototype的一种语法糖,是实时的委托而不是复制
  2. 共享和私有的实现
  3. 同名属性和方法的屏蔽
  4. super中的this的动态绑定
  5. toMethods方法绑定到原方法

class真是个大坑….而且真是别扭