理解object、context、this、closure和return——初级进阶的必经之路--转载

很多时候写js,根本不会用到「对象」这个东西,因为一般而言初级前端的作用是操作DOM实现一些炫酷效果,而万能的jQuery已经替我们封装好了90%在开发中会用到的函数。但是有个大自然的规律是,越是没有难度的事情,它的价值就越低,如果你想走一条进阶之路,了解标题中的这些名词的含义是非常重要的———这是我在学习过程中的感悟。

言归正传。

1、什么是object

Javascript中有一条定理:一切皆对象。之所以这么有名是因为对象object这个概念在所有OO语言中都存在,但是没有像Javascript这么面向对象面向的这么彻底,我觉得一方面是因为Javascript的语言特质决定的,它轻巧,开放,灵活,优美。。。『Javascript是最好的语言』

怎么又开始废话了。

好了再次言归正传。

在Javascript,一切皆对象,而什么是对象呢?大多数书本上的说法是:对象是一组属性和方法的集合,我表示同意。

对象可以通过如下方法来创建:

var o = new Object();也可以var o = {};

对象怎么创建的不重要,重要的是它能做什么,你可以这样往对象里面增加属性和方法:

var o = new Object();

o.name = 'xheldon';

o.site = 'xheldon.com';

o.come = function(){

    console.log('GlaDOS')

}

也可以这样:

var o = {

    name:'xheldon',

    site:'xheldon.com',

    come:function(){

        console.log('GlaDOS')

    }

}

『一切皆对象』!?

我们可以这样声明一个字符串的属性和方法:

var s = new String('abc');s.name = 'def';console.log('s的值是:'+s+',s.name的值是:'+s.name);//输出结果『s的值是abc,s.name的值是:def』

这样一来,字符串就增加了一个叫做name的属性而被当做对象来处理。

注意:不能直接通过如下方式来为字符串增加属性和方法:

var s = 'abc';s.name = 'def';console.log('s的值是:'+s+',s.name的值是:'+s.name)//输出结果『s的值是:abc,s.name的值是:undefined』

其实前一个增加属性的本质是先隐式的将字符串'abc'转化成String对象,再将其赋值给s,最后再添加属性。因此这个操作是对引用类型而言的,对基本类型增加属性和方法是无效的(但是也不会报错,只是undefined),由此可见,『一切皆对象』在Javascript中是个谎言,其并没有将散落在内存中的基本类型真正的当做对象对待,而是使用的时候隐式的转化成String对象,再进行操作。

所有的对象都是继承自Object对象,因此你可以对任何对象来使用typeof操作,除了基本类型之外,都会显示object类型,不过书上说instanceof这个方法检测类型会更可靠,因为它会告诉你这个对象是哪个Object子对象的实例,Javascript里面有些内置的对象,我称它为子对象,或者叫做引用类型。如String、Array、Function、Date、Number等。

示例:

console.log(typeof 'abc');//string

console.log(typeof new String('abc'))//object

console.log('abc' instanceof String)//false

var n = new String('abc');n instanceof String//true

2、context和this

如上所述,Function也是对象,不过首先你需要知道的是,通过function(){}创造出来的就是函数,它就是对象,它没有名字。

我就是我,是不一样的烟火

但是就像new String('abc')一样,这个语句是有效的,但是也是毫无用处的。你不给它名字,它就一直躺在内存中,直到内存回收器将其回收,就像它从未存在过一样

也许有人会说,匿名函数不也是经常被使用吗?此为后话,我们一会儿再提。

因此,你想声明一个函数,首先第一件事就是给它个名字以方便我们引用:

var s = function(){console.log('我被引用啦!')};//我被引用啦!

而声明一个函数并将其赋值给一个变量之后,它还是静静的躺在内存中,就像从未存在过,你需要在其赋值的变量后面加个括号来执行它,就像这样:

s();

那这个和上下文有啥关系呢?别急,好戏开始了。

context翻译过来是上下文,上下文是和this以及作用域是密不可分的。你可以像下面这样将this指向一个函数的上下文(如果你能明白「指向」的含义的话):

var o = {

    name:'xheldon',

    getname:function(){

        console.log(this.name);

    }

}

o.getname();//xheldon

名字为getname的函数的上下文指向对象o,所以毫无疑问o.name为xheldon

下面这个将context变得复杂一点点:

var o = {

    name:'xheldon',

    getname:function(){

        console.log(this.name);

    }

}

var p = {

    name:'whyme'

}

o.getname.call(p)//whyme

这个例子中我将对象o中的叫做getname的函数(也即对象o的方法)的上下文设置为p。

有过其他语言基础的同学可能会有疑问,这特么函数声明时的this还能随便让给别人的啊?

是的,在Javascript中,函数执行时的上下文是由函数调用时决定的,而不是函数声明时决定的

还有个例子,我们将这个例子再变复杂一点点:

