标签推荐的写法
首先介绍一下几个常见的属性.
async 属性
可以在标签当中直接添加async
确保,改脚本是异步加载,但是切记不要在脚本执行DOM元素的操作.
defer属性
defer属性,只支持对外部链接的脚本进行操作.对内嵌的脚本不支持次操作.加入defer的目的是为了确保脚本在整个页面解析完成后执行,实际其运行机制执行的先后顺序并不确定,只包含一个defer脚本最佳.
严格模式
可以规避一些不安全的行为,如果我们想启用严格模式,那么需要将在脚本的头部或者是函数体内加入"use strict;"
那么就会启用严格模式.如果写在函数体内部那么指定其作用范围是函数体内.
书写规则
1.强烈推荐每个语句后加入分号,否则会导致不正常的解析
2.变量的定义需要额外注意,明确是函数体内的变量那么定义如下,使用var关键声明的变量确保其作用域,如果直接去掉关键字var,那么全局变量就会被覆盖会引起不必要的错误,在严格模式下,赋值给未经声明的变量会导致错误.
function test(){
var value = test;
}
JS 基础数据类型
字符串、数字、布尔、数组、对象、Null、Undefined
typeof 操作符
必须要知道typeof的支持判断的类型的返回的字符串
"undefined" 未定义的值
typeof 操作声明未初始化与未声明的变量都会返回undefined
可以用来判断是否初始化与是否声明,如果代码中明确了所有变量都会被初始化,那么就解决了判断的歧义.
"boolean" bool值
"string" 字符串
"object" 对象或者是null
"function" 函数类型
"number" 数值类型
全局函数isNaN()判断是否为非数字类型,在数值转换的时候undefined类型会转换为NaN的类型
for in
for in
可以用来遍历属性的值.使用forin,单独拿出来需要说明一个问题.养成一个良好的编程风格
//这里的变量加入关键字var
for (var propertyName in window)
//ECMA6添加了新的关键字let,相当于有了块级作用域的概念,在其声明的作用域块才会起作用
for (let a = 1; a < 10; a++){
let a = 10;//循环输出10次
}
函数
函数在严格模式下一些限制:
不能把函数命名为eval,或arguments
不能把参数命名为eval或arguments
不能出现两个参数同名
(一般情况下都不会这么做,只要根据业务去命名参数就不会有这样的情况发生)
arguments可以动态的获取传递的参数,并不是Array的实例但是可以通过下表来进行元素的访问,通过length的属性获取传入参数的个数.
动态获取参数:
function test(arg1, arg2){
alert(arguments[0])
alert(arguments.length)
}
值同步特点:
当时用arguments修改参数的值时,也会影响到对应的参数的值,上例子当中arguments[1] = 10
,那么arg2的值会被改变,反过来就不会成立因为是单向的,在严格模式下,重写arguments的值会导致语法错误
参数传递需要留意的是:
参数传入对象时是引用传递的,因此需要需要留意,参数也是局部变量,对参数重新赋值新的对象不会影响线上.
执行环境
所有的变量都存在于一个执行环境当中,当这个执行环境决定了变量的声明周期,以及哪一部分可以访问其中的变量.
执行环境有全局执行环境和函数执行环境.
每次进入一个新的执行环境,都会创建一个用于搜索的变量和函数的作用域链
函数的局部环境不仅有权访问函数作用域中的变量而且也可以访问父级环境和全局环境
全局环境只能访问全局环境中定义的变量和作用域
变量的执行环境有助于内存释放
作用域链
作用域链:是保证对执行环节有权访问的所有变量和函数的有序访问.
不存在块级作用域.
内存管理
内存管理多数浏览器采取了标记清楚的方式,在一些比较老的浏览器当中可能会存在引用计数的方式管理内存
避免内存泄露问题可以提前将不适用的变量赋值为null,垃圾收集机制会确保其回收.
引用计数的方式还需要注意循环引用的问题.
基础对象
Object
对象的创建分为两种形式:
1.构造函数创建
2.字面量
var obj = {
name:"test"
}
var obj = new Object()
如何动态的访问对象当中的元素?
var pro = "test"
obj[pro]
使用delete删除对象属性.不要使用delete删除数组元素.
Array
构造函数的创建分为两种形式:
1.构造函数创建
2.字面量
当时用构造函数创建时需要注意的是,传入数字和传入多个字符串是不一样的
var arr = new Array(3)//创建一个包含3项的数组
var arr2 = new Array("test")//创建一个包含1项的数组,并对其赋值
字面量创建的方式
var values = [1, 2]//不要在最后一个元素末尾加入','在低版本的IE会创建额外undefined变量
数组当中的length不是只读的,因此可以对其长度进行更改
常用的操作函数
var arr = new Array();
arr.push("");
arr.unshift("");
arr.pop("");
arr.unshift("");
//以上函数执行后的返回值为数组最新的长度
function compareFunc(value1, value2){
if (value1 < value2){
return 1;
}else if(value1 < value2){
return -1;
}else{
return 0;
}
}
arr.reverse();//翻转数组顺序
arr.sort(compareFunc);//传入比较函数
arr.concat(["test"]);
//以上函数的返回值返回新的数组
arr.slice(1)//从位置1到最后的数组元素
arr.slice(1,3)//从位置1到位置3的数组元素
arr.splice(1,2)//删除任意数组的由位置1起,删除的个数
arr.splice(2,1,"test","green")//删除数组由位置2起删除1个元素后,在位置2插入元素
//splice返回的是数组arr被删除的元素
arr.indexOf(4);//从前查找,返回位置
arr.lastIndexOf(4)//从后查找,返回位置
arr.every()//对数组当中的每一项运行给定函数,如果该函数对每一项都返回true则返回true
arr.filter()//对数组当中的每一项运行给定函数返回true的元素组成
arr.forEach()//对数组当中的每一项运行给定函数
arr.map()//对数组当中的每一项运行给定函数,对数组当中的每次函数调用的结果组成数组
arr.some()//对数组当中的每一项运行给定函数,只要有任意一项返回true那么久返回true
//arr.map(function(item, index, arr){
});
arr.reduce(function (prev, cur, index, array){
return 1;
})//prev是前一项的值,cur是当前项的值,index是索引值
arr.reduceRight()
Date
var now = new Date();
now.toDateString();//以特定于实现的格式显示星期几 月 日 年
now.toUTCString();//以特定实现于完整的UTC日期
now.setTime();//传入毫秒级时间戳,并更改变时间互相转化
now.getTime();//获取时间戳
Date.parse();//传入日期类型字符串,进行解析,ISO8601拓展格式
Date.now();//获取时间戳
当然时间类型有很多方法 这里不一一介绍.
RegExp
JS里的正则对象长得比较特殊,奇怪的那种方法时js里字面量的创建方法,其中包含三种模式
g:全局模式
i:不区分大小写模式
m:多行模式
正则表达式改怎么写这里不做过多的介绍,正则表达式在任何语言当中都被广泛应用.因此需要独立的练习加深印象.
//对象的创建
var reg = /test/g;//匹配test,指定模式为g
var reg = new RegExp("test", "g");//匹配test,指定模式为g
//实例方法test
两个实例化方法
var str = "123";
reg.test(str);//test方法在str中匹配test匹配到后返回true否则返回false
reg.exec(str);//exec方法匹配查找到的字符串返回得是一个数组,包含二外的两个属性 index(表示匹配的字符串的位置) input(这里指的就是str)
Function
函数内部有两个特殊的对象:arguments,this
arguments.callee指向函数本身,可以arguments.callee(“params”),严格模式下不可用
this指的是当前域的对象,和他被声明的域没有关系,只和它调用的域有关系
还有其余三个函数apply(),call(),bind()这里不做详细介绍
Number
Number类型重写了toString,toLoaaleString,valueOf方法
使用toString将数字转换为其它进制字符串
使用toFixed, toPrecision将数字修正精度
var num = new Number(10.06);
num.toFiexed(1);//保留小数点后一位10.1
num = 10;
num.toString(2);//转换为二进制字符串
num = 99;
num.toPrecision(2);//当参数传入比当前位数小的情况为科学计数法表示,否则展示精度数字
String
通过length属性获取字符串的长度,是根据字符的编码长度而定
var str = "hello";
str.charAt(1);//获取单个字符,不推荐使用数组下表访问的方式
str.charCodeAt(1);//获取单个字符
str.concat(" world");//拼接字符串,可以传递任意个参数,当然+号应用比较广泛
//求子串有三个函数 传递的可变参数有两种那么就使得存在六种情况 参数还可以传入负数,情况可能变得更加复杂 简单介绍几种 负数忽略
str.slice(3);//功能同 str.substring(3),str.substr(3) 截取前N个字符
str.slice(3, 7);//安位置截取字符串,不截取位置为7的字符
str.substr(3, 7);//从位置3起始截取长度为7的字符串
//字符串搜索的方法
str.indexOf("w");//从前往后查找字符串的位置
str.lastIndexOf("w");//从后往前查找字符串的位置
//去空格方法
str.trim()
//大小写转换
str.toLocaleUpperCase();//推荐使用这个方法,与toUpperCase输出是一致的
str.toLocaleLowerCase();
//字符串的模式匹配的方法
str.match(/123/);//返回matches对象 match.index索引位置 matches[0]匹配元素 matches.lastIndex 与RegExp返回的是一样的对象
str.search(/123/);//返回位置没找到返回-1
str.replae(/1/g, "3");//进行匹配替换,这个常用需要记住
str.split(",");//对字符串str以给定字符串进行分割,也可以传入RegExp
global
所有在全局作用域定义的属性和函数,都是global对象的属性.
在浏览器当中存在两个对象:window Math
encodeURI();//对URI进行编码
encodeURIComponent();//对任何的非标准字符进行编码
decodeURI();//对URI进行解码
decodeURIComponent();//对任何的非标准字符进行解码
eval();//执行一段字符串代码,不推荐使用
Math.random();//生成一个0-1的随机数
面向对象
定义属性:
configurable(主要表示该属性能否被删除)
ennumberable(能否被for in循环)
writable
value
除了value以上的默认值都为true
//设置值
Object.defineProperty(obj, "pro", {
writeable:true,
value:"test"
})
设定set方法get方法,在许多函数里都回存在类似使用
//修改属性
Object.defineProperty(obj, "pro", {
get:function(){
return this.pro;
},
set:function(newValue){
this.pro + newValue
}
})
Object.defineProperties(obj,{
year:{
value:1234,
configurable:false
}
});
获取描述符
Object.getOwnPropertyDescriptor(obj, "pro")
构造函数
创建对象需要使用构造函数去创建,构造函数中使用this指定属性,方法不需要显示的返回值
function MyObject(){
this.name = "test";
this.test = function(){
};
}
var obj = new MyObject();
原型
prototype是一个指针,指向一个对象(这个对象包含由特定类型的所有实例和方法);
访问的层级关系,先到自有属性确认该属性是否存在,然后在原型当中查找
可以通过下述方法设置属性将会被所有对象访问
构造函数,实例与原型:
每一个构造函数(Foo)都有一个原型对象(Foo.prototype),原型对象包含一个指向构造函数的指针(Foo.prototype.constructor),而实例包含一个指向原型对象内部的指针.
不理解的可以根据下述应用公式理解
Foo.prototype.constructor.prototype == Foo.prototype//循环指向原型对象
true
Foo.prototype.constructor == Foo//原型对象指向constructor指向构造函数
true
f.__proto__ == Foo.prototype//实例对象中的__proto__指向原型对象
true
MyObject.prototype.name = "test";
//或者是用下面的方法
MyObject.prototype = {
name:"test",
test:"name"
};
字面量设置prototype,constructor对象也会被改变,动态性也会被影响(对象定义后对prototype改变不会影响已定义对象),上述例子的constructor为Object,不像构造函数一样自动将constructor指向构造函数
obj.hasOwnProperty("name");//判断对象是否存在自有属性,而非原型属性
获取原型当中可被for-in的属性
Object.keys(obj);//返回"name,test"
通过原型我们可以给已定义的类型创建属性和方法,当然这样通常是不背推荐使用的.
有时使用原型会带来一些不必要的麻烦,例如在声明一个数组,所有的实例都共享这一个数组,那么就不容易被修改.可以通过构造函数来声明属性
原型链
利用原型让一个引用类型继承自另一个引用类型,形成继承关系
将原型对象通过修改prototype来实现
function Foo(){
this.name = "test"
}
function Bar(){
}
Bar.prototype = new Foo();
这时Bar的实例的constructor就不在指向Bar指向了Foo,而且this.name不能正确的被继承
子类构造函数调用call方法,避免了应用对象变为共享
function Bar(){
Foo.call(this);
}
这样Bar具有了Foo的属性,但是constructor不能正确的指向对应的构造函数
结合上述的方式,得出正规的继承方式
function inheritPrototype(subType, superType){
var pro = object(superType.prototype);
pro.constructor = subType;
subType.prototype =pro;
}
inheritPrototype(Bar, Foo);
原型对象一定要避免引用
为什么要将constructor去进行切换?
为了让instance of正确的去执行.
函数
在递归的时候:
arguments.callee获取当前函数的指针,非严格模式下使用会报错,可以通过函数命名表达式来指定
var f = (function test(){
if( n < 1){
return 1;
}
return test() -1;
});
常见问题闭包中变量,下述例子当中i的值都变成了成了10, 因为 i引用的是同一个
func test(){
var result = new Array()
for (var i = 0; i < 10; i++){
restult[i] = function (){
return i;
}
}
return result;
}
//i按引用传递
为了避免i发生引用错误,for循环可以改写为如下
for(var i = 0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i)
}
//匿名函数立即执行然后返回闭包,这里的变量是按值 传递
在JS当中可以通过闭包访问局部变量来实现私有函数和私有变量
this变量
在之前的文章当中也简单介绍了一下this变量
var obj = {
name : "test",
test :function (){
return function (){
return this.name;
}
}
}
obj.test()();//输出The window
内部搜索这两个变量,其活动对象自动获取this,arguments的值,不会直接访问外部函数的这两个变量,这就是产生这个问题的原因
通过变量保存可以避免类似的问题发生
var obj = {
name : "test",
test :function (){
return function (){
return this.name;
}
}
}
浏览器当中的应用
窗口
//TODO://assure the property of screenLeft,resizeBy
screenLeft
screenTop
window.screenLeft = 80;
window.resizeTo(100, 100)
window.outerHeight
window.outerWidth
//以上返回浏览器本身的尺寸
window.innerHeight
window.innerWidth
//以上返回容器页面视图区大小,chrome中以上值返回相同的值
打开窗口
open函数进行窗口跳转
第二个参数指定跳转的窗口或者框架,如果不存在依赖于第三个参数的创建
key | desc |
---|---|
height | 新窗口高度小于100 |
width | 新窗口的宽度 |
location | 表示是否在浏览器窗口显示地址栏 |
toolbar | 表示是否在浏览器窗口中显示工具栏 |
scrollbars | 表示内容在视口中显示不下 |
top | y坐标相对原窗口 |
left | x坐标相对原窗口 |
window.open('https://www.baidu.com', 'testWindow', "height=400,width=400,top=10,left=10,resize=yes,location=no");
单线程执行
Javascript主要是单线程执行,一些延迟执行异步执行的操作,放入到Javascript的执行队列当中.
location 对象
key | desc |
---|---|
hash | 获取URL当中的(#号后的字符) 如:#content |
host | 服务器名称与端口号 |
port | 端口号 |
href | 当前页面的链接 |
pathName | 返回URI的目录或文件名 |
port | 端口号 |
protocol | URL当中的 |
search | 返回URL的查询字符串 |
我们可以重新请求查询,基于上述的参数.
window.location = "http://www.baidu.com"
location.href = "http://www.baidu.com"
navigator
key | desc |
---|---|
appCodeName | 常量:‘Mozilla’ |
platform | 浏览器所在的平台 |
plugins | 判断浏览器当中存在的插件 |
userAgent | 浏览器的用户代理字符串 |
mimeTypes | 在浏览器中注册的MIME数组 |
cookieEnabled | cookie是否可用 |
vendor | 浏览器生成方 |
screen
key | desc |
---|---|
availHeight | 返回屏幕的高度(不包括Windows任务栏) |
availWidth | 返回屏幕的宽度(不包括Windows任务栏) |
height | 返回屏幕的高度 |
width | 返回屏幕的宽度 |
history
key | desc |
---|---|
go | 跳转到最近访问的域名的页面 如:go(“www.baidu.com”) |
back | 向后跳转一页 |
forword | 向后跳转一页 |