参考资料:

  • 《javascript权威指南 第六版》
  • 《javascript高级程序设计 第二版》

写在前面的话

所谓的原型链就是一个一个的对象通过其__proto__属性连接起来的数据结构

(链)。这个数据结构对JS的继承很重要。

object a		object b		object c
|----------| |---------| |---------|
|__proto__----> |__proto__---->|__proto__----> ...
|----------| |---------| |---------|
  • js的世界里除了简单数据类型(Number,String,Boolean,Undefined,Null)就是复杂数据类型——对象,连作用域都是对象

    • 简单数据类型很简单,就是简单的数据段,直接赋值给变量,生存在中,因为它们的大小设置好后就不可以改变
    • 复杂数据类型很复杂,由多类型值组成,生存在中,栈中的变量只有对这个复杂数据类型的内存引用,设置好后可能会发生变化
    • 有些语言(java,c#)把字符串设置为对象,但是js放弃了。
  • 每个对象都有一个__proto__属性,它默认指向另一个对象(构造这个对象的构造器的prototype属性指向的对象)或者为null(null是一个空对象,什么也没有,Object.prototype.__proto__===null),现代浏览器都支持你访问到这个属性。
  • 当引擎读取一个对象的属性时,引擎先找自身的是否有个这个属性,没有的话按照自身的__proto__属性指向的对象查找,一直递归查询到Object.prototype指向的对象为止,因为Object.prototype.__proto__===null。
  • 每个Function对象(包括Function自己)都有一个prototype属性,它指向一个对象,这个对象有一个constructor属性默认指向这个引用对象函数对象。
  • js中的函数是一个对象,一个特殊的对象。

1 函数对象和对象

可以说函数对象是对象扩展,相比普通对象函数对象多了一个逻辑代码+prototype属性。prototype属性指向一个对象,这个对象有一个constructor属性指向函数对象。

2 new操作符

当我们使用new调用构造函数时会自动的创建一个对象,因此构造函数本身只要初始化这个新对象的状态。调用构造函数的一个特征就是把构造函数的prototype属性被用作新对象的原型,即新对象的__proto__属性会指向构造函数的prototype指向的对象。多个对象的__proto__都指向同一个prototype对象。

3 函数执行的本质

当我们调用一个函数时是这样的:查找函数对象中逻辑代码,执行之。

4 构造函数和函数

2个都是函数,只不过是调用的方式不同导致他们叫法不一样。当使用new操作符调用函数时函数叫构造器,使用(),apply,call时叫函数。

instanceof运算符的原理

A instanceof B

流程:先计算B.prototype,然后查询A.__proto__判断是否相同,不同则继续沿着A.__proto__.__proto__查找是否相同(也就是沿着原型链查找),直到原型链的头Object.prototype.__proto__。

5 Object,Function

Object是所有对象直接或者间接构造器,Function是所有函数的直接或者间接构造器,但是他们指向的对象都是函数对象。

5.1 谁是上帝

回想下instanceof的原理吧。

Function instanceof Function;
Function instanceof Object;
Object instanceof Function;
Object instanceof Object;

6 TEST

推测下alert出什么值?console出什么值?

Object.prototype.sth = "O";
Function.prototype.sth = "F";
function f() {
return function () {
console.log(this.sth);//F
return sth;
}
}
alert(f().apply(function(){}));//O

6.1 提示

  • 作用域在js里也是对象,查找变量也是在作用域对象中查找的。
  • typeof window === 'object'

6.2 解释变量的二维查找

alert的值:引擎先查找返回的匿名函数的作用域对象,发现没有sth变量,进而沿着作用域链的第二位查找f的作用域对象,发现也没有,接着查找globel(window)作用域对象,发现也没有。接着sth会在全局的global对象的属性来查找,沿着global对象的原型链查找,发现Object.prototype.sth = "O",所以...

console的值:这里的this是apply指定的执行环境:匿名函数。匿名函数的原型链上存在sth,所以输出F。

window.__proto__===Window.prototype;//true
Window.__proto__===Object.prototype;//true
window instanceof Window;//true
window instanceof Object;//true

7 原型链的优势

代码复用,构造出的对象节省内存空间。

8 深入delete操作符

delete可以删除对象的属性,它的操作数应该是一个属性访问表达式,它只能删除对象自身的属性,不能删除原型链上的属性。

注意

  • 如果对象没有这个属性,或者操作数不是属性表达式,返回true

      var a = {};
    delete a.b;//true
    a.b = 1;
    console.info(a.b);//1
    delete a.b;//true
    console.info(a.b);//undefined
    delete 1;//true
  • 但是如果删除的是全局属性,则可以省略对全局对象的引用,直接删除

      window.a = 1;
    delete a;//true
    console.info(typeof window.a);//undefined
  • 当delete删除一些不可以删除的属性返回false,全局环境声明的变量、函数是无法删除的。

      var a = 1;
    function f(){};
    console.info(window.a);//1
    delete a;//false
    delete f;//false
    delete window.a;//false
    delete window.f;//false
    console.info(window.a);//1
    console.info(window.f);//function f(){}
  • eval执行的代码中声明的变量,函数是可以删除的,控制台的代码是放在eval中执行的

      eval("var a=1;function f(){};");
    
      console.info(a);//1
    console.info(f);//function f(){} delete a;//true
    delete f;//true console.info(typeof a);//undefined
    console.info(typeof f);//undefined

8.1 test

delete document.getElementById//true
document.hasOwnProperty("getElementById");//false 表明getElementById不是document的属性。
document.__proto__==HTMLDocument.prototype;//HTMLDocument是document的构造函数
HTMLDocument.prototype.hasOwnProperty("getElementById");//getElementById也不是HTMLDocument.prototype属性。
HTMLDocument.prototype.__proto__===Document.prototype;//true
Document.prototype.hasOwnProperty("getElementById");//true
document.__proto__.__proto__===Document.prototype;//沿着原型链可以看到getElementById属性来自Document.prototype。
delete Document.prototype.getElementById;//无法删除这个属性。
Document.prototype.getElementById=null;//修改这个属性
document.getElementById("xx");//TypeError: Property 'getElementById' of object #<HTMLDocument> is not a function

Prototype Chain的更多相关文章

  1. 深入理解原型链(Prototype chain) __proto__

    原型链(Prototype chain) 原型对象也是普通的对象,并且也有可能有自己的原型,如果一个原型对象的原型不为null的话,我们就称之为原型链(prototype chain). A prot ...

  2. [Javascript] Link to Other Objects through the JavaScript Prototype Chain

    Objects have the ability to use data and methods that other objects contain, as long as it lives on ...

  3. (翻译) Inheritance and the prototype chain 继承和原型链

    JavaScript is a bit confusing for developers experienced in class-based languages (like Java or C++) ...

  4. Inheritance and the prototype chain 继承和 原型 链

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain Inherita ...

  5. prototype chain & prototype & __proto__

    prototype chain & prototype & proto prototype chain MDN https://developer.mozilla.org/en-US/ ...

  6. illustrating javascript prototype & prototype chain

    illustrating javascript prototype & prototype chain 图解 js 原型和原型链 proto & prototype func; // ...

  7. js & object & prototype & __proto__ & prototype chain

    js & object & prototype & proto & prototype chain constructor prototype === instance ...

  8. 全面了解 Javascript Prototype Chain 原型链

    原型链可以说是Javascript的核心特征之一,当然也是难点之一.学过其它面向对象的编程语言后再学习Javascript多少会感到有些迷惑.虽然Javascript也可以说是面向对象的语言,但是其实 ...

  9. Only Link: Inheritance and the prototype chain

    Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_cha ...

随机推荐

  1. java实体类如果不重写toString方法,会如何?

    先认识一下Object Object 类的 toString 方法 返回一个字符串,该字符串由类名(对象是该类的一个实例).at 标记符“@”和此对象哈希码的无符号十六进制表示组成.换句话说,该方法返 ...

  2. python write file

    fileHandle = open ( 'test.txt', 'a' ) fileHandle.write ( '\n\nBottom line.' ) fileHandle.close() 转自: ...

  3. html5小趣味知识点系列(二)tabindex

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. C#中Dictionary的作用及用法讲解

    Dictionary<string, string>是一个泛型 他本身有集合的功能有时候可以把它看成数组 他的结构是这样的:Dictionary<[key], [value]> ...

  5. drawRect setNeedsDisplay layoutSubViews

    drawRect   setNeedsDisplay layoutSubViews 1. drawRect: is invoked automaticall,never call it directl ...

  6. String、StringBuilder、 StringBuffer 深入分析 源代码解析

    java学习有一段时间了.但学习的东西都是框架等东西,java基础知识有点遗忘.所以重温一下java基础知识.写写文章里面有错的希望大家指正共同进步~~ 一.String 大家常常会说使用" ...

  7. SWD下载调试填坑,SWD连接丢失问题解决

    野火SWD下载器,设置好以后,第一次下载成功,莫名其妙丢失连接,发现在复位状态可以连接(惊奇) 网络上搜索到把Boot0和Boot1置高,就可以把程序下载到RAM里, 能下载以后就好办了,把程序里SW ...

  8. SharePoint解决方案及开发系列(1)-BPM

    自从2008年做SharePoint第一个项目至今,不知不觉已经快7个年头了:上次听涂曙光老师的讲座,有机会能跟他面对面地沟通(“我是看您的blog长大的”).刚换了新工作,暂时比较闲,乘着这段时间对 ...

  9. LLVM编译器

    LLVM 1. 说说 LLVM(Low Level Virtual Machine)到底是什么吧 先说编译器:编译器是把程序员的代码翻译成机器可以理解的语言的工具: 再谈 LLVM:一个模块化和可重用 ...

  10. 9.Django里的数据同步migrations命令

    一个关键的目录: 目录名:migrations 作用:用来存放通过makemigrations命令生成的数据库脚本,这里的内容一般不要手动去改 规定:app目录下必须要有migrations目录且目录 ...