解析JavaScript面向对象概念中的Object类型与作用域


Posted in Javascript onMay 10, 2016

引用类型

引用类型主要包括:Object 类型、Array 类型、Date 类型、RegExp 类型、Function 类型等等。

引用类型使用时,需要从它们身上生成一个对象(实例)。也就是说,引用类型相当于一个模版,当我们想要用某个引用类型的时候,就需要用这个模版来生成一个对象来使用,所以引用类型有时候也称作对象定义。

例如,我们需要生成一个 person 对象,来定义某人的个人信息和行为,那么我们就需要依赖 Object 类型:

var person = new Object();
person.name = "jiangshui";
person.sayName = function(){
  console.log(this.name);
}

上面的这个 person 对象,通过 new 操作符使用 Object 类型这个“模版”定义。之后就可以对这个对象添加属性 name 和方法 sayName 了。属性和方法是 Object 类型具有的“功能”,所以通过 Object 等引用类型创建的对象就可以用这个了。

创建对象不一定非得需要用 new 操作符,有一些类型可以简化的创建,例如创建一个上面那样的 Object 类型的对象,也可以使用下面两种方法:

var person = {};
person.name = "jiangshui";
person.sayName = function(){
  console.log(this.name);
}

var person = {
  name : "jiangshui",
  sayName : function(){
    console.log(this.name);
  }
};

{}操作符的功能就跟 new Object() 一样,简化了操作。上面两种写法也有一些区别,第一种是“追加”,也就是在之前的定义中,继续添加属性或者方法,如果之前已经存在了同名属性方法,则会覆盖。而第二种是“取代”,就是不管前面是否定义 person 对象的属性和方法,这个方法会用新定义的内容,整个替换掉之前定义的。因为引用类型生成的对象,是储存在内存中的一块区域,然后将其指针保存在某变量中(person),第二种写法,是生成了一个新对象(新内存区域),然后将 person 变量指向了新内存区域,所以就把之前的取代了。了解这一点对后面理解,至关重要。

其他引用类型的用法大致一致,例如 Array 类型,也可以用 [] 来生成对象,或者直接定义。生成数组对象之后,就可以按照数组的格式存储信息内容,此外对象会得到 Array 类型中定义的那些方法,例如 push、shift、sort 等等,就可以调用这些方法,例如:

var colors = [];
colors.push('red','green');
console.log(colors);

上面代码就是通过 Array 类型创建一个数组类型的对象,然后调用 Array 类型里面之前定义的 push 方法,向对象里面添加了 red 和 green 两个值,最后在控制台打印出来,就可以看到了。

call 和 apply 方法

这两个方法是 Function 类型提供的,也就是说,可以在函数上面使用。call 和 apply 方法的功能一样,就是可以扩充函数运行的作用域,区别就在于使用 call 的时候,传递给函数的参数必须逐个列举出来,而 apply 方法却不用。这样可以根据自己函数的要求来决定使用 call 或者 apply。

扩充函数运行的作用域是什么意思?举个例子你就明白了。

你可以这样理解,函数被包裹在一个容器(作用域)里面,在这个容器里面存在一些变量或者其他东西,当函数运行,调用这些变量等,就会在当前容器里面找这个东西。这个容器其实外面还包裹了一个更大的容器,如果当前小容器没有的话,函数会到更大的容器里面寻找,依次类推,一直找到最大的容器 window 对象。但是如果函数在当前小容器里面运行的时候,小容器里面有对应变量等,即便是大容器里面也有,函数还是会调用自己容器里面的。

而 call 和 apply 方法,就是解决这个问题,突破容器的限制。就前面例子:

var person = {
  name : "jiangshui",
  sayName : function(){
    console.log(this.name);
  }
};

打开 Chrome 的 Console 之后,粘贴进去执行一下,之后再执行 person.sayName() 可以看到

解析JavaScript面向对象概念中的Object类型与作用域

这时候,person 就是一个容器,其中创建了一个 sayName 方法(函数),执行的时候,必须在 person 作用域下面执行。当在最下面直接执行的时候,也就是在 window 的作用域下面执行会报错 not defined,因为 window 下面没有定义 sayName 方法。而里面的 this 指针,是一个比较特殊的东西,它指向当前作用域,this.name 的意思,就是调用当前作用域下面的 name 值。

下面我们为 window 对象添加一个 name 属性:

window.name = "yujiangshui";

或者直接

name = "yujiangshui";

因为 window 是最大的容器,所以 window 可以省略掉,所有定义的属性或者变量,都挂靠到 window 上面去了,不信可以看:

解析JavaScript面向对象概念中的Object类型与作用域

那现在我们就想在 window 这个大容器下面,运行 person 小容器里面的 sayName 方法,就需要用 call 或 apply 来扩充 sayName 方法的作用域。执行下面语句:

person.sayName.call(window);

或者

person.sayName.call(this);

输出的结果都是一样的,你也可以换用 apply 看看效果,因为这个 demo 太简单的,不需要传递参数,所以 call 和 apply 功能效果就完全一致了。

