javascript几个知识点

2023-11-20

本文总结一下javascript几个比较重要的知识点,包括scope chain,this,和函数的一些高级特性

scope chain

scope chain是javascript函数调用里最核心的概念,尤其是要理解闭包的概念的话,必须先了解scope chain的原理

函数在scope chain上查找变量

function执行时,会在scope chain自底向上地查找变量。scope chain的第一个对象是自己的调用对象(activation object),然后是外层的function的调用对象,然后是更外层的调用对象,直到global object

如这段代码:

function wrapper(){

    var name = "kyfxbl";

    function inner(){
        console.log(name);
    }

    inner();
}

inner执行时,自己的调用对象上没有变量name,于是在wrapper的调用对象上查找。如果wrapper的调用对象上也没有,就去全局变量里找

scope chain在函数定义时确定

javascript的作用域规则是词法作用域,也就是说,函数的scope chain是在定义时决定的,而不是调用时才决定

比如这段代码:

function wrapper(){

    var scope = "local";

    return function(){
        console.log(scope);
    }

}

var f = wrapper();

var scope = "global";

f();

返回的那个匿名函数,其作用域在wrapper()执行时就确定了:self call object -> wrapper call object -> global object。而不是当执行f()的时候才决定

scope chain上的调用对象可修改

虽然一个函数在定义的时候,scope chain就已经确定了,但是只是确定了scope chain上包含哪些对象。这些对象的属性可以改变,比如这段代码:

function wrapper(){

    var name = "original";

    function setName(new_name){
        name = new_name;
    }

    function getName(){
        console.log(name);
    }

    return [setName, getName];
}

var funcs = wrapper();

funcs[1]();// original
funcs[0]("new_name");
funcs[1]();// new_name

wrapper()被调用时,定义了2个函数。这2个函数的scope chain上,共享着wrapper的call object。所以调用setName()改变name的值,会对getName()也产生影响。scope chain是确定的,但是其中对象的属性却是可以修改的

闭包(closure)如何形成

简单而言,当嵌套函数做为返回值,被外部的变量引用,或者作为外部对象的属性时,闭包就形成了。形成闭包之后,scope chain上的调用对象,都能继续使用,而不会立刻被垃圾回收。犀牛书上有更详细的描述:

a function is executed in the scope in which it was defined. When a function is invoked, a call object is created for it and placed on the scope chain. When the function exits, the call object is removed from the scope chain. When no nested functions are involved, the scope chain is the only reference to the call object. When the object is removed from the chain, there are no more references to it, and it ends up being garbage collected. But nested functions change the picture. If a nested function is created, the definition of that function refers to the call objects because that call object is the top of the scope chain in which the function was defined. If the nested function is used only within the outer function, however, the only reference to the nested function is in the call object. When the outer function returns, the nested function refers to the call object, and the call object refers to nested function, but there are no other references to either one, and so both objects become available for garbage collection. Things are different if you save a reference to the nested function in the global scope. You do so by using the nested function as the return value of the outer function or by storing the nested function as the property of some other object. In this case, there is an external reference to the nested function, and the nested function retains its reference to the call object of the outer function. The upshot is that the call object for that one particular invocation of the outer function continues to live, and the names and values of the function arguments and local variables persist in this object. JavaScript code cannot directly access the call object in any way, but the properties it defines are part of the scope chain for any invocation of the nested function.

所有变量都是某个对象的属性

  1. 在function内部,通过var声明的变量,是临时变量,本质上是调用对象的属性
  2. 在function内部,用function声明的函数,也是临时变量
  3. 在function内部,不通过var声明的变量,是全局变量,本质上是全局对象的属性。如果使用strict模式,这种写法是被禁止的,解释器会直接报错
  4. 不在任何function内部,声明的变量,是全局变量

以下示例代码可以说明:

(function(){

    var a = function(){
        console.log("a");
    };

    b = function(){
        console.log("b");
    };

    function c(){
        console.log("c");
    }

})();

a();// error
b();// ok
c();// error

