博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript核心概念及实践
阅读量:5838 次
发布时间:2019-06-18

本文共 10088 字,大约阅读时间需要 33 分钟。

1.JavaScript中的数据类型

在Javascript中,包含6种数据类型:字符串(string)、数值(number)、布尔值(boolean)、undefined、null以及对象(object)。PS:第6种应该是object还是symbo(ES6)?

2.JavaScript中的对象

此处的对象包括:对象(属性的集合,即键值的散列表)、数组(有序的列表)、函数(包含可执行的代码)

3.相等与等同运算符

相等运算符:如果操作数具有相同的类型,则判断其等同性,如果两个操作数的值相等,则返回true,否则返回false。

如果操作数的类型不同,则按照这样的情况来判断:

  • null和undefined相等;
  • 其中一个是数字,另一个是字符串,则将字符串转换为数字,再做比较;
  • 其中一个是true,先转换为1(false转为0)再做比较;
  • 如果一个值是对象,另一个是数字/字符串,则将对象转换为原始值(通过toString()或者valueOf());
  • 其他情况,直接返回false。

<br/>

等同运算符(===):如果操作数的类型不同,则不进行值的判断,直接返回false。

如果操作数的类型相同,分下列情况来判断:

  • 都是数字的情况,如果值相同,则两者等同(有一个例外,就是NaN,NaN与其本身也不相等),否则不等同;
  • 都是字符串的情况,与其他程序设计语言一样,如果串的值不相等,则不等同;
  • 都是布尔值,且值均为true/false,则等同;
  • 如果两个操作数引用同一个对象(数组,函数),则两者完全等同;

如果两个操作数均为null/undefined,则等同。

4.原型对象及原型链

javascript本身是基于原型的,每个对象都有一个prototype的属性,这个prototype本身也是一个对象,因此它本身也可以有自己的原型,这样就构成了一个链结构。
访问一个属性的时候,解析器需要从下向上的遍历这个链结构,直到遇到该属性,则返回属性对应的值,或者遇到原型为null的对象(javascript的基对象Object的构造器的默认prototype有一个null原型),如果此对象仍没有该属性,则返回undefined。

5.数组对象的方法

方法 描述
concat() 连接两个或更多的数组,并返回结果数组
join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔
pop() 删除并返回数组的最后一个元素
push() 向数组的末尾添加一个或更多元素,并返回新的长度
reverse() 颠倒数组中元素的顺序
shift() 删除并返回数组的第一个元素
slice() 从某个已有的数组返回选定的元素
sort() 对数组的元素进行排序
splice() 删除元素,并向数组添加新元素
unshift() 向数组的开头添加一个或更多的元素,并返回新的长度
valueOf() 返回数组对象的原始值

6.借助数组对象自身的slice方法删除数组某个数据

jQuery的设计者John Resig提供的方法
Array.prototype.remove = function (from, to) {    var rest = this.slice((to || from) + 1 || this.length);    this.length = from < 0 ? this.length + from : from;    return this.push.apply(this.rest);};array.remove(0);//删除第一个元素array.remove(-1);//删除倒数第一个元素array.remove(0,2);//删除数组下标为0-2的元素(3个)

7.正则表达式

元字符 含义
^ 串的开始
$ 串的结束
* 零到多次匹配
+ 一到多次匹配
? 零或一次匹配
b 单词边界
字符 含义
字符本身 匹配字符本身
r 匹配回车
n 匹配换行
t 制表符
f 换页
x# 匹配十六进制数
cX 匹配控制字符
标志符 含义
[...] 在集合中的任一个字符
不在集合中的任一个字符
. 除n之外的任一个字符
w 所有的单字,包括字母数字及下划线
W 不包括所有的单字,w的补集
s 所有的空白字符,包括空格,制表符
S 所有的非空白字符
d 所有的数字
D 所有的非数字
b 退格字符
标记 含义
{n} 重复n次
{n,} 重复n或更多次
{n,m} 重复至少n次,至多m次
var pid = /^(\d{15}|\d{18})&/;//身份证var mphone = /\d{11}/;//手机号码var phone = /\d{3,4}-\d{7,8};//电话号码

8.使用正则表达式

创建正则表达式:

  • 使用字面量:var regex = /pattern/;
  • 使用RegExp对象:var regex = new RegExp("pattern", switchs);

而正则表达式的一般形式描述为:var regex = /pattern/[switchs];

这里的开关(switchs)有以下三种:

修饰符 描述
i 忽略大小写开关
g 全局搜索开关
m 多行搜索开关(重定义^与$的意义)

