一段奇葩Javascript代码引发的思考
今天与一挚友加同事调试一段奇葩的javascript代码,在分析出结果后,让我萌生了写此篇文章的想法,如有不对之处望指正,也欢迎大家一起讨论。缩减后的js代码如下,你是否能准确说明他的输出值呢?
function DemoFunction(){
this.init = function(){
var func = (function(va){
this.va = va;
return function(){
va += this.va;
return va;
}
})(function(va1, va2){
var va3 = va1 + va2; //干扰代码
return va1;
}(1,2)); console.log(func(20)); this.func = func;
console.log(this.func(100));
}
}
var a = new DemoFunction();
a.init();
如果要解释这段代码,首先我们得有如下几个概念:
- 执行上下文:每次当控制器转到ECMAScript可执行代码时,即会进入一个可执行上下文,参考文献
- this:this的创建是在 “进入执行上下文” 时创建的,在代码执行过程中是不可变的,参考文献。
- 自执行函数:准确来说应该叫:立即调用函数表达式。因为他声明后即执行,参考文献。
详细解释此段代码
一、首先看DemoFunction的构造函数
这是代码的重点,第一层代码可以缩减为如下:
function DemoFunction(){
this.init = function(){
//省略代码....
}
}
表示为DemoFunction的实例提供init方法(声明:此处有误导成份,方法应尽可能放在原型链接上,也就是prototype上。),对外公开的接口。
二、在init方法中,再次省略代码如下:
var func = (function(va){
this.va = va;
return function(){
va += this.va;
return va;
}
})(8/*省略代码...*/); //省略代码....
代码虽短,但信息量巨大,但这样省略部分代码后,你是否可以清晰的看出他的层次结构。
- 首先定义了一个立即执行函数,并把此函数的执行结果赋值给func。
- 需要注意立即执行函数中
this.va=va
这行代码,由于立即执行函数没有调用者,所以在进入可执行上下文时,this会被赋值为Global(浏览器中为window对象)。 - 更需要注意立即执行函数,返回的是一个闭包,在这里一定要注意一个问题:this是在进入可执行上下文时创建的。
- 也就是说此段代码执行完成后,func的值应该是这样的:
func = function(){
va += this.va;
return va;
}
只不过此时他的父级作用域是立即执行函数而已。
三、在init方法中,注意如下代码:
var func = (function(va){
this.va = va;
return function(){
va += this.va;
return va;
}
})(function(va1, va2){
var va3 = va1 + va2;
return va1;
}(1,2));
//省略代码....
va又为一个立即执行函数,这个立即执行函数接受了两个参数va1,va2,但只返回了va1。以此为据,那么可以确定va的值也就为1。接着就执行this.va=va
这句代码,由于当前this为window,所以参数va的值被赋值到了window的一个叫va的属性上。
四、在init方法中,加上输出语句:
var func = (function(va){
this.va = va;
return function(){
va += this.va;
return va;
}
})(function(va1, va2){
var va3 = va1 + va2;
return va1;
}(1,2)); console.log(func(20)); this.func = func;
console.log(this.func(100));
}
主要分析两个console.log,也是产出结果的时候到了。
- 第一个console.log输出的是func(20),这里一定要注意调用者是没有具体指定的,此时默认的就是Global(也就是widnow对象),因此输出为:2
- 第二个console.log输出的是this.func(100),可以看到this.func与func是指向同一个函数的引用,但此时的调用者则指定为this,也就是当前对象的实例,因此输出为:NaN。
原因:this(当前对象的实例)作为调用者,在func的函数中
va += this.va
这句代码中的this是指向当前对象的实例,但当前对象的实例上是没有va属性的。如果你调试跟踪会发现va是有值的,他的值为:1,这是为什么呢?这就是作用域链,va虽然在当前作用域没有,但在父级(也就是window的作用域下)是存一个叫va的属性的。
总结
通过此段示例代码的分析,我们可以体会到要深入理解Javascript代码,必须要明白且深度掌握他的:闭包、this、原型链(作用域链)、立即调用函数表达式、函数等概念和机理。此类概念每时每该都充斥任务一个库或者框架的代码中,有了他们做为基石,理解和看懂别人的Js代码就so easy了。
一段奇葩Javascript代码引发的思考的更多相关文章
- 由闭包引起的对javascript代码可维护性的思考
在最近的编程实践中由闭包的使用引起了我对javascript代码可维护性的思考.面向对象的其中一个特性封装性通过封装可以降低类与类之间或模块与模块之间耦合性从而使我们的设计更加高内聚低耦合,在大规模的 ...
- 因一段JavaScript代码引发的闲扯
前两天,一朋友给我发了一段JavaScript代码: function f1(){ var n=999; nAdd=function(){ n+=1 }; function f2(){ alert(n ...
- 由一段JS代码引发的思考
不知道大家在编程的时候有没有遇到过这种情况,就是在循环遍历删除一部分内容的时候,发现只能删除其中一部分,而另一部分却总也删不掉,然后觉得自己的逻辑没有问题啊,于是陷入了深深的抑郁之中…… 昨天在处理一 ...
- 一段自用javascript代码
function jsontoarray(mjson) { var arr = []; ; for(var x in mjson.data){ arr[i] = new Array(); arr[i] ...
- 前端福利!10个短小却超实用的JavaScript 代码段
JavaScript正变得越来越流行,它已经成为前端开发的第一选择,并且利用基于JavaScript语言的NodeJS,我们也可以开发出高 性能的后端服务,甚至我还看到在硬件编程领域也出现了JavaS ...
- 以优美方式编写JavaScript代码
英文原文:CoffeeScript: The beautiful way to write JavaScript 我用 JavaScript 编程很多年了,写了大量的 JavaScript 代码,即便 ...
- silverlight 中javascript 代码与托管代码的互调用 以及一些思考
silverlight 客户端javascript 代码与托管代码的互调用时比较用意义的同时,因为silverlight本身就是一个插件,如果两者之间不能进行相互的调用,对于web 上的一些特殊的功能 ...
- JavaScript代码段整理笔记系列(二)
上篇介绍了15个常用代码段,本篇将把剩余的15个补齐,希望对大家有所帮助!!! 16.检测Shift.Alt.Ctrl键: event.shiftKey; //检测Shift event.altKey ...
- JavaScript代码段整理笔记系列(一)
30段JavaScript代码——上篇 1.如何区分IE及非IE浏览器: if(!+[1,]){ //IE 11 不支持 alert("这是 IE 浏览器"): }else{ al ...
随机推荐
- Python语言的PyCharm开发工具的简单使用
1.创建一个新的项目 创建一个目录或者文件夹 设置模板:制作一个常用的,模板 # @Author:lnx# @version V1.0# -*- coding:UTF-8 -*- 搜索/替换快捷键 代 ...
- *CTF——shellcode
一看题目是利用shellcode解决问题 伪代码: checksec:开启了NX exp: from pwn import* context(os='linux',arch='amd64',log ...
- SpringBoot与日志框架1(基本使用)
一.日志框架 1.无论在什么系统,日志框架都是一个重要角色,所以理解和用好日志框架是相当重要的:像JDBC一样,日志框架分为接口层的门面和具体的实现组成. 2.市面上的产品: 2.1门面:SLF4J( ...
- c++/qt的数据序列化和反序列化
序列化以及反序列化的实现 struct Body { double weight; double height; }; //结构体 struct People { int age; Body dBod ...
- MYSQL可调用执行自定义SQL的代码
DELIMITER $$ USE `mysql_wispeed01`$$ DROP PROCEDURE IF EXISTS `sp_execSQL`$$ CREATE DEFINER=`sa`@`%` ...
- CF.802C.Heidi and Library (hard) (费用流zkw)
题目链接 复习了下餐巾计划问题.全忘了=-= 首先这是一道网络流.然后本题有\(n\)种建图方法,以及\(smy\) dalao还有单纯形做法. 先假设所有物品都是买入的.那么对于每一天,拆成两个点\ ...
- 英语口语练习系列-C41-食物词汇-鹊桥仙
词汇 1, rice [raɪs] n. 稻:米饭 vt. 把-捣成米糊状 Rice: 米饭 | 大米 | 稻 2, bread [bred] n. 面包:生计 vt. 在-上洒面包屑 Bread: ...
- Python操作Excel, 开发和调用接口,发送邮件
笔记: 上周回顾: 模块: 导入模块的顺序 lyl.py # def hhh(): pass name = 'lyl' a.py import lyl import sys from lyl impo ...
- 详解Session和cookie
1.cookie 1.1. 为什么会有cookie? 由于HTTP是无状态的,服务端并不记得你之前的状态.这种设计是为了HTTP协议的方便,但是也存在一些问题.比如我们登录一个购物网站,我们需要用户登 ...
- Angular 2项目的环境配置和项目搭建
AngularJS2 发布于2016年9月份,它是基于ES6来开发的. AngularJS2 是一款开源JavaScript库,由Google维护,用来协助单一页面应用程序运行.AngularJS2 ...