node和浏览器环境,在表现上稍有区别。浏览器环境下,在function外部声明的变量,是全局对象window的属性;而在node环境,不会直接成为global的属性,因为其实node每个文件都是被一个匿名的function包裹着

this指向哪个对象

javascript和java里的this,完全不同。java中的this含义非常明确,即当前实例。而javascript中的this要复杂得多。比如以下代码:

function doSomething(){
    console.log(this.name);
}

如果只看这段代码,无法确定在运行时this指向哪个对象。要确定javascript中的this指向哪个对象,必须依赖上下文。总共有5种情况:

作为某对象的方法被调用

var obj = {
    name: "kyfxbl"
};

obj.sayHi = function(){
    console.log(this.name);
};

obj.sayHi();

当function做为某对象的方法被调用时,this指向该对象

直接调用

global.name = "kyfxbl";

function sayHi(){
    console.log(this.name);
}

sayHi();
global.name = "kyfxbl";

function wrapper(){

    (function(){
        console.log(this.name);
    })();
}

wrapper();

直接调用时,this指向全局对象,浏览器环境下是window,node环境是global

作为构造函数被调用

function Person(name){
    this.name = name;
}

var person = new Person("kyfxbl");

console.log(person.name);

当function被作为构造函数调用时,this指向新创建的那个对象。在OO编程里,这是一种常见的形式

通过call和apply调用

function sayHi(){
    console.log(this.name);
}

var obj = {
    name: "kyfxbl"
};

sayHi.call(obj);

这种情况下,this就是call的第一个参数

在顶层代码中的行为

在顶层环境,即不在任何function内部的this,在浏览器环境和node环境不同

在node环境,以下代码的输出结果可能有点出人意料:

console.log(this === exports);// true
console.log(this === global);// false

(function(){
    console.log(this === exports);// false
    console.log(this === global);// true
})();

在顶层环境,this指向module.exports,而非global

而在浏览器环境,顶层的this指向window

alert(this === window);// true

这是浏览器环境和node环境的差异

function的高级属性

function有些高级属性,平时可能用得比较少,但是在写框架和库的时候,有时必须要用到

apply和call函数

通过apply和call,可以实现函数动态调用

这2个函数很接近,唯一的区别是,apply是传参数数组,而call是传变参

arguments和this

函数被调用时,会自动创建arguments对象,它的行为类似数组,但又不是数组。通过arguments可以动态判断参数的情况

另一个关键字是this,前面介绍过了。

因为每一个function内部都有这2个关键字,所以如果存在函数嵌套的情况,内部函数的this和arguments就会覆盖外层函数的this和arguments。因此如果需要在内层函数里访问外层函数的这2个属性,通常的做法是:

function wrapper(age){

    var that = this;

    var thatArguments = arguments;

    function inner(){
        console.log(that.name);
        console.log(thatArguments);
    }

    inner();
}

var obj = {
    name: "kyfxbl"
};

wrapper.call(obj, 23);// kyfxbl, {'0': 23}

length属性

length表示该function形参的个数:

function sayHi(name, words){
    // logic
}

console.log(sayHi.length);// 2

caller

caller指向当前调用此函数的外层函数,如果本身就是最外层的函数,则返回null

function wrapper(){

    function inner(){
        console.log(inner.caller.toString());
    }

    inner();
}

wrapper();

另外,如果在node环境下,最外层的function,其caller并不是null,而是某一个函数。这也说明了node里的每一个文件,其实都被一个function包裹着:

function test(){
    console.log(test.caller.toString());
}

test();

输出是:

function (exports, require, module, __filename, __dirname) { 

    function test(){
        console.log(test.caller.toString());
    }

    test();
}

callee

callee是arguments上的一个属性,指向自己。当需要获取到function自身的引用时,会用到这个属性。比如实现匿名函数的递归调用

function test(){
    console.log(arguments.callee === test);
}

test();// true
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

