参考资料:

  • 《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. 利用github Pages和Jekyll搭建blog实践1

    你必须要懂一点git和网页开发.安装了git,并且有github账户. github设计了Pages功能,允许用户自定义项目首页 github提供模板,允许站内生成网页,但也允许用户自己编写网页,然后 ...

  2. 关于JQ checkbox选择的问题

    今天做了一个狠坑爹的事情. $("#dele_chk").bind('click',function(){ if($(this).attr('checked')){ $(" ...

  3. vue2+element组件库开发

    Vue2:https://cn.vuejs.org/v2/guide/single-file-components.html element组件库:http://element-cn.eleme.io ...

  4. Java图形界面实战案例——实现打字母游戏

    实现打字母的游戏 这次这个案例能够说是头几次所讲的内容的一个技术汇总,主要是 运用了几大块的知识.我们先来定义一下案例的背景:在一个300*400的窗口上.有10个随机产生的字母下落,在键盘上敲击字母 ...

  5. 洛谷 P3216 [HNOI2011]数学作业

    最近学了矩阵,kzj大佬推荐了我这一道题目. 乍一眼看上去,没看出是矩阵,就随便打了一个暴力,30分. 然后仔细分析了一波,发现蛮简单的. 结果全wa了,先看看下面的错误分析吧! 首先,设f[n]为最 ...

  6. Django开发模式会加载两次settings文件导致RotatingFileHandlerError

    当使用RotatingFileHandler作为django的日志处理器的时候,会报: Traceback (most recent call last): File "C:\Python2 ...

  7. 6.让ORM映射执行的时候打印SQL语句

    配置Django日志:\hello_django\hello_django\settings.py 文件中的 LOGGING 加入如下配置: LOGGING = { 'version': 1, 'di ...

  8. SUBMIT 用法

    [转自http://lz357502668.blog.163.com/blog/static/16496743201241195817597/] 1.最普通的用法 *Code used to exec ...

  9. pom.xml配置文件详解(转发)

    setting.xml主要用于配置maven的运行环境等一系列通用的属性,是全局级别的配置文件:而pom.xml主要描述了项目的maven坐标,依赖关系,开发者需要遵循的规则,缺陷管理系统,组织和li ...

  10. LeetCode:加一【66】

    LeetCode:加一[66] 题目描述 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外 ...