var o = {

    name:'xheldon',

    getname:function(){

        var name = 'inset';

        var a = function(){

            console.log(this.name);

        }

        a();

    }

}

o.getname()//undefined

为啥是undefined呢?按照刚才的说法,函数也是对象,那a()执行的过程是在m函数里面执行的,按理说a函数的this.name应该是inset才对啊!

非也~

在Javascript中,所有的函数,如果左边没有xxx.的形式的对象来引用,或者没有call,apply,bind之类的来强行改变上下文,那么这个函数默认的上下文对象指向的是window也即指向顶层对象,即使这个函数不在window顶层声明且已经使用了var声明也是如此。

不信?没关系,实践是检验真理的唯一标标准

看下上面那个例子的变形:

var name = "I'm the window object!"

var o = {

    name:'xheldon',

    getname:function(){

        var name = 'inset';

        var a = function(){

            console.log(this.name);

        }

        a();

    }

}

o.getname()//I'm the window object!

3、scope和closure

closure中文翻译为闭包,中文就是牛逼,故名思议,闭包意为封闭的包,也即内部的东西你是看不到的。

你们要的匿名函数:匿名函数最大的作用是用来创建闭包,如下:

(function(para){

    //body

})(para)

闭包常常被用在一个函数的内部嵌套(nested)。除非在闭包里return相关信息否则外部函数无法访问里面的东西。

为什么?

内部函数内心独白:『特么的这是老子的scope啊!!!』

没有块级作用域:

function s(){

    var name = 'xheldon';

    {

        var name = 'anotherxheldon'   

    }

    console.log(name);

}

s()//anotherxheldon

闭包示例:

function a(){

    var b = 'xheldon';

    (function(){

        var b = 'anotherxheldon';

        console.log(b);

    })()

    console.log(b);

};

a();//分别输出『anotherxheldon』和『xheldon』

闭包的应用:创建命名空间,减少命名冲突:

var o = {};

(function(){

    var a = function(){ /*代码的实现省略了*/ };

    function bt(){}

    var xxx;一些可能会冲突的命名

    var xxx;一些可能会冲突的命名

    var xxx;一些可能会冲突的命名

    oEvent.a = a;

    oEvent.b = b;

})();

这里a和b都是局部变量,可以为o对象新增了两个方法,这样就可以访问闭包内的函数而又不会造成命名冲突,大大减少了全局变量的使用;

闭包还能简化操作:

var s = (function(x,y){return x+y})(2,3)//s被赋值为5

//也可以这样写,但是不推荐:

var s = function(x,y){return x+y}(2,3)//省略括号的写法

而不使用闭包时:

var s1 = function(x,y){return x+y}

var s2 = s1(2,3)

4、return

简单说,return返回的是指针/引用,举例来说:

返回字符串值:

var f = function(){var s = 'name';return s};

var sValue = f();//sValue的值为'name'字符串

返回函数引用:

var s = function(){return function(){console.log('xheldon')}};

s()()//xheldon

因为s()执行的结果是个匿名函数的引用,因此需要再执行一次,所以就再加了个括号。

连续返回:

function compare(a,b){

    return function(a,b){

        if(a>b){return -1}

        if(a<b){return 1}

        if(a=b){return 0}

    }

}

/**

*等同于

*function compare(a,b){return a-b}

**/

转载自:http://www.xheldon.com/?p=449

转载于:https://www.cnblogs.com/liujinF21/p/5005978.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,让我们来了解一下ε-closure(I)的概念:ε-closure(I)是指从状态集合I开始,通过零个或多个ε转换可以到达的所有状态的集合。在有限状态自动机(Finite State Machine)中,ε-closure(I)非常有用,可以帮助我们确定一个状态集合的闭包。 现在,让我们来介绍一下如何使用我们开发的ε-closure(I)程序。 1. 下载程序: 你可以从我们的GitHub仓库,下载ε-closure(I)程序的源代码,或者下载已编译好的可执行文件。 2. 运行程序: 打开命令行终端,进入程序所在的文件夹,运行以下命令: ``` ./epsilon_closure ``` 3. 输入状态集合: 程序会提示你输入状态集合,以空格分隔每个状态,例如: ``` Enter the states: q0 q1 q2 ``` 4. 输入ε转换: 程序会提示你输入ε转换,以逗号分隔每个转换,例如: ``` Enter the epsilon transitions: q0,q1 q1,q2 q2,q0 ``` 5. 输入操作: 现在,你可以选择执行以下操作: - 输入状态集合,计算ε-closure(I) - 输入单个状态,计算ε-closure(S) - 退出程序 6. 运行操作: 输入操作序号,按回车即可执行对应操作。例如: ``` Choose an operation: 1 - Compute epsilon closure of a state set 2 - Compute epsilon closure of a single state 3 - Exit Enter your choice: 1 Enter the state set: q0 q1 ``` 程序会输出ε-closure(I)的结果。 以上就是ε-closure(I)程序的使用说明。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值