javascript几个知识点 的相关文章

  • 禁用内容安全策略

    当我开发网站时 我经常想看看特定功能在网站上的外观如何 所以我会使用 chrome 开发者工具并经常运行一些 javascript 脚本 我经常发现一些脚本由于内容安全策略 CSP 而无法运行的问题 我完全理解该策略是为了防止跨站点脚本攻击
  • angularjs:如何向资源对象添加缓存?

    在 http 中添加缓存非常简单 通过传递cache true http docs angularjs org api ng http https docs angularjs org api ng service 24http有缓存选项
  • 如何通过单击图像预览上的“x”从文件输入中删除图像?

    我目前有一个文件输入 一旦用户上传图像 就会显示图像预览 在图像预览上 有一个 x 可以从列表中删除图像预览 单击此 x 后 有什么方法可以从输入中的文件集中删除图像吗
  • 如何使用 JavaScript 中的值填充下拉列表?

    我在 Tridion CMS 扩展中的功能区工具栏按钮中添加了一个按钮 单击该按钮后 将显示一个弹出页面 其中包含两个下拉菜单 通过更改第一个下拉控件中的值 我应该填充第二个下拉控件的值 就我而言 我正在使用ASP drop down li
  • 在Javascript中按降序对字符串进行排序(最有效)?

    W3Schools 有这个例子 var fruits Banana Orange Apple Mango fruits sort fruits reverse 这是在 Javascript 中按降序对字符串进行排序的最有效方法吗 Updat
  • jquery 验证错误位置

    这看起来很简单 但我无法弄清楚 我正在使用 jquery 验证插件 我验证所有文件 但我想要的是在输入文本行中显示验证消息警报 例如在电子邮件输入中 请填写电子邮件地址 但现在它出现在所有字段下 在我的html中
  • 动画进度元素值

    我有一个progress元素 该元素如下所示 div class container div div div
  • JavaScript 中数组的 HTML 数据列表值

    我有一个简单的程序 它必须从服务器上的文本文件中获取值 然后将数据列表填充为输入文本字段中的选择 为此 我想要采取的第一步是我想知道如何动态地将 JavaScript 数组用作数据列表选项 我的代码是
  • 如果链接包含特定文本,jQuery 将类添加到 href

    我的网站上的列表中有一些动态填充的链接 这些链接链接到文件 是否可以使用 jQuery 查看文件名是否以 pdf 结尾 并在 href 或类似的链接文本以 mp3 结尾时添加一个类 例如 我的列表中有以下链接 文件1 pdf 歌曲1 mp3
  • 未捕获的错误:找不到模块“jquery”

    我在用Electron https github com atom electron制作桌面应用程序 在我的应用程序中 我正在加载一个外部站点 Atom 应用程序之外 可以说http mydummysite index html http
  • 是否有任何非轮询方式来检测 DOM 元素的大小或位置何时发生变化?

    很长一段时间以来 我一直在寻找一种方法来检测 DOM 元素的大小或位置何时发生变化 这可能是因为窗口调整了大小 或者因为向该元素添加了新的子元素 或者因为在该元素周围添加了新元素 或者因为 CSS 规则已更改 或者因为用户更改了浏览器的字体
  • 在d3.js中将2D形状转换为3D,并根据ANGULAR中的值调整高度

    我正在使用 d3 js v6 创建以下 2D 图表表示的 3D 图表 这个圆圈中有多个正方形 每个正方形都根据值分配了一种颜色 值越大 正方形越暗 现在我想将其转换为 3D 形状 其中当值变高时 只有特定正方形的高度会增加 因此结果在某种程
  • JS用正则表达式替换数字

    我有元素的标识符 如下所示 form book 1 2 3 我想要的是用其他值替换该标识符中的第二个数字 我将函数 match 与以下正则表达式一起使用 var regexp d d d 但它返回我包含的数组 1 2 3 2 因此 当我尝试
  • IE11不监听MSFullscreenChange事件

    我正在尝试使用 Bigscreen js 在 IE11 中使用全屏 但 IE11 不监听 MS FullscreenChange 事件 document addEventListener MSFullscreenChange functio
  • 单击关闭按钮后不显示 Google 一键登录 UI

    我正在尝试按照本指南使新的谷歌一键登录工作 https developers google com identity one tap web https developers google com identity one tap web
  • 查询为空 Node Js Sequelize

    我正在尝试更新 Node js 应用程序中的数据 我和邮递员测试过 我的开发步骤是 从数据库 MySQL 获取ID为10的数据进行更新 gt gt 未处理的拒绝SequelizeDatabaseError 查询为空 我认识到 我使用了错误的
  • 如何在 javascript 正则表达式中匹配平衡分隔符?

    我原以为这个问题是不可能的 据我所知 Javascript 的正则表达式既没有递归插值 也没有漂亮的 NET 平衡组功能 但问题就在那里 如问题 12 所示正则表达式 alf nu http regex alf nu 匹配平衡对 lt an
  • 防止文本区域出现新行

    我正在开发聊天功能 使用 Vue 并使用文本区域作为输入 以便溢出换行 并且对于编写较长消息的用户来说更具可读性 不幸的是 当用户按下 Enter 键并提交时 光标会在提交之前移动到新行 从而使用户体验感觉不佳 关于如何使用普通 Javas
  • 单击列表时使用 bootstrap Dropdown 防止下拉菜单消失

    我正在使用使用引导下拉菜单 http twitter github com bootstrap javascript html dropdowns生成下拉菜单 我想防止点击菜单时菜单消失 我已经实现了以下代码 但它不起作用 知道如何修复它吗
  • 在 GWT 中,在任何主机页标记上添加事件处理程序

    我想为任何标签添加 MouseOver 事件处理程序 举个例子 我想为旧版 HTML 页面中的每个锚点页面添加事件处理程序 继GWT指南 http code google com webtoolkit doc 1 6 DevGuideUse

