《你不知道的JS上》笔记

JS是编译型语言

编译发生在代码执行前几微秒,简单来讲就是js在执行前要进行编译,编译过程发生在代码执行前几微妙,甚至更短。闭包

编译的步骤

  1. 词法分析
    以var a = 2 为例,词法分析会将其分红三个有意义的代码块即词法单元。
  2. 语法分析
    将词法单元组合生成表明了程序语法的结构的树,即抽象语法书(AST)。
  3. 代码生成
    将AST生成可执行的代码。即将AST转化成一组机器指令。​​​

LHS RHS

若是查找的目的是对变量进行赋值,那么就会使用 LHS 查询;若是目的是获取变量的值,就会使用 RHS 查询。app

词法做用域

决定于你在写代码时的块级做用域ide

优化

依赖于词法的静态分析函数

eval with 会建立新的做用域

在词法分析阶段,没法知道eval with会对做用域作怎样的修改,此时引擎再也不对做用域进行任何优化优化

函数做用域

函数声明 函数表达式

区分函数声明和表达式最简单的方法是看 function 关键字出如今声明中的位
置(不只仅是一行代码,而是整个声明中的位置)。若是 function 是声明中
的第一个词,那么就是一个函数声明,不然就是一个函数表达式。this

let

  1. 隐式的生成块级做用域
  2. 不存在变量提高

提高

缘由

变量(包括函数在内)的全部声明都会优先执行,只有声明自己会提高,而赋值或其余运行逻辑会留在原位置prototype

过程

这意味着不管做用域中的声明出如今什么地方,都将在代码自己被执行前首先进行处理。
能够将这个过程形象地想象成全部的声明(变量和函数)都会被“移动”到各自做用域的
最顶端,这个过程被称为提高。
声明自己会被提高,而包括函数表达式的赋值在内的赋值操做并不会提高。code

闭包

定义

当函数可以记住或访问所在的词法做用域,及时是被做用域外调用,就产生了闭包对象

模块

  1. 现代模块机制
  2. 将来的模块机制

关于this

绑定时间点

是在函数运行时绑定的,而非定义时。它的上下文取决于函数调用时的各类条件,和在哪里定义的没有关系,只取决于函数的调用方式。继承

绑定过程

当函数被调用时,会建立一个执行上下文,在这个上下文里包含了函数在哪里没调用(调用栈),调用函数的方法,参数等。this做为执行上下文的一个属性,能够在函数执行的过程当中用到。

绑定类型

  1. 默认绑定
    即绑定到全局,严格模式下回绑定到undefined。

    function foo() {
      console.log( this.a );
    }
    var a = 2;
    (function(){
      "use strict";
       foo(); // 2
    })()
  2. 隐式绑定
    即绑定到最顶层(或最近调用对象)上

    function fun() {
      console.log(this.a)
    }
    var obj2 = {
      a: 3,
     fun: fun,
    }
    var obj1 = {
      a: 2,
      obj2: obj2,
    }
    obj1.obj2.fun() // 3
  3. 显式绑定
    即用call或apply手动进行绑定
  4. bind方法实现
  5. new绑定(构造函数)

    1. 不存在
      其实在js中不存在构造函数,咱们所说的构造函数其实就是普通的函数,它只是用new被“构造调用”而已。
    2. new发生了什么?

      1. 建立(或者说构造)一个全新的对象。
      2. 这个新对象会被执行[[原型]]链接。
      3. 这个新对象会绑定到函数调用的this。
      4. 若是函数没有返回其余对象,那么new表达式中的函数调用会自动返回这个新对象。
  6. 箭头函数 =>

对象

内置对象

基本类型在须要的时候(好比说获取长度),会被引擎默认转成内置对象,从而进行方法的调用。
基础类型并非继承自内置对象​

var strPrimitive = "I am a string";
    typeof strPrimitive; // "string"
    strPrimitive instanceof String; // false
    var strObject = new String( "I am a string" );
    typeof strObject; // "object"
    strObject instanceof String; // true
    Object.prototype.toString.call( strObject ); // [object String]

null

typeof null === Object;

原理是这样的,不一样的对象在底层都表示为二进制,在 JavaScript 中二进制前三位都为 0 的话会被判
断为 object 类型,null 的二进制表示是全 0,天然前三位也是 0,因此执行 typeof 时会返回“object”

拷贝

  1. 浅拷贝
    Object.assign({}, obj)
  2. 深拷贝
    JSON.stringify

属性描述符

getOwnPropertyDescriptor(myObj, 'a')
defineProperty
Object.defineProperty(myObj, 'a', {
  value: 2,            
  ​writable: true,
  configurable: true, 
  enumerable: true 
​})

Getter 、Setter