正则表达式对象的方法:

方法名 描述
test() 测试串中是否有合乎模式的匹配
exec() 对串进行匹配
compile() 编译正则表达式

9.String中的正则表达式

除了正则表达式对象及字面量外,String对象中也有多个方法支持正则表达式操作。
方法 作用
match 匹配正则表达式,返回匹配数组
replace 替换
split 分割
search 查找,返回首次发现的位置
var str = "life is very much like a mirror.";var result = str.match(/is|a/g);//返回["is", "a"]var str = "Welcome, John";var result = str.replace(/span/g, "div");//
Welcome, John
如果想把Welcome和John两个单词调换顺序:var result = str.replace(/(\w+),\s(\w+)/g, "$2, $1");//John,Welcome

10.正则表达式中括号的作用

  1. 括号用来将子表达式标记起来,以区别于其他表达式,比如很多的命令行程序都提供帮助命令,键入h和键入help的意义是一样的,那么就会有这样的表达式:h(elp)?//字符h之后的elp可有可无
  2. 括号用来分组,当正则表达式执行完成之后,与之匹配的文本会按规则填入各个分组。

    例如:

    var pattern = /\w{4}(\d{4})(\w{2})/;var result = pattern.exec("yunn0871cg");console.log("city code = " + result[1] + ", county code = " + result[2]);//city code = 0871, county code = cg

    正则表达式的exec方法会返回一个数组,数组的第一个元素(下标为0)表示整个串,第一个元素为第一个分组,第二个元素为第二个分组;

  3. 第三种情况,括号用来对引用起辅助作用,即在同一个表达式中,后边的式子可以引用前边匹配的文本。

11.匿名自执行函数

有的函数只需要执行一次,其内部变量无需维护,比如UI的初始化,那么我们可以使用闭包。例如:
var datamodel = {    table: [],    tree: {}};(function (dm) {    for (var i = 0; i < dm.table.rows; i++) {        var row = dm.table.rows[i];        for (var j = 0; j < row.cells; i++) {            drawCell(i, j);        }    }})(datamodel);

我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在执行完后很快就会被释放,最主要的是这种机制不会污染全局对象。

12.缓存