随机推荐

  • 就现在!为元宇宙和Web3对互联网的改造做准备!

    欢迎来到Hubbleverse 关注我们 关注宇宙新鲜事 预计阅读时长 8分钟 本文仅代表作者个人观点 不代表平台意见 不构成投资建议 如今 互联网是各种不同的网站 应用程序和平台的集合 由于彼此分离 它们缺乏互操作性和数据可移植性 因此
  • ant design vue中menu组件递归渲染报错解决

    ant design vue中menu组件递归渲染报错 开始递归组件后打开页面后报错如下 解决如下 使 单 件 式递归 成菜单 Before v2 0 因组件内部会动态更改a sub menu的属性 如果拆分单文件 无法将属性挂载到a su
  • BI的需求调研的方法分类

    今天看到一篇文章 里面提到需求调研的几种思路 觉得分类有些道理 结合项目写一下 这种方法论在指导实践和体现专业两个方面都很实用 1 现有报表 这个是最常用的 使用这种方法注意区别报表目的 紧急度 和数据是否适合在BI实现 细节度 为什么以前
  • Oracle统计多张表的Count数的和

    需求描述 Table1 job1 job1 id name status other column 1 file1 process 2 file2 failed 3 file3 success Table2 job2 job2 id nam
  • 03:MYSQL----DQL,聚合函数

    目录 1 介绍 2 语法 3 聚合函数 4 DOL 语句练习 5 SQL执行顺序 1 介绍 数据查询语言 用来查询数据库中表的记录 2 语法 select 字段列表 from 表名列表 where 条件列表 group by 分组字段列表
  • 手写 git hooks 脚本

    我们的 Git 仓库中包含了编译后的代码 所以每次修改了源码 都需要运行一下编译命令 然后把源码和编译后的代码一起提交到 Git 仓库 这个流程没什么问题 但是 人脑不是电脑 总会有疏忽的时候 经常会出现这样一种情况 修改了源码 却忘记了运
  • sql判断字段是否为null,是否为空串

    问题现象 今天在项目中思考了一个问题 如何在sql中判断一个字段是否为 null值 是否为 空串 呢 问题分析 需要注意的是 null值 和 空串 并不是同一个概念 null值 就是这个字段没有赋值 也就是java中常说的 null 而 空
  • 权重实现随机抽奖

    一般抽奖是怎么实现的 在实习期间学会了一种通用的写法 在这里记录一下 最近在学Golang语法基础 这里就用Golang来写 package main import fmt time math rand func main r rand N
  • 模态对话框与非模态对话的几种销毁方法与区别

    前几天发现自己的程序中使用非模态对话框 Debug版本有警告提示如下 Warning calling DestroyWindow in CWnd CWnd OnDestroy or PostNcDestroy in derived clas
  • 关于高并发与多线程中的线程池

    关于高并发与多线程中的线程池 定义 线程是稀缺资源 它的创建与销毁是一个相对偏重且耗资源的操作 而Java线程依赖于内核线程 创建线程需要进行操作系统状态切换 为避免资源过度消耗需要设法重用线程执行多个任务 线程池就是一个线程缓存 负责对线
  • Qt webengine 显示web页面、前后端通信以及下载详解

    概述 官方文档 https doc qt io archives qt 5 11 qtwebengine overview html 翻译文档 Qt5 9 WebEngine 概述 一花一世界 一叶一乾坤 博客园 从Qt5 5开始 Qt W
  • libuv 原理_[Nodejs原理] 核心库Libuv入门(Hello World篇)

    Libuv是什么 1 简介Libuv是一个高性能的 事件驱动的异步I O库 它本身是由C语言编写的 具有很高的可移植性 libuv封装了不同平台底层对于异步IO模型的实现 所以它还本身具备着Windows Linux都可使用的跨平台能力 L
  • 数据密集型应用系统设计(2)

    文章目录 数据模型与查询语言 NoSQL 数据库历史 关系数据库与文档数据库现状 数据查询语言 图状数据模型 小结 数据模型与查询语言 大多数应用程序是通过一层层叠加数据模型来构建的 例如 应用程序开发人员观测现实世界 通过对象或者数据结构
  • Vue 和 jQuery 两者之间的区别是什么?

    1 jQuery 介绍 jQuery 曾经也是现在依然最流行的 web 前端 js 库 可是现在无论是国内还是国外他的使 用率正在渐渐被其他的 js 库所代替 随着浏览器厂商对 HTML5 规范统一遵循以及 ECMA6 在浏 览器端的实现
  • NGINX配置PHP网站

    NGINX配置PHP网站 NGINX配置PHP网站 源码安装NGINX 安装PHP 修改PHP参数 重启PHP 修改nginx配置文件 重启NGINX 测试 解决报错问题 NGINX配置PHP网站 源码安装NGINX 脚本一键安装 安装路径
  • springboot 整合EHcache 实现分页缓存

    一 简要概述 Cacheable 对当前的对象做缓存处理 Cacheable 作用 把方法的返回值添加到 Ehcache 中做缓存 Cacheable value xxx key xxxx Value 属性 指定一个 Ehcache 配置文
  • 小米造车?年轻人的第一辆电动车?

    素来有着价格屠夫称号的 小米 终于要对电动车出手了 事件简讯 昨天下午 据 晚点LatePost 爆料 小米 已确定造车 并视其为战略级决策 不过具体形式和路径还未确定 或许仍有变数 一位知情人士称 小米造车或将由小米集团创始人雷军亲自带队
  • 软件质量保障之代码走查

    目的 代码走查有几个目的 第一个是让新同学快速熟悉代码并了解系统 第二个是做咨询防控的事前检查 避免引发线上故障 第三个是通过一起讨论和审查 加强团队代码阅读和编写能力 让大家编写出优秀的代码 代码走查的优点非常多 但是最核心的还是提前发现
  • 模2除法——用非常直观的例子解释

    前言 差错检测中有名唤CRC之方法 但很多学习者难以理解其运行原理 特别是模2除法 故博主将其原理以示例方式记录下来 以便同道稍作借鉴 因博主水平有限 难免会出现错误 希各位能多多包涵和给予建议 注意 本博客假设各位已理解CRC原理但对模2
  • javascript几个知识点

    本文总结一下javascript几个比较重要的知识点 包括scope chain this 和函数的一些高级特性 scope chain scope chain是javascript函数调用里最核心的概念 尤其是要理解闭包的概念的话 必须先