解析JavaScript面向对象概念中的Object类型与作用域

解释一下上面代码,sayName 首先是 Function 类型的实例,也就具有了 call 方法和 apply 方法,call 和 apply 方法既然是 Function 类型的方法,所以就需要用这种方式调用 person.sayName.call(window) 而不是什么 person.sayName().call(window) 之类的。

然后 call 和 apply 方法的参数,就是一个作用域(对象),表示将前面的函数在传递进去的作用域下面运行。将 window 这对象传递进去之后,sayName 方法中的 this.name 指向的就是 window.name,于是就扩充了作用域。

为什么传递 window 和 this 都是一样的效果?因为我们当前执行这个函数的位置是 window,前面说过 this 指针指向的是当前作用域,所以 this 指向的就是 window,所以就等于 window。

Javascript 相关文章推荐
syntaxhighlighter 使用方法
Jul 02 Javascript
FF火狐下获取一个元素同类型的相邻元素实现代码
Dec 15 Javascript
Extjs优化(二)Form表单提交通用实现
Apr 15 Javascript
jquery简单的拖动效果实现原理及示例
Jul 26 Javascript
jQuery动画效果-fadeIn fadeOut淡入浅出示例代码
Aug 28 Javascript
分享一则javascript 调试技巧
Jan 02 Javascript
总结在前端排序中遇到的问题
Jul 19 Javascript
jQuery+正则+文本框只能输入数字的实现方法
Oct 07 Javascript
jquery mobile实现可折叠的导航按钮
Mar 11 Javascript
easyui-edatagrid.js实现回车键结束编辑功能的实例
Apr 12 Javascript
基于vue打包后字体和图片资源失效问题的解决方法
Mar 06 Javascript
vue 重塑数组之修改数组指定index的值操作
Aug 09 Javascript
JavaScript根据CSS的Media Queries来判断浏览设备的方法
May 10 #Javascript
JavaScript中的原型prototype完全解析
May 10 #Javascript
简单解析JavaScript中的__proto__属性
May 10 #Javascript
Web Uploader文件上传插件使用详解
May 10 #Javascript
详解原生JavaScript实现jQuery中AJAX处理的方法
May 10 #Javascript
JS上传组件FileUpload自定义模板的使用方法
May 10 #Javascript
使用jQuery处理AJAX请求的基础学习教程
May 10 #Javascript
You might like
中英文字符串翻转函数
2008/12/09 PHP
php中定时计划任务的实现原理
2013/01/08 PHP
php5.5中类级别的常量使用介绍
2013/10/02 PHP
PHP使用FFmpeg获取视频播放总时长与码率等信息
2016/09/13 PHP
解决Laravel blade模板转义html标签的问题
2019/09/03 PHP
php屏蔽错误及提示的方法
2020/05/10 PHP
JavaScript实现点击按钮后变灰避免多次重复提交
2013/07/15 Javascript
解决Jquery鼠标经过不停滑动的问题
2014/03/03 Javascript
深入理解javascript中的立即执行函数(function(){…})()
2014/06/12 Javascript
使用jquery 简单实现下拉菜单
2015/01/14 Javascript
PHP+mysql+Highcharts生成饼状图
2015/05/04 Javascript
js全选按钮的实现方法
2015/11/17 Javascript
jQuery实现可拖拽的许愿墙效果【附demo源码下载】
2016/09/14 Javascript
yarn与npm的命令行小结
2016/10/20 Javascript
原生js实现对Ajax的封装(仿jquery)
2017/01/22 Javascript
关于JavaScript的单双引号嵌套问题
2017/08/20 Javascript
MVVM 双向绑定的实现代码
2018/06/21 Javascript
基于React Native 0.52实现轮播图效果
2020/08/25 Javascript
layui switch 开关监听 弹出确定状态转换的例子
2019/09/21 Javascript
laravel实现中文和英语互相切换的例子
2019/09/30 Javascript
vue使用transition组件动画效果的实例代码
2021/01/28 Vue.js
Python基础知识_浅谈用户交互
2017/05/31 Python
Python实现GUI学生信息管理系统
2020/04/05 Python
目前不被任何主流浏览器支持的CSS3属性汇总
2014/07/21 HTML / CSS
Kent & Curwen:与大卫·贝克汉姆合作
2017/06/13 全球购物
Lime Crime官网:美国一家主打梦幻精灵系的彩妆品牌
2019/03/22 全球购物
运动会开幕式邀请函
2014/01/22 职场文书
知名企业招聘广告词大全
2014/03/18 职场文书
中国梦主题教育活动总结
2014/05/05 职场文书
党的群众路线教育实践活动个人整改方案
2014/09/21 职场文书
2014年个人工作总结报告
2014/11/27 职场文书
优秀共产党员事迹材料
2014/12/18 职场文书
幼儿园新学期开学寄语
2015/05/27 职场文书
保留意见审计报告
2015/06/05 职场文书
同意报考公务员证明
2015/06/17 职场文书
Python机器学习之KNN近邻算法
2021/05/14 Python