`

javascript几个知识点

 
阅读更多

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

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
<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
分享到:
评论

相关推荐

    几个经典JavaScript控件

    JavaScript是一种广泛应用于网页和网络应用开发的脚本语言,它主要负责处理客户端的交互和...以上知识点涵盖了JavaScript在网页交互中的核心应用,每个话题都值得深入学习和实践,以提升网页的用户体验和功能丰富度。

    JavaScript几个小游戏

    在这个"JavaScript几个小游戏"的压缩包中,我们很可能找到了一些利用JavaScript编写的趣味小游戏,这些游戏能够帮助开发者更好地理解和实践JavaScript的核心概念,同时也能为用户带来娱乐体验。 JavaScript小游戏...

    javascript知识点汇总.doc

    在日常开发中,JavaScript主要用于以下几个方面: 1. 嵌入动态文本到HTML页面,使网页内容更具活力。 2. 对浏览器事件作出响应,如点击、滚动等,实现交互功能。 3. 读取和修改HTML元素的内容,实现动态更新。 4. ...

    javascript笔记 javascript笔记

    根据提供的文件信息,我们可以归纳出以下几个JavaScript相关的知识点: ### JavaScript基础用法 #### 内联JavaScript 内联JavaScript指的是在HTML元素中直接嵌入JavaScript代码的方式。这种方式常见于`&lt;a&gt;`、`...

    几个最简单的JavaScript dropdown menu

    下面我们将详细探讨如何使用JavaScript创建简单下拉菜单及其相关知识点。 1. HTML结构: 创建一个下拉菜单首先需要定义HTML结构,通常包含一个`&lt;ul&gt;`元素作为主菜单容器,每个菜单项由`&lt;li&gt;`元素表示,子菜单则嵌套...

    几个简单的javascript 客户端编码.rar_javascript

    在JavaScript客户端编码中,有几个关键知识点: 1. **DOM操作**:JavaScript可以操作文档对象模型(DOM),改变HTML元素、属性、样式,甚至添加或删除元素。例如,`document.getElementById()`、`document....

    javascript100个小例子

    在JavaScript的学习中,了解和掌握以下几个关键知识点至关重要: 1. **基础语法**:包括变量声明(var、let、const)、数据类型(如字符串、数字、布尔、数组、对象)、运算符(算术、比较、逻辑、三元)、流程控制...

    javaScript

    以下是关于JavaScript的一些核心知识点和历史背景: 1. 什么是JavaScript? JavaScript是一种面向对象的程序设计语言,它具有解释执行的特性,允许在客户端浏览器中直接运行。它不需要特定的运行环境,只需浏览器...

    javascript

    在这个场景下,我们主要关注以下几个核心知识点: 1. DOM操作:在HTML文档对象模型(DOM)的帮助下,JavaScript可以查找、修改或添加页面上的元素。例如,在购物车应用中,我们可能需要找到特定的商品元素,然后在...

    JavaScript算24点小游戏

    在实现这个小游戏的过程中,我们需要关注以下几个核心知识点: 1. **事件监听**:JavaScript 提供了 `addEventListener` 方法来监听用户的操作,例如点击按钮。在游戏中,用户可能会点击“新游戏”或“提示”等按钮...

    几十个JavaScript例子

    本文将深入探讨标题"几十个JavaScript例子"所涵盖的几个关键知识点。 1. **数字动态时钟**:JavaScript可以实时更新页面上的时间显示,创建一个数字动态时钟。通过`setInterval`函数定时调用一个函数来获取当前时间...

    从零开始学JavaScript

    初学者在开始学习JavaScript时,通常需要了解以下几个重要知识点: 1. JavaScript基础语法:包括变量声明、数据类型、运算符、控制结构(if...else语句,switch语句,循环语句等)、函数的定义与使用等。 2. DOM...

    JavaScript函数式编程.pdf

    JavaScript函数式编程的知识点非常丰富,涉及很多方面的内容,下面将详细介绍几个核心知识点。 1. 函数式编程基础 函数式编程(Functional Programming)是一种编程范式,它将计算视为数学函数的评估,并且避免...

    JavaScript权威指南(JavaScript犀牛书一本)

    这本书的知识点广泛且深入,主要包括以下几个方面: 1. **基础语法**:讲解了变量、数据类型、运算符、流程控制(如条件语句、循环)、函数等基本元素,帮助初学者建立JavaScript编程的基本框架。 2. **对象和原型...

    用javascript做简单计算器

    通过分析和解释给定的代码,我们可以总结出以下几个知识点: 1. JavaScript 是一种广泛应用于 web 开发的脚本语言。 2. 计算器可以使用 JavaScript 实现,包括数据处理、运算逻辑和结果显示等。 3. 在实现计算器时...

    JavaScript学习(一)

    在JavaScript学习的第一阶段,通常会涉及以下几个核心知识点: 1. **基础语法**:JavaScript的基础包括变量声明(var, let, const)、数据类型(如字符串、数字、布尔值、null、undefined、对象、数组、Symbol和...

    javascript实例

    JavaScript是一种广泛应用于Web开发的脚本语言,它主要负责网页的动态交互,使得网页具有更强的用户...每个示例可能涵盖一个或多个知识点,通过阅读和实践这些代码,学习者能够加深对JavaScript的理解,提升编程技能。

    Javascript.info Ebook Part 1 The JavaScript language (2019).pdf

    为了提升代码质量,作者在教程中也涉及了以下几个方面: - 调试技巧,特别是在Chrome浏览器中的调试方法。 - 编码风格和注释的规范。 - 避免使用"忍者代码"(即晦涩难懂的代码)。 - 自动化测试的介绍,包括使用...

    javascript函数式编程

    函数式编程指南通常会涵盖以下几个重要知识点: 一等公民的函数:在函数式编程中,函数是一等公民,这意味着函数可以作为参数传递给其他函数、作为结果返回,也可以被赋值给变量。这一特性让代码更加灵活,支持高级...

Global site tag (gtag.js) - Google Analytics