var obj = {
  get a() {
    return this._a_
  },
  set a(val) {
   this._a_ = val * 5
  }
}
obj.a = 10
console.log(obj.a) // 50
​
var obj2 = {}
Object.defineProperty(obj2, 'a', {
  get: function() {
    return this._a_
  },
  set: function(val) {
    this._a_ = val * 2
  }
})
obj2.a = 15
console.log(obj2.a) // 30

存在性

  1. in
    'a' in obj1 会检查obj及其原型链上是否有'a'
  2. hasOwnProperty
    不会检查原型链,若是须要能够Object.prototype.hasOwnProperty.call(myObj, 'a')

原型(prototype)

constructor

返回实例对象O的构造函数(的引用)。任何一个prototype对象都有一个constructor属性,指向它的构造函数,每个实例也有一个constructor属性,默认调用prototype对象的constructor属性​
例如

function Test() {
  this.name = 'test'
}
var test = new Test()
console.log(test.constructor === Test) // true

类constructor

构造函数 constructor 是用于建立和初始化类中建立的一个对象的一种特殊方法.

class Polygon {
    constructor() {
        this.name = "Polygon";
    }
}
class Square extends Polygon {
    constructor() {
        super();
    }
}
class Rectangle {}
Object.setPrototypeOf(Square.prototype, Rectangle.prototype);
console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false
console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true
let newInstance = new Square();
console.log(newInstance.name); //Polygon​

proto

实例对象__proto__指向生成改对象的构造函数的原型
例如

|function Test() {
  this.name = 'test'
}
Test.prototype = {
  color: 'red'
}
var test = new Test()
console.log(test.__proto__ === Test.prototype) // true
console.log(test.__proto__)

Object.create

var foo = {
something: function() {
  console.log( "Tell me something good..." );
}
};
var bar = Object.create( foo ); 
bar.something(); // Tell me something good...
Object.create(..) 会建立一个新对象(bar)并把它关联到咱们指定的对象(foo)

这样 咱们就能够充分发挥 [[Prototype]]
机制的威力(委托)而且避免没必要要的麻烦
(好比使 用 new 的构造函数调用会生成 .prototype 和 .constructor 引用)。

继承

原型继承

缺点
实例的属性都会指向同一个引用
实现

function Parent() {
  this.names = [1, 2, 3]
}
function Child() {
  
}
Child.prototype = new Parent()
var child1 = new Child()
var child2 = new Child()
child1.names.push(4)
console.log(child1.names) // [1,2, 3,4]
console.log(child2.names) // [1,2, 3,4]

借用构造函数

实现

function Parent() {
  this.names = [1, 2, 3]
  this.getName = function () {
    console.log(this.name)
  }
}
function Child() {
  Parent.call(this)
}
var child1 = new Child()
var child2 = new Child()
child1.names.push(4)
console.log(child1.names)
console.log(child2.names)

缺点
每一个子实例都会实例化方法一次,内存爆炸

组合继承(最经常使用)

实现

function Parent() {
  this.names = [1, 2, 3]
}
Parent.prototype.getName = function () {
  console.log(this.names)
}
function Child() {
  Parent.call(this)
}
Child.prototype = new Parent()
var child1 = new Child()
var child2 = new Child()
child1.names.push(4)
child1.getName()
child2.getName()

缺点

  1. 子类实例上有一份父类的属性,两者重复形成内存浪费
  2. 父类的构造函数被调用了两次​

寄生式组合继承

实现

function Parent() {
  this.names = [1, 2, 3]
}
Parent.prototype.getName = function () {
  console.log(this.names)
}
function Child() {
  Parent.call(this)
}
Child.prototype = Object.create(Parent.prototype)
var child1 = new Child()
var child2 = new Child()
child1.names.push(4)
child1.getName()
child2.getName()

优势
属性不会再原型链上重复

行为委托

js中的继承其实就是在对象间创建关联关系,而行为委托就是创建这种关联关系的纽带。

("原型")面向对象风格

function Foo(who) {
  this.me = who;
}
Foo.prototype.identify = function () {
  return "I am" + this.me;
};
function Bar(who) {
  Foo.call(this,who);
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.speak = function () {
  alert("Hello," + this.identify() + '.');
};
var b1 = new Bar("b1");
var b2 = new Bar("b2");
b1.speak();
b2.speak();

对象关联风格

Foo = {
  init:function (who) {
    this.me = who;
  },
  identify:function () {
    return "I am" + this.name
  }
};
Bar = Object.create(Foo);
Bar.speak = function () {
  alert("hello," + this.identify() + '.');
};
var b3 = Object.create(Bar);
b3.init("b3");
var b4 = Object.create(Bar);
b4.init("b4");
b1.speak();
b2.speak();

相关文章
相关标签/搜索