原型

圣杯模式

image.png

  1. //圣杯模式
  2. function inherit(Target,Origin){
  3. function F(){}
  4. F.prototype = Origin.prototype;
  5. Target.prototype = new F()
  6. Target.prototype.constructor = Target
  7. Target.prototype.uber = Origin.prototype
  8. }
  9. Father.prototype.lastName = "deng"
  10. function Father(){
  11. }
  12. function Son(){
  13. }
  14. inherit(Son,Father)
  15. var son = new Son()
  16. var father = new Father()
  17. //雅虎
  18. var inherit = (function () {
  19. var F = function () {}
  20. return function (Target, Origin) {
  21. F.prototype = Origin.prototype;
  22. Target.prototype = new F();
  23. Target.prototype.constructor = Target;
  24. Target.prototype.uber = Origin.prototype
  25. }
  26. }())

继承模式 37 分钟

this 指向

总的来说 this 就是函数运行时所在的环境对象.
this理解 :

  • 关键字 不能指定定义变量
  • this本身是一个内置的变量,该变量用于指向一个对象
  • this有两种 全局this=>window 局部(函数)this=>调用其的对象 构造函数this =>当前构造函数的实例对象
  • 特殊this call apply 强制修改this

1.纯粹的函数调用 属于全局性调用 this就代表全局对象

  1. function fun(){
  2. console.log(this)
  3. }
  4. fun() //this => window
  5. // 相当于 window.fun()
  6. 例子:
  7. // window.a
  8. function a(){
  9. var user = "chu";
  10. console.log(this.user) //undefined
  11. console.log(this) //window
  12. }
  13. a() //等同于 window.a()

2.作为对象方法的调用 this 指向这个上级对象

  1. var obj = {
  2. user:"chu",
  3. fun:function(){
  4. console.log(this)
  5. console.log(this.user) //chu
  6. }
  7. }
  8. obj.fun() //this 指向obj
  9. 需要注意的是.this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁.

3.作为构造函数调用 即通过这个函数,可以生成一个新对象, this 指向这个新对象

  1. function Fn(){
  2. this.user = "chu"
  3. }
  4. var a = new Fn()
  5. console.log(a.user) //chu
  6. 例子
  7. var x = 2
  8. function test(){
  9. this.x = 1;
  10. }
  11. var obj = new test()
  12. obj.x //1
  13. x //2
  14. /*
  15. new 操作符 语法 new function()
  16. 1.创建空对象
  17. 2.执行函数
  18. 3.确认this的指向 this=>创建空对象
  19. 4.返回执行的结果
  20. */
  21. function Person(name,age){
  22. //1.创建空对象{}
  23. this.name = name;
  24. this.age = age;
  25. }
  26. var person1 = new Person("chu",18)

4.apply调用

apply()是函数的一个方法 作用是改变函数的调用对象 它的第一个参数就表示改变后的调用这个函数的对象
因此 这时this指的就是这个第一个参数

  1. var x = 0;
  2. function test(){
  3. console.log(this.x)
  4. }
  5. var obj = {}
  6. //obj = {
  7. // x:1,
  8. // m:test()
  9. // }
  10. obj.x =1;
  11. obj.m = test();
  12. obj.m.apply() //0
  13. obj.m.apply(obj) //1
  14. apply() 参数为空时,默认调用全局对象.
  1. 情况1:如果一个函数中有this,但是他没有被上一级的对象所调用,那么this的指向就是window
  2. 需要说明的是在js的严格版中this指向的不是window
  3. 情况2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象
  4. 情况3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是最外层的对象所调用,this指向
  5. 的也只是它上一级的对象
  6. 例子
  7. 1)
  8. var o = {
  9. a:10,
  10. b:{
  11. a:12,
  12. fn:function(){
  13. console.log(this.a) //12
  14. }
  15. }
  16. }
  17. o.b.fn()
  18. 2)
  19. var o = {
  20. a:10,
  21. b:{
  22. fn:function(){
  23. console.log(this.a) //undefined
  24. }
  25. }
  26. }
  27. o.b.fn()
  28. 特殊情况
  29. 注意:this 永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,下面的例子
  30. 函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行,所以最终指向的是window
  31. var o ={
  32. a:10,
  33. b:{
  34. a:12,
  35. fn:function(){
  36. console.log(this.a) //undefined
  37. console.log(this) //window
  38. }
  39. }
  40. }
  41. var j = o.b.fn
  42. j()

参考文档 : https://www.cnblogs.com/pssp/p/5216085.html#

https://segmentfault.com/a/1190000017510043

https://www.jianshu.com/p/d647aa6d1ae6

this 面试题

  1. this.x = 9;
  2. var module = {
  3. x:81,
  4. getX:function(){
  5. return this.x
  6. }
  7. }
  8. module.getX() //81
  9. var retrieveX = module.getX;
  10. retrieveX() //window
  11. var boundGetX = retrieveX.bind(module)
  12. boundGetX() //81

this 指向之箭头函数 apply call