设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包可以做到这一点,因为它不会释放外部的引用,函数内部的值可以得以保留。
var CachedSearchBox = (function () {    var cache = {}, count = [];    return {        attachSearchBox: function (disd) {            if (disd in cache) {//如果在缓存中                return cache[disd];//直接返回            }            var fsb = new uikit.webctrl.SearchBox(disd);//创建            cache[disd] = fsb;//更新缓存            if (count.length > 100) {//保证缓存的大小小于100个                delete cache[count.shift()];//删除最前面那个缓存            }            return fsb;        },        clearSearchBox: function (disd) {            if (disd in cache) {                cache[disd].clearSelection();            }        }    }})();CachedSearchBox.attachSearchBox("input1");

13.闭包实现封装

var person = function () {    //变量作用域为函数内部,外部无法访问    var name = "default";    return {        getName: function () {            return name;        },        setName: function (newName) {            name = newName;        }    }}();person.name;//undefinedperson.getName();//defaultperson.setName("aaa");person.getName();//aaa

14.闭包中的this

关于this我们之前已经做过讨论,它表示对调用对象的引用,而在闭包中,最容易出现错误的地方是误用了this。在js的开发中,一个常见的错误就是将this类比为其他的外部局部变量。
$(function () {    var con = $("#div#panel");    this.id = "content";    con.click(function () {        alert(this.id);//panel    })});
此处的this.id到底引用着什么呢?很多开发者可能根据闭包的概念,做出错误的判断:content,理由是,this.id显示的被赋值为content。然而事实上,这个alert会弹出panel,究其原因,就是此处的this,因为调用对象的存在,使得当闭包被调用时(当这个panel的click发生时),this引用的是con这个jQuery对象。而匿名函数中的this.id="content"是对匿名函数本身做的操作。两个this引用的不是同一个对象。如果想要在事件处理函数中访问这个值,我们必须做一些改变:
$(function () {    var con = $("#div#panel");    this.id = "content";    var self = this;    con.click(function () {        alert(self.id);//content    })});

15.new操作符

在JavaScript中,通过new操作符来作用于一个函数,实质上会发生这样的动作。
首先,创建一个空对象,然后用函数apply方法,将这个空对象传入作为apply的第一个参数以及上下文参数。这样函数内部的this将会被这个空的对象所替代。
var triangle = new Shape("triangle");//上一句相当于下面的代码var triangle = {};Shape.apply(triangle, ["triangle"]);

16.用JavaScript函数实现封装

function Person(name) {    //私有变量    var address = "1";    //公共方法    this.getAddress = function () {        return address;    };    //公共变量    this.name = name;}//公共方法Person.prototype.getName = function () {    return this.name;};//公共方法Person.prototype.setName = function (name) {    this.name = name;};

首先声明一个函数,作为模板,用面向对象的术语来说,就是一个类。用var方式声明的变量仅在类内部可见,所以address为一个私有成员,访问address的唯一方法就是通过我们向外暴露的getAddress方法,而get/setName,均为原型链上的方法,因此为公开的。我们可以做个测试:

var jack = new Person("jack");console.log(jack.name);//jackconsole.log(jack.getName());//jackconsole.log(jack.address);//undefinedconsole.log(jack.getAddress());//1

添加静态变量:

function Person(name) {    //私有变量    var address = "1";    //公共方法    this.getAddress = function () {        return address;    };    //公共变量    this.name = name;}Person.TAG = "javascript-core";//在访问该变量的时候,不需要实例化Person类

17.函数式的JavaScript

函数可以保持自己内部的数据,函数的运算对外部无副作用(修改了外部的全局变量的状态等)。关于函数可以保持自己内部的数据这一特性,成为闭包。示例:
var outter = function () {    var x = 0;    return function () {        return x++;    }};var a = outter();console.log(a());//0console.log(a());//1console.log(a());//2var b = outter();console.log(b());//0console.log(b());//1

变量a通过闭包引用outter的一个内部变量,每次调用a()就会改变此内部变量,应该注意的是,当调用a时,函数outter已经返回了,但是内部变量x的值仍然被保持。而变量b也引用了outter,但是这是一个不同的闭包,所以b开始引用的x值不会随着a()被调用而改变,两者有不同的实例,这就相当于面向对象中的不同实例拥有不同的私有属性,互不干涉。

18.柯里化的概念

柯里化就是预先将函数的某些参数传入,得到一个简单的函数,但是预先传入的参数被保存在闭包中,因此会有一些奇特的特性。比如:
var adder = function (num) {    return function (y) {        return num + y;    }};var inc = adder(1);var dec = adder(-1);console.log(inc(99));//100console.log(dec(101));//100

19.函数式编程风格

通常来讲,函数式编程的谓词(关系运算符,如大于、小于、等于的判断等),以及运算(加减乘除等)都会以函数的形式出现,比如:
a > b
通常表示为:
gt(a, b)
因此,可以首先对这些常见的操作进行一些包装,以便我们的代码更具有“函数式”风格。
如果我们之前的编码风格是这样:
//阶乘    function factorial(n) {        if (n == 1) {            return 1;        } else {            return n * factorial(n - 1);        }    }
在函数式风格下,就应该是这样了:
function factorial(n) {        if (equal(n, 1)) {            return 1;         } else {             return mul(n, factorial(dec(n)));         }`    }

20.活动对象

在JavaScript中,当一个函数被调用的时候,就会产生一个特殊的对象:活动对象。这个对象中包含了参数列表和arguments对象等属性。由于活动对象是变量对象的特例,因此,它包含变量对象所有的属性,如变量定义,函数定义等。
实例:
function func(handle, message) {    var id = 0;    function doNothing(x) {        return x;    }    handle(message);}func(print, "hello");//执行到这里的时候,活动对象被创建

21.作用域链

作用域链与原型链类似,也是一个对象组成的链,用以在上下文中查找标识符(变量、函数等)。查找时也与原型链类似,如果激活对象本身具有该变量,则直接使用该变量的值,否则向上层搜索,依次类推,直到查找到或者返回undefined。作用域链的主要作用是用以查找自由变量。所谓自由变量是指,在函数中使用的,非函数内部局部变量,也非函数内部定义的函数名,也非形式参数变量。这些变量通常来自于函数的“外层”或者全局作用域,比如,我们在函数内部使用的window对象及其属性。
var topone = "top-level";(function outter() {    var middle = "mid-level";    (function inner() {        var bottom = "bot-level";        console.log(topone + ">" + middle + ">" + bottom);    })();})();//在函数Inner中,console.log语句出现的topone、middle变量就是自由变量

22.词法作用域

在javascript中,函数对象的创建和函数本身的执行是完全不同的两个过程。
function func() {    var x = 0;    console.log("func");}//这是函数的创建func();//函数的执行
所谓词法作用域(静态作用域)是指,在函数对象的创建时,作用域就已经建立,而并非到执行时,因为函数创建后可能永远不会被执行,但是作用域是始终存在的。比如在上例中,如果在程序中没有调用func(),那么,func对象仍旧是存在的,在内存的结构可能是这样的:
func.["[[scope]]"] = global.["variable object"];
而当函数执行时,进入函数执行期上下文,函数的活动对象被创建,此时的作用域链是活动对象和"[[scope]]"属性的合成。

23.this的上下文

this值是执行期上下文对象的一个属性(执行期上下文对象包括变量对象、作用域链以及this)。执行期上下文对象有三类,当进入不同的上下文时,this的值会确定下来,并且this的值不能更改。在执行全局代码时,控制流会进入全局执行期上下文,而在执行函数时,又会有函数执行期上下文。例如:
var global = this;var tom = {    name: "Tom",    home: "desine",    getInfo: function () {        console.log(this.name + ", from " + this.home);    }};tom.getInfo();var jerry = {    name: "Jerry",    getInfo: tom.getInfo};jerry.getInfo();global.getInfo = tom.getInfo;global.getInfo();输出结果:    Tom, from desine    Jerry, from undefined    , from undefined

tom对象本身具有name和home属性,因此在执行tom.getInfo时,会打印tom对象上的这两个属性值。当将global.getInfo属性设置为tom.getInfo时,getInfo中的this值,getInfo中的this值,在运行时,事实上是global对象,所以name和home均未定义。

24.window对象

window对象是对浏览器当前窗口的引用,因为浏览器会将window与自身绘制出来的窗口绑定起来,我们对window的操作事实上会映射到浏览器窗口上。正是浏览器本身提供了这种脚本化的能力,我们才有机会通过JavaScript代码来完成很多操作。

25.文档对象模型(DOM)

DOM即文档对象模型,它是一个平台,提供语言无关的API,允许程序访问并更改文档的内容、结构以及样式。HTML文档是一个树形的结构,与浏览器中的页面中的结构一一对应。

26.事件驱动模型

由于客户端JavaScript的开发属于用户界面开发的范畴,因此使用事件驱动模型就显得非常自然了。事件驱动的特点在于:代码块的运行与否与程序流程无关。而传统的流式代码的特点是,从函数的入口进入,依次调用各个子模块的处理函数,最后退出。这种编程模式主要适用于与UI关系不大的场合,很少有异步的过程,这些特点可能要追溯到计算机程序的最初模型——批处理。
而事件驱动模型主要是面向用户的,你无法知道用户会如何使用你的程序,因此就只能通过回调、事件监听等方式,当用户做出某个动作时才会触发之前已经注册好的监听器,从而执行相关代码,而不是顺序地执行。甚至在一次运行中,部分代码始终没有被触发,也就根本不会被执行到。

27.与服务器端交互(Ajax)

Ajax表示异步JavaScript与XML。事实上,Ajax与XML几乎没有任何关系,因为是异步交互,所以用户的页面不用刷新,在同一个页面中,客户端请求服务数据,当服务数据返回时,通过JavaScript将数据片段填充到页面的某个部分,即实现了局部刷新。

  1. ...

转载地址:http://bkncx.baihongyu.com/

你可能感兴趣的文章
从Maya中导入LightMap到unity中
查看>>
大话“扁平化设计”
查看>>
【Unity Shaders】Using Textures for Effects介绍
查看>>
Java排序算法 归并排序
查看>>
Newtonsoft.Json高级用法
查看>>
正则表达式30分钟入门教程
查看>>
解决mysql不允许外部用户连接的问题(host xxx is not allowed to connect to this MySQL server)...
查看>>
poj3748
查看>>
总结个关于MySQL数据库的问题
查看>>
排序算法:七大排序算法的PHP实现
查看>>
网络工作室暑假后第二次培训资料(SQLServer存储过程和ADO.NET访问存储过程)整理(二)...
查看>>
CentOS 7安装tensorflow 1.6
查看>>
Java IO浅析(转)
查看>>
前端js实现 blob转base64位 和 base64位转blob
查看>>
css3的3D翻牌效果
查看>>
ASP.NET MVC 路由
查看>>
Linux mint下firefox安装flashplayer
查看>>
js面向对象小结(工厂模式,构造函数,原型方法,继承)
查看>>
使用VS调试64位应用程序
查看>>
php数组·的方法-数组与数据结构
查看>>