箭头函数中

  1. var name = "windowsName";
  2. var a = {
  3. name : "chu",
  4. func1: function () {
  5. console.log(this.name)
  6. },
  7. func2: function () {
  8. setTimeout( function () {
  9. this.func1()
  10. },100);
  11. }
  12. };
  13. a.func2() // this.func1 is not a function
  14. 因为 最后调用 setTimeout 的对象是 window,但是在 window 中并没有 func1 函数。
  15. var name = "windowsName"
  16. var a = {
  17. name:"chu",
  18. func1:function(){
  19. console.log(this.name)
  20. },
  21. func2:function(){
  22. setTimeout(()=>{
  23. this.func1()
  24. },100)
  25. }
  26. }
  27. a.func2() //chu
  28. 箭头函数的 this 始终指向函数定义时的 this,而非执行时。

在函数内部使用 _this = this

  1. var name = "windowsName";
  2. var a = {
  3. name : "Cherry",
  4. func1: function () {
  5. console.log(this.name)
  6. },
  7. func2: function () {
  8. var _this = this;
  9. setTimeout( function() {
  10. _this.func1()
  11. },100);
  12. }
  13. };
  14. a.func2() // Cherry

https://juejin.im/post/59bfe84351882531b730bac2

执行上下文

变量声明提升
变量提升 (预解析 )
定义:
js引擎在js代码正式执行之前会做一些预处理工作
1.找var 和 function 关键字
2.找到var以后将var后面的变量提前声明但不是赋值, var a
3.找到function以后定义该函数

执行上下文的类型

  • 全局执行上下文
    • 这是默认或者说基础的上下文,任何不在函数内部的代码都在全局上下文中。它会执行两件事:创建一个全局的 window 对象(浏览器的情况下),并且设置 this 的值等于这个全局对象。一个程序中只会有一个全局执行上下文。
  • 函数执行上下文
    • 每当一个函数被调用时, 都会为该函数创建一个新的上下文。每个函数都有它自己的执行上下文,不过是在函数被调用时创建的。函数上下文可以有任意多个。每当一个新的执行上下文被创建,它会按定义的顺序(将在后文讨论)执行一系列步骤。
  • Eval函数执行上下文
    • 执行在 eval 函数内部的代码也会有它属于自己的执行上下文,但由于 JavaScript 开发者并不经常使用 eval,所以在这里我不会讨论它。

      执行栈

      执行上下文栈(Execution context stack ,ESC)
      执行栈是一种拥有 LIFO (后进先出)数据结构的栈,被用来存储代码运行时创建的所有执行上下文

怎么创建执行上下文

1)创建阶段 2)执行阶段

  • 创建阶段
    • this值的决定,即 this 绑定
    • 创建词法环境组件
    • 创建变量环境组件
  1. 概念上
  2. Environment 环境
  3. Lexical 词汇
  4. Variable 变量
  5. ExecutionContext = {
  6. ThisBinding = <this value>,
  7. LexicalEnvironment = { ... },
  8. VariableEnvironment = { ... },
  9. }

This 绑定
在全局执行上下文中,this的值指向全局对象(在浏览器中 this引用window对象)
在函数执行上下文中,this的值取决于该函数是如何被调用的,如果它是被一个引用对象调用,那么this会被设置成哪个对象,否则this的值被设置为全局对象或者undefined ( 在严格模式下 )

  1. let foo = {
  2. baz:function(){
  3. console.log(this) //foo 因为baz 被对象 foo调用
  4. }
  5. }
  6. foo.baz()
  7. let bar = foo.bar
  8. bar() //window 因为没有指定引用对象

词法环境 (未知 )
词法环境是一种规范类型,基于ECMAScript 代码的词法嵌套结构来定义标识符和具体变量和函数的关联,一个词法环境由环境记录器和一个可能的引用外部词法环境的空值组成
简单说就是 一种持有标识符 - 变量映射的结构.(这里的标识符指的是变量/函数的名字,而变量是对实际对象[包含函数类型对象]或原始数据的引用)。
(1) 环境记录器和 (2) 一个外部环境的引用

  1. 环境记录器是存储变量和函数声明的实际位置。
  2. 外部环境的引用意味着它可以访问其父级词法环境(作用域)。

总结

  • 全局环境中,环境记录器是对象环境记录器。
  • 函数环境中,环境记录器是声明式环境记录器。

变量环境 (未知 )
同样是一个词法环境,其环境记录器持有变量声明语句在执行上下文中创建的绑定关系
在 ES6 中,词法环境组件和变量环境的一个不同就是前者被用来存储函数声明和变量(letconst)绑定,而后者只用来存储 var 变量绑定。

文章 :https://juejin.im/post/5ba32171f265da0ab719a6d7#heading-11

执行上下文可以理解为函数执行的环境,每一个函数执行时,都会给对应的函数创建这样一个执行环境

  1. 全局上下文在浏览器窗口关闭后出栈
  2. 函数中, 遇到 return 能直接终止可执行代码的执行,因此会直接将当前上下文弹出栈
  1. function f1(){
  2. var n = 999;
  3. function f2(){
  4. alert(n)
  5. }
  6. return f2;
  7. }
  8. var result = f1()
  9. result() //999

image.png

  1. var result = f1() f1()开始执行了
  2. 但是在f1()中 f2()并没有被调用执行,所以f2不会创建新的上下文
  3. 而到result 执行时,才创建一个新的
  4. f1()执行完毕返回的 f2 result() 就是执行f2()

原型对象

作用域

原型相关

原型链
访问一个对象的属性时
现在自身属性中查找,找到返回
如果没有,在沿着proto这条链向上查找 找到返回
如果最终没有找到 返回 undefined
别名 隐式原型链
作用 查找对象的属性 (方法 )

image.png