js-13 JS的执行和编译过程的副本

ECMAScript

基于事件驱动并独立于平台的脚本/客户端语言

JS的执行和编译过程

解析器

  1. 没有执行,检查:提升,语法

  2. 提升:提升到一个临时空间内,

  3. 语法:语法不对,抛出错误,直接终止一切

提升:提升到一个临时空间内,

语法:语法不对,抛出错误,直接终止一切

编译器

  1. 执行

  2. 如果解析器没有遇到报错,并且把所有的提升都做好了,才会执行编译器

  3. 当编译器执行时,会先去临时空间中读取要操作的变量,直接使用

js-JSON

JSON

JSON是JavaScript Object Notation的缩写,它是一种数据交换格式。

格式

  1. 必须是字符
  2. 这个字符的格式与js中的数组和对象大体一致
  3. 但是如果与对象一致,对象的key必须加双引号
  4. 不允许出现没有意义的,号
  5. 不允许出现undefined,function,NaN

数据类型

  • number:和JavaScript的number完全一致;
  • boolean:就是JavaScript的truefalse
  • string:就是JavaScript的string
  • null:就是JavaScript的null
  • array:就是JavaScript的Array表示方式——[]
  • object:就是JavaScript的{ ... }表示方式。

序列化

var xiaoming = {
    name: '小明',
    age: 14,
    gender: true,
    height: 1.65,
    grade: null,
    'middle-school': '\"W3C\" Middle School',
    skills: ['JavaScript', 'Java', 'Python', 'Lisp']
};
var s = JSON.stringify(xiaoming);
console.log(s);
JSON.stringify(xiaoming, null, '  ');//要输出得好看一些,可以加上参数,按缩进输出:
  • JSON.stringify() 第二个参数用于控制如何筛选对象的键值,如果我们只想输出指定的属性,可以传入Array:
JSON.stringify(xiaoming, ['name', 'skills'], '  ');
  • 还可以传入一个函数,这样对象的每个键值对都会被函数先处理。
function convert(key, value) {
    if (typeof value === 'string') {
        return value.toUpperCase();
    }
    return value;
}

JSON.stringify(xiaoming, convert, '  ');
  • 对象定义一个toJSON()的方法,直接返回JSON应该序列化的数据:
var xiaoming = {
    name: '小明',
    age: 14,
    gender: true,
    height: 1.65,
    grade: null,
    'middle-school': '\"W3C\" Middle School',
    skills: ['JavaScript', 'Java', 'Python', 'Lisp'],
    toJSON: function () {
        return { // 只输出name和age,并且改变了key:
            'Name': this.name,
            'Age': this.age
        };
    }
};

JSON.stringify(xiaoming); // '{"Name":"小明","Age":14}'

反序列化

拿到一个JSON格式的字符串,我们直接用JSON.parse()把它变成一个JavaScript对象 。

JSON.parse('[1,2,3,true]'); // [1, 2, 3, true]
JSON.parse('{"name":"小明","age":14}'); // Object {name: '小明', age: 14}
JSON.parse('true'); // true
JSON.parse('123.45'); // 123.45

JSON.parse()还可以接收一个函数,用来转换解析出的属性:

var obj = JSON.parse('{"name":"小明","age":14}', function (key, value) {
    if (key === 'name') {
        return value + '同学';
    }
    return value;
});
console.log(JSON.stringify(obj)); // {name: '小明同学', age: 14}

js-BOM

BOM

浏览器对象模型

浏览器对象

window对象不但充当全局作用域,而且表示浏览器窗口。

window对象有innerWidthinnerHeight属性,可以获取浏览器窗口的内部宽度和高度。内部宽高是指除去菜单栏、工具栏、边框等占位元素后,用于显示网页的净宽高

console.log('window inner size: ' + window.innerWidth + ' x ' + window.innerHeight);

//window inner size: 1280 x 613

对应的,还有一个outerWidthouterHeight属性,可以获取浏览器窗口的整个宽高

navigator对象表示浏览器的信息

最常用的属性包括:

​ 浏览器名称

​ 浏览器版本

​ 浏览器设置的语言

​ 操作系统类型

​ 浏览器设定的User-Agent字符串

请注意,以上属性返回的均为字符串`

请注意navigator的信息可以很容易地被用户修改,所以JavaScript读取的值不一定是正确的。很多初学者为了针对不同浏览器编写不同的代码,喜欢用if判断浏览器版本,例如:

var width;
if (getIEVersion(navigator.userAgent) < 9) {
    width = document.body.clientWidth;
} else {
    width = window.innerWidth;
}

但这样既可能判断不准确,也很难维护代码。正确的方法是充分利用JavaScript对不存在属性返回undefined的特性,直接用短路运算符||计算:

var width = window.innerWidth || document.body.clientWidth;

screen

screen对象表示屏幕的信息

常用的属性有:

  • screen.width:屏幕宽度,以像素为单位;
  • screen.height:屏幕高度,以像素为单位;
  • screen.colorDepth:返回颜色位数,如8、16、24。
console.log('Screen size = ' + screen.width + ' x ' + screen.height);

// Screen size = 1920 x 1080

history//不推荐使用

history对象保存了浏览器的历史记录

JavaScript可以调用history对象的back()forward (),相当于用户点击了浏览器的“后退”或“前进”按钮。

这个对象属于历史遗留对象,对于现代Web页面来说,由于大量使用AJAX和页面交互,简单粗暴地调用history.back()可能会让用户感到非常愤怒。

新手开始设计Web页面时喜欢在登录页登录成功时调用history.back(),试图回到登录前的页面。这是一种错误的方法。

任何情况,你都不应该使用history这个对象了。

length

历史记录的个数

back()

back() 方法可加载历史列表中的前一个 URL(如果存在)。

调用该方法的效果等价于点击后退按钮或调用 history.go(-1)。

  • 语法

    history.back()
    
  • 实例

    history.back();//回退上一个页面
    
forward()

forward() 方法可加载历史列表中的下一个 URL。

调用该方法的效果等价于点击前进按钮或调用 history.go(1)。

  • 语法

    history.forward();
    
  • 实例

    history.forward();//前进一个页面
    
go()

go() 方法可加载历史列表中的某个具体的页面。 跳转指定的步数,负为退,正为进,0为刷新

  • 语法

    history.go(number|URL)
    
  • 实例

    window.history.go(-1);//回退上一个页面
    window.history.go(5);//前进5个页面
    

location

location对象表示当前页面的URL信息

例如一个完整的URL:http://www.example.com:8080/path/index.html?a=1&b=2#TOP

可以用location.href获取。要获得URL各个部分的值,可以这么写:

location.protocol; // 'http'
location.host; // 'www.example.com'
location.port; // '8080'
location.pathname; // '/path/index.html'
location.search; // '?a=1&b=2'
location.hash; // 'TOP'

要加载一个新页面,可以调用location.assign()。如果要重新加载当前页面,调用location.reload()方法非常方便。

if (confirm('重新加载当前页' + location.href + '?')) {
    location.reload();
} else {
    location.assign('/'); // 设置一个新的URL地址
}
href

href 属性是一个可读可写的字符串,可设置或返回当前显示的文档的完整 URL。

因此,我们可以通过为该属性设置新的 URL,使浏览器读取并显示新的 URL 的内容。

  • 语法

    location.href = URL
    
  • 实例

    console.log(location.href);//当前页面完整的URL
    

search 属性是一个可读可写的字符串,可设置或返回当前 URL 的查询部分(问号 ? 之后的部分)。

  • 语法

    location.search = path_from_questionmark
    
  • 实例

    console.log(location.href);//返回当前 URL 的查询部分(问号 ? 之后的部分)
    
hash

hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)

  • 语法

    location.hash = anchorname
    
  • 实例

    console.log(location.hash);// URL 的锚部分(从 # 号开始的部分)
    location.hash = "#3_2"//改变锚点#ID,可以到达指定位置
    
reload()

reload() 方法用于重新加载当前文档。

  • 语法

    location.reload(force)
    
  • 实例

    window.location.reload()//刷新页面
    
assign()

assign() 方法可加载一个新的文档。

  • 语法

    location.assign(URL)
    
  • 实例

     window.location.assign("http://www.w3school.com.cn")//重新加载新的网页
     window.location.assign("")//刷新页面
    

document

document对象表示当前页面。由于HTML在浏览器中以DOM形式表示为树形结构,document对象就是整个DOM树的根节点。

documenttitle属性是从HTML文档中的xxx读取的,但是可以动态改变:

document.title = '努力学习JavaScript!';
getElementById()

按ID获得一个DOM节点

getElementsByTagName()

按Tag名称获得一组DOM节点

可以获取当前页面的Cookie

Cookie是由服务器发送的key-value标示符。因为HTTP协议是无状态的,但是服务器要区分到底是哪个用户发过来的请求,就可以用Cookie来区分。当一个用户成功登录后,服务器发送一个Cookie给浏览器,例如user=ABC123XYZ(加密的字符串)...,此后,浏览器访问该网站时,会在请求头附上这个Cookie,服务器根据Cookie即可区分出用户。

Cookie还可以存储网站的一些设置,例如,页面显示的语言等等。

JavaScript可以通过document.cookie读取到当前页面的Cookie:

document.cookie; // 'v=123; remember=true; prefer=zh'

由于JavaScript能读取到页面的Cookie,而用户的登录信息通常也存在Cookie中,这就造成了巨大的安全隐患,这是因为在HTML页面中引入第三方的JavaScript代码是允许的:

<!-- 当前页面在wwwexample.com -->
<html>
    <head>
        <script src="http://www.foo.com/jquery.js"></script>
    </head>
    ...
</html>

如果引入的第三方的JavaScript中存在恶意代码,则www.foo.com网站将直接获取到www.example.com网站的用户登录信息。

为了解决这个问题,服务器在设置Cookie时可以使用httpOnly,设定了httpOnly的Cookie将不能被JavaScript读取。这个行为由浏览器实现,主流浏览器均支持httpOnly选项,IE从IE6 SP1开始支持。

为了确保安全,服务器端在设置Cookie时,应该始终坚持使用httpOnly

js-DOM

DOM

元素选择器

getElementById()

getElementById() 方法可返回对拥有指定 ID 的第一个对象的引用。

  • 语法

    document.getElementById(id)
    
  • 实例

    var c = document.body.children;
    

getElementsByClassName()

getElementsByClassName() 方法可返回带有指定标签名的对象的集合

  • 语法

    document.getElementsByTagName(classname)
    
  • 实例

    var aCont = document.getElementsByClassName("cont");//返回的是一个集合
    

getElementsByTagName()

getElementsByTagName() 方法可返回带有指定标签名的对象的集合

  • 语法

    document.getElementsByTagName(tagname)
    
  • 实例

    var aSpan = document.getElementsByTagName("span");//返回的是一个集合
    

getElementsByName()

getElementsByName() 方法可返回带有指定名称的对象的集合

  • 语法

    document.getElementsByName(name)
    
  • 实例

    var x=document.getElementsByName("myInput");//返回的是一个集合
    

querySelector()

querySelector() 方法返回文档中匹配指定 CSS 选择器的一个元素

  • 语法

    elementList = document.querySelectorAll(selector);
    
  • 实例

    var ele = document.querySelector("#box");
    var ele = document.querySelector(".cont");
    var ele = document.querySelector("span");
    var ele = document.querySelector(".msg h2");
    var ele = document.querySelector(".msg>h2");
    var ele = document.querySelector("input[name=pass]");
    

querySelectorAll()

querySelectorAll() 方法返回文档中匹配指定 CSS 选择器的所有元素,返回NodeList对象。

  • 语法

    elementList = document.querySelectorAll(selectors);
    
  • 实例

    var ele = document.querySelectorAll("#box");
    var ele = document.querySelectorAll(".cont");
    var ele = document.querySelectorAll("span");
    var ele = document.querySelectorAll(".msg h2");
    var ele = document.querySelectorAll(".msg>h2");
    var ele = document.querySelectorAll("input[name=pass]");
    var ele = document.querySelectorAll("span,p,input,div,#box,.cont")
    

关系选择器

.children

children 属性返回元素的子元素的集合,是一个 HTMLCollection 对象。

  • 语法

    element.children
    
  • 实例

    var c = document.body.children;
    

.parentNode

parentNode 属性以 Node 对象的形式返回指定节点的父节点。

如果指定节点没有父节点,则返回 null。

  • 语法

    node.parentNode
    
  • 实例

    document.getElementById("item1").parentNode;
    

.firstElementChild

firstElementChild 返回指定节点的第一个子元素节点

  • 语法

    var last = oXbox.lastElementChild;
    
  • 实例

    var last = oXbox.lastElementChild;
    

.lastElementChild

lastElementChild 返回指定节点的最后一个子元素节点

  • 语法

    var last = oXbox.lastElementChild;
    
  • 实例

    var last = oXbox.lastElementChild;
    

.previousElementSibling

previousElementSibling 属性返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)。

  • 语法

    node.previousElementSibling
    
  • 实例

    var x = document.getElementById("item2").previousElementSibling.innerHTML;
    

.nextElementSibling

nextElementSibling 属性返回指定元素之后的下一个兄弟元素(相同节点树层中的下一个元素节点)

  • 语法

    node.nextElementSibling
    
  • 实例

    var x = document.getElementById("item1").nextElementSibling.innerHTML;
    

其他节点选择器

.childNodes

Node.childNodes 返回包含指定节点的子节点的集合,该集合为即时更新的集合(live collection)

  • 语法

    var ndList = elementNodeReference.childNodes; 
    
  • 实例

    var child = oxbox.childNodes;
    console.log(child);
    console.log(child[0]);
    console.log(child[1]);
    console.log(child[2]);
    console.log(child[3]);
    

.firstChild

firstChild 属性返回指定节点的首个子节点,以 Node 对象。

  • 语法

    var childNode = node.firstChild;
    
  • 实例

    document.firstChild;//<!DOCTYPE html>(是一个对象)
    

.lastChild

lastChild 属性返回指定节点的最后一个子节点,以 Node 对象。

  • 语法

    node.lastChild;
    
  • 实例

    document.firstChild;//<html></html>
    

.previousSibling

返回当前节点的前一个兄弟节点,没有则返回null.

  • 语法

    previousNode = node.previousSibling
    
  • 实例

    // <a><b1 id="b1"/><b2 id="b2"/></a>
    alert(document.getElementById("b1").previousSibling); // null
    alert(document.getElementById("b2").previousSibling.id); // "b1"
    

.nextSibling

Node.nextSibling 是一个只读属性,返回其父节点的 childNodes 列表中紧跟在其后面的节点,如果指定的节点为最后一个节点,则返回 null

  • 语法

    nextNode = node.nextSibling
    
  • 实例

    // <a><b1 id="b1"/><b2 id="b2"/></a>
    alert(document.getElementById("b1").nextSibling.id); // "b2"
    alert(document.getElementById("b2").nextSibling); // null
    

.attributes

Element.attributes 属性返回该元素所有属性节点的一个实时集合。该集合是一个 NamedNodeMap 对象,不是一个数组,所以它没有 数组 的方法,其包含的 属性 节点的索引顺序随浏览器不同而不同。更确切地说,attributes 是字符串形式的名/值对,每一对名/值对对应一个属性节点。

  • 语法

    var attr = element.attributes;
    
  • 实例

    var obox = document.querySelector(".box");
    console.log(obox.attributes);
    console.log(obox.attributes[0]);
    console.log(obox.attributes[1]);
    console.log(obox.attributes[2]);
    console.log(obox.attributes[3]);
    console.log(obox.attributes[3].abc);
    console.log(obox.attributes[4]);
    

元素的操作

document.createElement()

Document.createElement() 方法创建由tagName 指定的HTML元素,或一个HTMLUnknownElement,如果tagName不被识别。

  • 语法

    let element = document.createElement(tagName[, options]);
    
  • 返回值

    新的元素[Element]
    
    • element 是创建的Element对象。
    • tagName 指定将要创建的元素类型的字符串。创建的element的nodeName会被初始化为tagName的值。该方法不接受带条件的元素名字(例如: html:a)。
    • options 是一个可选的 ElementCreationOptions 对象. 如果这个对象被定义并赋予了一个 is 特性,则创建的element的 is 属性会被初始化为这个特性的值. 如果这个对象没有 is 特性,则值为空.
  • 实例

    var mydiv = document.createElement("div");//创建了一个div元素节点
    

childNode.remove()

ChildNode.remove() 方法,把对象从它所属的 DOM 树中删除。

  • 语法

    node.remove();
    
  • 实例

    var el = document.getElementById('div-02');
    el.remove();//"id为'div-02"的元素被删掉了
    

    当你遍历一个父节点的子节点并进行删除操作时,要注意,children属性是一个只读属性,并且它在子节点变化时会实时更新。删除多个节点时,要注意children属性时刻都在变化。

node.removeChild()

Node.removeChild() 方法从DOM中删除一个子节点。返回删除的节点。

  • 语法

    let oldChild = node.removeChild(child);
    //OR
    element.removeChild(child);
    
  • 返回值

    注意到删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置。
    因此,你还可以把这个节点重新添加回文档中,当然,实现要用另外一个变量取得它的返回值。

  • 实例

    // 拿到待删除节点:
    var self = document.getElementById('to-be-removed');
    // 拿到父节点:
    var parent = self.parentElement;
    // 删除:
    var removed = parent.removeChild(self);
    console.log(removed === self )// true
    

属性的操作

setAttribute()

setAttribute() 方法添加指定的属性,并为其赋指定的值。

如果这个指定的属性已存在,则仅设置/更改值。

  • 语法

    element.setAttribute(attributename,attributevalue)
    
  • 实例

    document.getElementsByTagName("INPUT")[0].setAttribute("type","button");
    

getAttribute()

getAttribute() 方法返回指定属性名的属性值。

  • 语法

    element.getAttribute(attributename)
    
  • 实例

    document.getElementsByTagName("a")[0].getAttribute("target");//_blank
    

removeAttribute()

removeAttribute() 方法删除指定的属性。

此方法与 removeAttributeNode() 方法的差异是:removeAttributeNode() 方法删除指定的 Attr 对象,而此方法删除具有指定名称的属性。结果是相同的。同时此方法不返回值,而 removeAttributeNode() 方法返回被删除的属性,以 Attr 对象的形式

  • 语法

    element.getAttribute(attributename)
    
  • 实例

    document.getElementsByTagName("H1")[0].removeAttribute("style");
    

内置属性

可见

  • 作为对象操作(点语法,中括号语法)

    var obox = document.getElementsByClassName("box")[0];
    var a = document.getElementsByTagName("a")[0];
    var img = document.getElementsByTagName("img")[0];
    obox.className;
    obox["title"];
    obox.id;
    a.href;
    img.src;
    img["alt"];
    
  • Attribute系列:set,get,remove

    console.log(obox.getAttribute("title"))//可获得内置可见属性
    obox.setAttribute("title","123123132")//可设置内置可见属性
    obox.removeAttribute("title")//可删除内置可见属性
    

不可见

  • 作为对象操作(点语法,中括号语法)

    innerHTML,innerText,tagName
    console.log(obox.innerHTML)
    console.log(obox.innerText)
    console.log(obox.tagName)
    obox.tagName = "SPAN";//不可更改
    

自定义属性

可见

  • Attribute系列:set,get,remove

    console.log(obox.abc)
    console.log(obox.href)
    console.log(obox.getAttribute("abc"))//可以获得自定义可见属性的值
    console.log(obox.getAttribute("href"))
    obox.setAttribute("qwe","hahahahah")//可以设置或修改自定义可见属性的值
    obox.setAttribute("abc","world")
    obox.removeAttribute("abc")//可以删除自定义可见属性的值
    obox.removeAttribute("href")
    

不可见

  • 作为对象操作(点语法,中括号语法)

    obox.aaa = "bbb"
    console.log(obox.aaa);//bbb
    

样式的操作

element.style

由.style设置的所有样式都会以行内样式的形式体现

获取的也是行内样式

  • 语法

    element.style.attribute =  ""
    
  • 实例

    obox.style.width = 20 + "px";
    

getComputedStyle()

Window.getComputedStyle()方法返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有CSS属性的值。 私有的CSS属性值可以通过对象提供的API或通过简单地使用CSS属性名称进行索引来访问。

注意:该属性只能获取属性不能设置属性

  • 语法

    let style = window.getComputedStyle(element, [pseudoElt]);//第二个参数是fasle,为true的情况下查看的是元素的伪类或者伪元素
    
  • 返回值

    返回的style是一个实时的CSSStyleDeclaration对象,当元素的样式更改时,它会自动更新本身。
    
  • 实例

element.currentStyle

Element.currentStyle 是一个与 window.getComputedStyle方法功能相同的属性。这个属性实现在旧版本的IE浏览器(IE8及以下)中。

注意:该属性只能获取属性不能设置属性

  • 语法

    element.currentStyle.attribute
    
  • 实例

    obox.currentStyle.width;
    

兼容性获取样式方法

function getStyle(ele,attr){
    if(ele.currentStyle){//判断获取到的是不是true,那么就执行IE的currentStyle,如果是undefined那么就是false,那就执行getComputedStyle()
        return ele.currentStyle[attr];//IE8及以下支持
    }else{
        return getComputedStyle(ele,false)[attr];//其他正常浏览器支持
    }
}

尺寸类样式的获取

offsetWidth

HTMLElement.offsetWidth 是一个只读属性,返回一个元素的布局宽度。一个典型的(译者注:各浏览器的offsetWidth可能有所不同)offsetWidth是测量包含元素的边框(border)、水平线上的内边距(padding)、竖直方向滚动条(scrollbar)(如果存在的话)、以及CSS设置的宽度(width)的值。

content+padding+border

  • 语法

    var offsetWidth =element.offsetWidth;
    

    这个属性将会 round(四舍五入)为一个整数。如果你想要一个fractional(小数)值,请使用element.getBoundingClientRect()

  • 分类

    1. 假如元素无padding无滚动无border

      offsetWidth = clientWidth = style.width
      
    2. 假如元素有padding无滚动有border

      offsetWidth = style.width + style.padding*2 + border宽度*2
      offsetWidth = clientWidth + border宽度*2
      
    3. 假如元素有padding有滚动,有border,且滚动是显示的

      offsetWidth = style.width + style.padding*2 + (border-width)*2
      offsetWidth = clientWidth + 滚轴宽度 + border宽度*2
      

      offsetHeight同理

  • 实例

    var wid = obox.offsetWidth;//返回一个整数数值
    

    Image:Dimensions-offset.png

offsetHeight

HTMLElement.offsetHeight 是一个只读属性,它返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。**(content+padding+border)**

通常,元素的offsetHeight是一种元素CSS高度的衡量标准,包括元素的边框、内边距和元素的水平滚动条(如果存在且渲染的话),不包含:before或:after等伪类元素的高度。

对于文档的body对象,它包括代替元素的CSS高度线性总含量高。浮动元素的向下延伸内容高度是被忽略的。

如果元素被隐藏(例如 元素或者元素的祖先之一的元素的style.display被设置为none),则返回0

  • 语法

    var intElemOffsetHeight = document.getElementById(id_attribute_value).offsetHeight;
    
  • 实例

    var hei = obox.offsetHeight;//返回一个整数数值
    

    Image:Dimensions-offset.png

    上面的图片中显示了scollbar和窗口高度的offsetHeight.但是不能滚动的元素可能会有一个很大的高度值,大于可以看见的内容。这些元素原则上是被包含在滚动元素之中的。所以,这些不能滚动的元素可能会因为scrollTop的值会被完全隐藏或者部分隐藏;

clientWidth

clientWeight是一个只读属性。尺寸范围为:padding+content

内联元素以及没有 CSS 样式的元素的 **clientWidth** 属性值为 0。**Element.clientWidth** 属性表示元素的内部宽度,以像素计。该属性包括内边距,但不包括垂直滚动条(如果有)、边框和外边距。

  • 语法

    var intElemClientWidth = element.clientWidth;
    //intElemClientWidth 是一个整数,表示元素的 clientWidth。
    
  • 分类

    1. 假如元素无padding无滚动

      clientWidth = style.width
      
    2. 假如元素有padding无滚动

      clientWidth = style.width + style.padding*2
      
    3. 假如元素有padding有滚动,且滚动是显示的

      clientWidth = style.width + style.padding*2 - 滚动轴宽度
      

      clientHeight同理

  • 实例

    var cw = obox.clientWidth;//返回一个整数数值
    

    Image:Dimensions-client.png

clientHeight

clientHeight是一个只读属性。尺寸范围为:padding+content

  • 语法

    var intElemClientHeight = element.clientHeight;
    //intElemClientHeight 是一个整数,表示元素的 clientHeight。
    
  • 实例

    var ch = obox.clientHeight;//返回一个整数数值
    

    Image:Dimensions-client.png

offsetTop

HTMLElement.offsetTop 为只读属性,它返回当前元素相对于其 offsetParent 元素的顶部内边距的距离。

相对于页面或包含块偏移的位置

  • 语法

    topPos = element.offsetTop;
    
  • 实例

    var d = document.getElementById("div1");
    var topPos = d.offsetTop;
     
    if (topPos > 10) {
      // div1 距离它的 offsetParent 元素的顶部的距离大于 10 px
    }
    

offsetLeft

HTMLElement.offsetLeft 为只读属性,它返回当前元素相对于其 offsetParent 元素的左边内边距的距离。

相对于页面或包含块偏移的位置

  • 语法

    leftPos = element.offsetLeft;
    
  • 实例

    var d = document.getElementById("div1");
    var topLeft = d.offsetLeft;
     
    if (topLeft > 10) {
      // div1 距离它的 offsetParent 元素的顶部的距离大于 10 px
    }
    

以上属性只能获取不能设置

scrollTop

Element.scrollTop 属性可以获取或设置一个元素的内容垂直滚动的像素数。

一个元素的 scrollTop 值是这个元素的顶部到视口可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的 scrollTop 值为0。

  • 语法

    // 获得滚动的像素数
    var  intElemScrollTop = someElement.scrollTop;
    
    // 设置滚动的距离
    element.scrollTop = intValue;
    
  • 实例

    document.onclick = function(){
        // console.log(obox.scrollTop);
        obox.scrollTop = 666;
    }
    

    Image:scrollTop.png

scrolLeft

Element.scrollLeft 属性可以读取或设置元素滚动条到元素左边的距离。

注意如果这个元素的内容排列方向(direction) 是rtl (right-to-left) ,那么滚动条会位于最右侧(内容开始处),并且scrollLeft值为0。此时,当你从右到左拖动滚动条时,scrollLeft会从0变为负数(这个特性在chrome浏览器中不存在)。

  • 语法

    //获取滚动条到元素左边的距离
    var sLeft = element.scrollLeft;
    
    //设置滚动条滚动了多少像素
    element.scrollLeft = 10;
    

    scrollLeft 可以是任意整数,然而:

    • 如果元素不能滚动(比如:元素没有溢出),那么scrollLeft 的值是0。
    • 如果给scrollLeft 设置的值小于0,那么scrollLeft 的值将变为0。
    • 如果给scrollLeft 设置的值大于元素内容最大宽度,那么scrollLeft 的值将被设为元素最大宽度。
  • 实例

    document.onclick = function(){
        // console.log(obox.scrollLeft);
        obox.scrollLeft = 666;
    }
    

    Image:Dimensions-client.png

Node类型的操作

DOM将任何HTML和XML文档描绘成一个由多层节点构成的结构。有几个不同类型的节点,节点又有各自的特点、数据和方法,同时节点之间存在着某种关系,这些关系构成层次。

DOM内的节点分为四种:元素,文本,注释和属性

除 IE 之外,在其他所有浏览器中都可以访问到Node类型。
JavaScript 中的所有节点类型都继承 Node 类型,因此所有节点类型都共享着相同的基本属性和方法。

12种节点类型

Node.ELEMENT_NODE(1);(常用) //元素节点
Node.ATTRIBUTE_NODE(2); //属性节点
Node.TEXT_NODE(3);(常用) //文本节点
Node.CDATA_SECTION_NODE(4);
Node.ENTITY_REFERENCE_NODE(5)
Node.ENTITY_NODE(6) ;
Node.PROCESSING_INSTRUCTION_NODE(7);
Node.COMMENT_NODE(8) //注释节点
Node.DOCUMENT_NODE(9);
Node.DOCUMENT_TYPE_NODE(10);
Node.DOCUMEN_FRAGME_NODE(11);
Node.NOTATION_NODE(12)

nodeType 属性

nodeType 属性返回以数字值返回指定节点的节点类型。

如果节点是元素节点,则 nodeType 属性将返回 1。

如果节点是属性节点,则 nodeType 属性将返回 2。

  • 语法

    node.nodeName
    
  • 实例

    document.body.nodeType;//1
    

nodeName属性

nodeName 属性指定节点的节点名称。

如果节点是元素节点,则 nodeName 属性返回标签名。

如果节点是属性节点,则 nodeName 属性返回属性的名称。

对于其他节点类型,nodeName 属性返回不同节点类型的不同名称。

  • 语法

    node.nodeName
    
  • 实例

    document.body.nodeName;//BODY
    

nodeValue属性

nodeValue 属性设置或返回指定节点的节点值。

注释:如果您希望返回元素的文本,请记住文本始终位于文本节点中,并且您必须返回文本节点的值(element.childNodes[0].nodeValue)。

提示:nodeValue 属性的替代选择是 textContent 属性。

更改文本节点的nodeValue属性值即可改变文本节点的内容

  • 语法

    node.nodeValue = value;
    
  • 实例

    var txt = document.createTextNode("123");
    txt.nodeValue = "456";
    console.log(txt)//内容变成了456;
    

    ```

操作DOM

由于HTML文档被浏览器解析后就是一棵DOM树,要改变HTML的结构,就需要通过JavaScript来操作DOM。

始终记住DOM是一个树形结构。操作一个DOM节点实际上就是这么几个操作:

  • 更新:更新该DOM节点的内容,相当于更新了该DOM节点表示的HTML的内容;
  • 遍历:遍历该DOM节点下的子节点,以便进行进一步操作;
  • 添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点;
  • 删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及它包含的所有子节点。

在操作一个DOM节点前,我们需要通过各种方式先拿到这个DOM节点

第一种方法或者最常用的方法是:

  • document.getElementById()

  • document.getElementsByTagName()

  • CSS选择器document.getElementsByClassName()

由于ID在HTML文档中是唯一的,所以document.getElementById()可以直接定位唯一的一个DOM节点。document.getElementsByTagName()document.getElementsByClassName()总是返回一组DOM节点。要精确地选择DOM,可以先定位父节点,再从父节点开始选择,以缩小范围。

​```js
// 返回ID为’test’的节点:
var test = document.getElementById(‘test’);

// 先定位ID为’test-table’的节点,再返回其内部所有tr节点:
var trs = document.getElementById(‘test-table’).getElementsByTagName(‘tr’);

// 先定位ID为’test-div’的节点,再返回其内部所有class包含red的节点:
var reds = document.getElementById(‘test-div’).getElementsByClassName(‘red’);

// 获取节点test下的所有直属子节点:
var cs = test.children;

// 获取节点test下第一个、最后一个子节点:
var first = test.firstElementChild;
var last = test.lastElementChild;




**第二种方法**是使用`querySelector()`和`querySelectorAll()`,需要了解selector语法,然后使用条件来获取节点,更加方便:

// 通过querySelector获取ID为q1的节点:
var q1 = document.querySelector(‘#q1’);

// 通过querySelectorAll获取q1节点内的符合条件的所有节点:
var ps = q1.querySelectorAll(‘div.highlighted > p’);


注意:低版本的IE<8不支持`querySelector`和`querySelectorAll`。IE8仅有限支持。

严格地讲,我们这里的DOM节点是指`Element`,但是DOM节点实际上是`Node`,在HTML中,`Node`包括`Element`、`Comment`、`CDATA_SECTION`等很多种,以及根节点`Document`类型,但是,绝大多数时候我们只关心`Element`,也就是实际控制页面结构的`Node`,其他类型的`Node`忽略即可。根节点`Document`已经自动绑定为全局变量`document`。

#### 更新DOM

#####  innerHTML 

>  可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树 

```js
// 获取<p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置文本为abc:
p.innerHTML = 'ABC'; // <p id="p-id">ABC</p>
// 设置HTML:
p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
// <p>...</p>的内部结构已修改

innerHTML时要注意,是否需要写入HTML。如果写入的字符串是通过网络拿到了,要注意对字符编码来避免XSS攻击。

通过innerHTML数组遍历实现多行多列的商品列表: 商品列表.html

innerText || textContent

可以自动对字符串进行HTML编码,保证无法设置任何HTML标签

// 获取<p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置文本:
p.innerText = '<script>alert("Hi")</script>';
// HTML被自动编码,无法设置一个<script>节点:
// <p id="p-id">&lt;script&gt;alert("Hi")&lt;/script&gt;</p>

两者的区别在于读取属性时,innerText不返回隐藏元素的文本,而textContent返回所有文本。另外注意IE<9不支持textContent

修改CSS

DOM节点的style属性对应所有的CSS,可以直接获取或设置

因为CSS允许font-size这样的名称,但它并非JavaScript有效的属性名,所以需要在JavaScript中改写为驼峰式命名fontSize

// 获取<p id="p-id">...</p>
var p = document.getElementById('p-id');
// 设置CSS:
p.style.color = '#ff0000';
p.style.fontSize = '20px';
p.style.paddingTop = '2em';

插入DOM

appendChild()

把一个子节点添加到父节点的最后一个子节点

<!-- HTML结构 -->
<p id="js">JavaScript</p>
<div id="list">
    <p id="java">Java</p>
    <p id="python">Python</p>
    <p id="scheme">Scheme</p>
</div>
var
    js = document.getElementById('js'),
    list = document.getElementById('list');
list.appendChild(js);

现在,HTML结构变成了这样:

<!-- HTML结构 -->
<div id="list">
    <p id="java">Java</p>
    <p id="python">Python</p>
    <p id="scheme">Scheme</p>
    <p id="js">JavaScript</p>
</div>

因为我们插入的js节点已经存在于当前的文档树,因此这个节点首先会从原先的位置删除,再插入到新的位置。

insertBefore()

把子节点插入到指定的位置

  • 语法

    document.getElementById("myList").insertBefore(newItem,existingItem);
    
  • 实例

    var
        list = document.getElementById('list'),
        ref = document.getElementById('python'),
        haskell = document.createElement('p');
    haskell.id = 'haskell';
    haskell.innerText = 'Haskell';
    list.insertBefore(haskell, ref);//把haskell节点 放在ref节点之前
    

js-JavaScript对象Math

aJavaScript对象

Math对象

Math方法
Math.round(3.6);

四舍五入

Math.random();

​ //返回一个大于等于0到小于1的随机数

Math.max(a,b)

返回较大的值

Math.min(a,b);

返回较小的值

Math.abs(num)

返回绝对值

Math.ceil(3.6)

向上取整

Math.floor(3.6)

向下取整

Math.pow(x,y)

x的y次方

Math.sqrt(num)

开平方

Math.sin(x)

x的正弦值,返回值在-1到1之间

Math.cos(x)

x的余弦值,返回值在-1到1之间

方法 描述
abs(x) 返回数的绝对值。
acos(x) 返回数的反余弦值。
asin(x) 返回数的反正弦值。
atan(x) 以介于 -PI/2 与 PI/2 弧度之间的数值来返回 x 的反正切值。
atan2(y,x) 返回从 x 轴到点 (x,y) 的角度(介于 -PI/2 与 PI/2 弧度之间)。
ceil(x) 对数进行上舍入。
cos(x) 返回数的余弦。
exp(x) 返回 e 的指数。
floor(x) 对数进行下舍入。
log(x) 返回数的自然对数(底为e)。
max(x,y) 返回 x 和 y 中的最高值。
min(x,y) 返回 x 和 y 中的最低值。
pow(x,y) 返回 x 的 y 次幂。
random() 返回 0 ~ 1 之间的随机数。
round(x) 把数四舍五入为最接近的整数。
sin(x) 返回数的正弦。
sqrt(x) 返回数的平方根。
tan(x) 返回角的正切。
toSource() 返回该对象的源代码。
valueOf() 返回 Math 对象的原始值。
Math属性
Math.PI

PI 属性就是 π,即圆的周长和它的直径之比。这个值近似为 3.141592653589793。

属性 描述
E 返回算术常量 e,即自然对数的底数(约等于2.718)。
LN2 返回 2 的自然对数(约等于0.693)。
LN10 返回 10 的自然对数(约等于2.302)。
LOG2E 返回以 2 为底的 e 的对数(约等于 1.414)。
LOG10E 返回以 10 为底的 e 的对数(约等于0.434)。
PI 返回圆周率(约等于3.14159)。
SQRT1_2 返回返回 2 的平方根的倒数(约等于 0.707)。
SQRT2 返回 2 的平方根(约等于 1.414)。

Date对象

Date 对象用于处理日期和时间。

创建 Date 对象的语法
var myDate = new Date();

注释:Date 对象会自动把当前日期和时间保存为其初始值。

设置Date对象的语法
  • 创建日期对象时设置

    • 单个参数:参数为字符,没有设置的部分为0,超出上限就:Invalid Date

      var d = new Date("2008.08.08 8:8:8");
      var d = new Date("2008.08.08");
      var d = new Date("2008.13.08");
      var d = new Date("2008/08/08");
      var d = new Date("2008-08-08");
      var d = new Date("2008,08,08");
      var d = new Date("2008 08 08");
      console.log(d);
      
    • 多个参数:参数为数值,月的范围是0~11,没有设置的部分为0,超出上限,向前进1

      var d = new Date(2008,8,8,8,8,8);
      var d = new Date(2008,8,8);
      var d = new Date(2008,12,33);//2009-2-02,33号自动进1个月,12(超过了0-11反胃)自动进1个年,相当于进了2个月
      console.log(d);
      
  • 创建日期对象后

    • 使用set系列方法单独设置:没有设置的部分,以当前日期为准,超出上限,向前进1

      var d = new Date();
      d.setFullYear(2008);
      d.setMonth(12);     //0~11
      d.setDate(56);
      //不能设置星期几,因为星期几是自动计算得出的
      d.setHours(35);
      d.setMinutes(78);
      d.setSeconds(86);
      
      d.setMilliseconds(666);
      console.log(d)
      console.log(d.getMilliseconds());
      
    • 使用设置时间戳

      var d = new Date();
      d.setTime(1000000000000);
      console.log(d);
      
属性
属性 描述
constructor 返回对创建此对象的 Date 函数的引用。
prototype 使您有能力向对象添加属性和方法。
方法
方法 描述
Date() 返回当日的日期和时间。
getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31)。
getDay() 从 Date 对象返回一周中的某一天 (0 ~ 6)。
getMonth() 从 Date 对象返回月份 (0 ~ 11)。
getFullYear() 从 Date 对象以四位数字返回年份。
getYear() 请使用 getFullYear() 方法代替。
getHours() 返回 Date 对象的小时 (0 ~ 23)。
getMinutes() 返回 Date 对象的分钟 (0 ~ 59)。
getSeconds() 返回 Date 对象的秒数 (0 ~ 59)。
getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)。
getTime() 返回 1970 年 1 月 1 日至今的毫秒数。
getTimezoneOffset() 返回本地时间与格林威治标准时间 (GMT) 的分钟差。
getUTCDate() 根据世界时从 Date 对象返回月中的一天 (1 ~ 31)。
getUTCDay() 根据世界时从 Date 对象返回周中的一天 (0 ~ 6)。
getUTCMonth() 根据世界时从 Date 对象返回月份 (0 ~ 11)。
getUTCFullYear() 根据世界时从 Date 对象返回四位数的年份。
getUTCHours() 根据世界时返回 Date 对象的小时 (0 ~ 23)。
getUTCMinutes() 根据世界时返回 Date 对象的分钟 (0 ~ 59)。
getUTCSeconds() 根据世界时返回 Date 对象的秒钟 (0 ~ 59)。
getUTCMilliseconds() 根据世界时返回 Date 对象的毫秒(0 ~ 999)。
parse() 返回1970年1月1日午夜到指定日期(字符串)的毫秒数。
setDate() 设置 Date 对象中月的某一天 (1 ~ 31)。
setMonth() 设置 Date 对象中月份 (0 ~ 11)。
setFullYear() 设置 Date 对象中的年份(四位数字)。
setYear() 请使用 setFullYear() 方法代替。
setHours() 设置 Date 对象中的小时 (0 ~ 23)。
setMinutes() 设置 Date 对象中的分钟 (0 ~ 59)。
setSeconds() 设置 Date 对象中的秒钟 (0 ~ 59)。
setMilliseconds() 设置 Date 对象中的毫秒 (0 ~ 999)。
setTime() 以毫秒设置 Date 对象。
setUTCDate() 根据世界时设置 Date 对象中月份的一天 (1 ~ 31)。
setUTCMonth() 根据世界时设置 Date 对象中的月份 (0 ~ 11)。
setUTCFullYear() 根据世界时设置 Date 对象中的年份(四位数字)。
setUTCHours() 根据世界时设置 Date 对象中的小时 (0 ~ 23)。
setUTCMinutes() 根据世界时设置 Date 对象中的分钟 (0 ~ 59)。
setUTCSeconds() 根据世界时设置 Date 对象中的秒钟 (0 ~ 59)。
setUTCMilliseconds() 根据世界时设置 Date 对象中的毫秒 (0 ~ 999)。
toSource() 返回该对象的源代码。
toString() 把 Date 对象转换为字符串。
toTimeString() 把 Date 对象的时间部分转换为字符串。
toDateString() 把 Date 对象的日期部分转换为字符串。
toGMTString() 请使用 toUTCString() 方法代替。
toUTCString() 根据世界时,把 Date 对象转换为字符串。
toLocaleString() 根据本地时间格式,把 Date 对象转换为字符串。
toLocaleTimeString() 根据本地时间格式,把 Date 对象的时间部分转换为字符串。
toLocaleDateString() 根据本地时间格式,把 Date 对象的日期部分转换为字符串。
UTC() 根据世界时返回 1970 年 1 月 1 日 到指定日期的毫秒数。
valueOf() 返回 Date 对象的原始值。

null

null 特指对象的值未设置。它是 JavaScript 基本类型 之一。

语法

null

描述

null 是一个字面量,不像 undefined,它不是全局对象的一个属性。null 是表示缺少的标识,指示变量未指向任何对象。把 null 作为尚未创建的对象,也许更好理解。在 API 中,null 常在返回类型应是一个对象,但没有关联的值的地方使用。

// foo 不存在,它从来没有被定义过或者是初始化过:
foo;
"ReferenceError: foo is not defined"

// foo 现在已经是知存在的,但是它没有类型或者是值:
var foo = null; 
foo;
null

nullundefined 的不同点:

当检测 nullundefined 时,注意相等(==)与全等(===)两个操作符的区别 ,前者会执行类型转换:

typeof null        // "object" (因为一些以前的原因而不是'null')
typeof undefined   // "undefined"
null === undefined // false
null  == undefined // true
null === null // true
null == null // true
!null //true
isNaN(1 + null) // false
isNaN(1 + undefined) // true

js-引用数据类型

引用数据类型

对象Object

  • 对象的概念:对象事物的描述
  • 对象的语法(组成,本质):属性名和属性值,键值对
var people = {
    name:"admin",
    age:18,
    sex:"男",
    like:"ball",
    sayhello:function(){
        console.log("我叫"+people.name+"今年"+people.age+"性别"+people.sex+"爱好"+people.like)
    }
}

people.sayhello();
  • 对象的作用(意义):储存数据,编程
  • 对象中的值的叫法和操作:对象里的变量叫属性,对象里的函数叫方法

操作

  • .语法:对象.属性(方法名),当属性名和方法名确定
obj1.name = "hello";
console.log(obj1.name);
  • [ ]语法,当属性名和方法名不确定
var obj1 = {};
var str = "age";
console.log(obj1[str]);
obj1[str] = "男";
console.log(obj1["name"]);
console.log(obj1);

函数Function

函数是由事件驱动的或者当他被调用时可执行的可重复使用的代码块。

函数的好处

  1. 重复使用----空调不可能是一次性的,可以重复使用
  2. 忽略细节----会用空调不一定会生产空调
  3. 选择执行----夏冬使用,春秋不用

函数的定义

  1. 声明式

    function 为声明函数的关键字,指出这是一个函数
    fn 是函数名,类似于永来存储函数的变量
    () 为函数的参数,多个参数用 , 隔开
    {} 放置函数体,用于执行时,所要编译的代码段
  2. 赋值式

    var fn = function(){};
    

    ​ 这种方式下,虽然这个函数没有名字,但是这个函数赋值给了fn,因此通过变量fn也能调用到这个函数,以上两种声明方式等价都可以使用,函数名/变量名+() 调用执行。

函数的调用

  1. 自身执行

    • 函数名(),任何情况下,只要函数名()了,函数立即执行
  2. 事件调用

    • 元素.事件 = 函数名

      box.onclick = fn;
      
    • 元素.事件 = 函数的内容

      box.onclick = function(){...}
      

函数写法的分类

  1. 有名函数

    • 声明式创建的函数:function fn(){}
  2. 无名函数

    注意:无名函数不允许直接存在,必须作为值使用,是一种表达式,或值

    function(){
      console.log(1)
    }
    

    使用:

    1. 作为赋值式创建函数的值var fn = function(){}
    2. 事件处理函数,直接作为事件执行函数存在:元素.事件 = function(){}
    3. 回调函数:作为函数的参数存在,也是一个值:
    function fn(a){a(1)}; fn(function(b){...});
    
    1. 作为匿名函数的函数体存在:**(function(){})()**
  3. 匿名函数

    (function(){})()
    

    特点:自动执行

函数的参数

  1. 形参

    1. 定义时的参数叫形参,
    2. 形参保存了实参
    3. 形参是变量
    4. 形参相当于赋值元素运算符=号,左边的内容
  2. 实参

    1. 执行时的参数叫实参
    2. 实参被形参接收
    3. 实参是值
    4. 实参相当于赋值元素运算符=号,右边的内容
  3. 参数的个数

    • 可以传无限个

    • 关系:实参和形参,数量一致,按照顺序一一对应

    • 形参多,多出来的形参是undefined

    • 实参多,多出来的实参,被传到arguments(实参全部都会比传到arguments)

  4. 参数的类型

    • 任何类型

函数的回调

​ 回调函数是一段可执行的代码段,它作为一个参数传递给其他的代码,其作用是在需要的时候方便调用这段(回调函数)代码。

​ 在JavaScript中函数也是对象的一种,同样对象可以作为参数传递给函数,因此函数也可以作为参数传递给另外一个函数,这个作为参数的函数就是回调函数

   function sum(x,y,callback){
                var sum = x+y;
                callback(sum);
        }
        sum(1,3,function(sum){
                console.log(sum)
        })

函数的return

将函数的执行或处理结果,返回到执行语句上,方便二次使用

  1. 默认情况下,函数返回undefined

  2. 如果需要有返回值,要在函数中使用关键字:return

  3. return 值

  • 为什么要有返回值,如果是处理数据的函数,处理之后的数据,有可能需要二次使用,需要有返回值,返回处理好的数据
  1. 通过return来返回无名函数

        function fn(a){
                return function(b){
                        return function (c){
                                return function (d){
                                        return a+b+c+d;
                                }
                        }
                }
        }
        fn(3)(4)(5)(6)=3+4+5+6;
    
  2. return 可以返回几次数据:1次

    • 函数中,可以写多个return,但是函数只能执行一次return,执行之后,函数会立即结束,后面代码不再执行

arguments对象

arguments是函数中专有的一个对象,只有在函数中能拿到,用来保存函数所有的实参。

  1. arguments其实是一个伪数组,可以使用数组的所有方法和属性(length)。
  2. arguments.length实际上就是实参的个数。
  3. 借助arguments找到所有的实参:console.log(arguments);

作用域

变量生效的区域

能不能跨作用域访问:

  1. 同级局部不能跨
  2. 不能拿子,子能拿父
  3. 多个父子级作用域内都有,找最近的作用域
局部作用域

区域:每个函数都是一个局部

  1. 生命周期:朝生暮死,作用域声明时被创建,作用域结束时被释放

  2. 缺点:更麻烦,每个局部都需要定义某个变量,甚至是几个局部都相同的变量

全局作用域

整个代码文件,不属于任何一个函数,就是全局

  1. 生命周期:一直存在,在任何位置都可以拿到
  2. 缺点:更浪费性能

递归

递归算法:在函数内部,执行自己

    function fn(n){
        if(n == 1 || n == 2){
            return 1
        }else{
            return fn(n-1) + fn(n-2);
        }
    }
    console.log(fn(8));

递归最重要的就是停止条件

Function.prototype方法

blind()

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

  • 语法

    function.bind(thisArg[, arg1[, arg2[, ...]]])
    
  • 返回值

    ​ 返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。

  • 实例

    this.x = 9;    // 在浏览器中,this 指向全局的 "window" 对象
    var module = {
      x: 81,
      getX: function() { return this.x; }
    };
    
    module.getX(); // 81
    
    var retrieveX = module.getX;
    retrieveX();   
    // 返回 9 - 因为函数是在全局作用域中调用的
    
    // 创建一个新函数,把 'this' 绑定到 module 对象
    // 新手可能会将全局变量 x 与 module 的属性 x 混淆
    var boundGetX = retrieveX.bind(module);
    boundGetX(); // 81
    
call()

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

  • 语法

    function.call(thisArg, arg1, arg2, ...)
    
  • 返回值

    ​ 使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined

  • 实例

    //使用call 方法调用父构造函数
    function Product(name, price) {
      this.name = name;
      this.price = price;
    }
    
    function Food(name, price) {
      Product.call(this, name, price);
      this.category = 'food';
    }
    
    function Toy(name, price) {
      Product.call(this, name, price);
      this.category = 'toy';
    }
    
    var cheese = new Food('feta', 5);
    var fun = new Toy('robot', 40);
    
    //使用call方法调用匿名函数
    var animals = [
      { species: 'Lion', name: 'King' },
      { species: 'Whale', name: 'Fail' }
    ];
    
    for (var i = 0; i < animals.length; i++) {
      (function(i) {
        this.print = function() {
          console.log('#' + i + ' ' + this.species
                      + ': ' + this.name);
        }
        this.print();
      }).call(animals[i], i);
    }
    
apply()

apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。

  • 语法

    func.apply(thisArg, [argsArray])
    
  • 返回值

    ​ 调用有指定this值和参数的函数的结果。

  • 实例

    //用 apply 将数组添加到另一个数组
    var array = ['a', 'b'];
    var elements = [0, 1, 2];
    array.push.apply(array, elements);
    console.info(array); // ["a", "b", 0, 1, 2]
    

数组Array

概念:一组数据,数据的组合

意义:可以操作多个数据

数组的创建

  • 字面量

    var arr = [];
    
  • 构造函数:

    var arr = new Array();
    
  • 二者的唯一区别:

    字面量:当只有一个数据,还是数值时,字面量会在数组中保存这个数值

    构造函数:会将这个数值作为长度

     var arr = [6];
        var arr2 = new Array(6);
        console.log(arr);//[6]
        console.log(arr2);//(6) [empty × 6]
        console.log(arr.length)//1
        console.log(arr2.length)//6
    

Array.prototype方法

索引操作

  • 增:给不存在的索引赋值

    var arr = [1,2,3];
    arr[5] = 5;
    console.log(arr);//(6) [1, 2, 3, empty × 2, 5]
    console.log(arr.length);//6
    
  • var arr = [1,2,3];
    arr.length = 2;
    console.log(arr);//(2) [1, 2]
    
  • var arr = [1,2,3];
    arr[1] = 4;
    console.log(arr);//(3) [1,4,3]
    
  • 查:数组的遍历

    var arr = [1,2,3];
    for(var i=0;i<3;i++)
        {
            console.log(arr[i]);
        }
    

方法操作(方法:对象中的函数属性)

concat()

功能:用于连接两个或多个数组,该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
参数:concat(data1,data2,…);所有参数可选,要合并的数据;data为数组时,将data合并到原数组;data为具体数据时直接添加到原数组尾部;省略时创建原数组的副本。

var arr1 = [1,2,3]
var arr2 = arr1.concat();
console.log(arr1);           //[1,2,3]---原数组
console.log(arr1 === arr2);  //false
console.log(arr2);           //[1,2,3]---原数组的副本

console.log(arr1.concat("hello","world"));           //[1,2,3,"hello","world"]
console.log(arr1.concat(["a","b"],[[3,4],{"name":"admin"}]));   //[1,2,3,"a","b",[3,4],{"name":"admin"}]
console.log(arr1);           //[1,2,3]---原数组未改变

1,2,3,4].concat(1,2,3,[1,[1,2,3,4,5],3]);//(10) [1, 2, 3, 4, 1, 2, 3, 1, Array(5), 3]
join()

功能:根据指定分隔符将数组中的所有元素放入一个字符串,并返回这个字符串。
参数:join(str);参数可选,默认为”,”号,以传入的字符作为分隔符。

    var arr = [1,2,3];
    console.log(arr.join());         //1,2,3
    console.log(arr.join("-"));      //1-2-3
    console.log(arr);                //[1,2,3]---原数组未改变
pop()

功能:方法用于删除并返回数组的最后一个元素。
参数:

    var arr = [1,2,3];
    console.log(arr.pop());     //3
    console.log(arr);           //[1,2]---原数组改变
shift()

功能:方法用于删除并返回数组的第一个元素。
参数:

    var arr = [1,2,3]
    console.log(arr.shift());       //1
    console.log(arr);               //[2,3]---原数组改变
unshift()

功能:向数组的开头添加一个或更多元素,并返回新的长度。
参数:unshift(newData1, newData2, ……)

    var arr = [1,2,3];
    console.log(arr.unshift("hello"));  //4
    console.log(arr);                   //["hello",1,2,3]---原数组改变
    console.log(arr.unshift("a","b"));  //6
    console.log(arr);                   //["a","b","hello",1,2,3]---原数组改变
push()

功能:向数组的末尾添加一个或更多元素,并返回新的长度。
参数:push(newData1, newData2, ……)

    var arr = [1,2,3];
    console.log(arr.push("hello"));  //4
    console.log(arr);                //[1,2,3,"hello"]---原数组改变
    console.log(arr.push("a","b"));  //6
    console.log(arr);                //[1,2,3,"hello","a","b"]---原数组改变
reverse()

功能:颠倒数组中元素的顺序。
参数:

    var arr = [1,2,3];
    console.log(arr.reverse());     //[3,2,1]
    console.log(arr);               //[3,2,1]---原数组改变
slice()

功能:可从已有的数组中返回选定的元素。该方法接收两个参数slice(start,end),strat为必选,表示从第几位开始;end为可选,表示到第几位结束(不包含end位),省略表示到最后一位;start和end都可以为负数,负数时表示从最后一位开始算起,如-1表示最后一位。
参数:slice(startIndex, endIndex)

    var arr = ["Tom","Jack","Lucy","Lily","May"];
    console.log(arr.slice(1,3));        //["Jack","Lucy"]
    console.log(arr.slice(1));          //["Jack","Lucy","Lily","May"]
    console.log(arr.slice(-4,-1));      //["Jack","Lucy","Lily"]
    console.log(arr.slice(-2));         //["Lily","May"]
    console.log(arr.slice(1,-2));       //["Jack","Lucy"]
    console.log(arr);                   //["Tom","Jack","Lucy","Lily","May"]---原数组未改变
sort()

功能:对数组中的元素进行排序,默认是升序。

    var arr = [6,1,5,2,3];
    console.log(arr.sort());    //[1, 2, 3, 5, 6]
    console.log(arr);           //[1, 2, 3, 5, 6]---原数组改变

但是在排序前,会先调用数组的toString方法,将每个元素都转成字符之后,再进行排序,此时会按照字符串的排序,逐位比较,进行排序。

    var arr = [6,1024,52,256,369];
    console.log(arr.sort());    //[1024, 256, 369, 52, 6]
    console.log(arr);           //[1024, 256, 369, 52, 6]---原数组改变

参数:sort(callback)
如果需要按照数值排序,需要传参。sort(callback),callback为回调函数,该函数应该具有两个参数,比较这两个参数,然后返回一个用于说明这两个值的相对顺序的数字(a-b)。其返回值如下:
若 a 小于 b,返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。

    var arr = [6,1024,52,256,369];
    console.log(arr.sort(fn));  //[6, 52, 256, 369, 1024]
    console.log(arr);           //[6, 52, 256, 369, 1024]---原数组改变
    function fn(a,b){
        return a-b;
    }
splice()

功能:向数组中添加,或从数组删除,或替换数组中的元素,然后返回被删除/替换的元素。
参数:splice(start,num,data1,data2,…); 所有参数全部可选。

  1. 不传参时:无操作
    var arr = ["Tom","Jack","Lucy","Lily","May"];
    console.log(arr.splice());      //[]
    console.log(arr);               //["Tom","Jack","Lucy","Lily","May"]---无操作
  1. 只传入start:表示从索引为start的数据开始删除,直到数组结束
    var arr = ["Tom","Jack","Lucy","Lily","May"];    
    console.log(arr.splice(2));     //["Lucy", "Lily", "May"]
    console.log(arr);               //["Tom", "Jack"]---原数组改变
  1. 传入start和num:表示从索引为start的数据开始删除,删除num个
    var arr = ["Tom","Jack","Lucy","Lily","May"];    
    console.log(arr.splice(2,2));   //["Lucy", "Lily"]
    console.log(arr);               //["Tom", "Jack", "May"]---原数组改变
  1. 删除和替换更多:表示从索引为start的数据开始删除,删除num个,并将第三个参数及后面所有参数,插入到start的位置
    var arr = ["Tom","Jack","Lucy","Lily","May"];    
    console.log(arr.splice(2,2,"a","b"));  //["Lucy", "Lily"]
    console.log(arr);                      //["Tom", "Jack", "a", "b", "May"]---原数组改变
  1. 增加更多:表示从索引为start的数据开始删除,删除num个,并将第三个参数及后面所有参数,插入到start的位置
    var arr = ["Tom","Jack","Lucy","Lily","May"];    
    console.log(arr.splice(2,0,"a","b"));  //[]
    console.log(arr);    //["Tom", "Jack", "a", "b", "Lucy", "Lily", "May"]---原数组改变
toString()

功能:转换成字符串,类似于没有参数的join()。该方法会在数据发生隐式类型转换时被自动调用,如果手动调用,就是直接转为字符串。
参数:

    var arr = [1,2,3];
    console.log(arr.toString());     //1,2,3
    console.log(arr);                //[1,2,3]---原数组未改变
valueOf()

功能:返回数组的原始值(一般情况下其实就是数组自身),一般由js在后台调用,并不显式的出现在代码中
参数:

    var arr = [1,2,3];
    console.log(arr.valueOf());         //[1,2,3]
    console.log(arr);                   //[1,2,3]
    //为了证明返回的是数组自身
    console.log(arr.valueOf() == arr);  //true
indexOf()

功能:根据指定的数据,从左向右,查询在数组中出现的位置,如果不存在指定的数据,返回-1。该方法是查询方法,不会对数组产生改变。
参数:indexOf(value, start);value为要查询的数据;start为可选,表示开始查询的位置,当start为负数时,从数组的尾部向前数;如果查询不到value的存在,则方法返回-1

    var arr = ["h","e","l","l","o"];
    console.log(arr.indexOf("l"));        //2
    console.log(arr.indexOf("l",3));      //3
    console.log(arr.indexOf("l",4));      //-1
    console.log(arr.indexOf("l",-1));     //-1
    console.log(arr.indexOf("l",-3));     //2
lastIndexOf()

功能:根据指定的数据,从右向左,查询在数组中出现的位置,如果不存在指定的数据,返回-1。该方法是查询方法,不会对数组产生改变。
参数:lastIndexOf(value, start);value为要查询的数据;start为可选,表示开始查询的位置,当start为负数时,从数组的尾部向前数;如果查询不到value的存在,则方法返回-1

    var arr = ["h","e","l","l","o"];
    console.log(arr.lastIndexOf("l"));        //3
    console.log(arr.lastIndexOf("l",3));      //3
    console.log(arr.lastIndexOf("l",1));      //-1
    console.log(arr.lastIndexOf("l",-3));     //2
    console.log(arr.lastIndexOf("l",-4));     //-1
forEach()

功能:ES5新增方法,用来遍历数组,该方法没有返回值。forEach接收的回调函数会根据数组的每一项执行,该回调函数默认有三个参数,分别为:遍历到的数组的数据,对应的索引,数组自身。
参数:forEach(callback);callback默认有三个参数,分别为value,index,self。

    var arr = ["Tom","Jack","Lucy","Lily","May"];
    var a = arr.forEach(function(value,index,self){
        console.log(value + "--" + index + "--" + (arr === self));
    })
    // 打印结果为:
    // Tom--0--true
    // Jack--1--true
    // Lucy--2--true
    // Lily--3--true
    // May--4--true
    console.log(a);     //undefined---forEach没有返回值
    //该方法为遍历方法,不会修改原数组
map()

功能:1.同forEach功能;2.map的回调函数会将执行结果返回,最后map将所有回调函数的返回值组成新数组返回。
参数:map(callback);callback默认有三个参数,分别为value,index,self。

    //功能1:同forEach
    var arr = ["Tom","Jack","Lucy","Lily","May"];
    var a = arr.map(function(value,index,self){
        console.log(value + "--" + index + "--" + (arr === self))
    })
    // 打印结果为:
    // Tom--0--true
    // Jack--1--true
    // Lucy--2--true
    // Lily--3--true
    // May--4--true

    //功能2:每次回调函数的返回值被map组成新数组返回
    var arr = ["Tom","Jack","Lucy","Lily","May"];
    var a = arr.map(function(value,index,self){
        return "hi:"+value;
    })
    console.log(a);     //["hi:Tom", "hi:Jack", "hi:Lucy", "hi:Lily", "hi:May"]
    console.log(arr);   //["Tom", "Jack", "Lucy", "Lily", "May"]---原数组未改变
filter()

功能:1.同forEach功能;2.filter的回调函数需要返回布尔值,当为true时,将本次数组的数据返回给filter,最后filter将所有回调函数的返回值组成新数组返回(此功能可理解为“过滤”)。
参数:filter(callback);callback默认有三个参数,分别为value,index,self。

    //功能1:同forEach
    var arr = ["Tom","Jack","Lucy","Lily","May"];
    var a = arr.filter(function(value,index,self){
        console.log(value + "--" + index + "--" + (arr === self))
    })
    // 打印结果为:
    // Tom--0--true
    // Jack--1--true
    // Lucy--2--true
    // Lily--3--true
    // May--4--true

    //功能2:当回调函数的返回值为true时,本次的数组值返回给filter,被filter组成新数组返回
    var arr = ["Tom","Jack","Lucy","Lily","May"];
    var a = arr.filter(function(value,index,self){
        return value.length > 3;
    })
    console.log(a);         //["Jack", "Lucy", "Lily"]
    console.log(arr);       //["Tom", "Jack", "Lucy", "Lily", "May"]---原数组未改变
includes()

includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。

  • 语法

    arr.includes(valueToFind[, fromIndex])
    
  • 返回值

    返回一个布尔值 Boolean ,如果在数组中找到了(如果传入了 fromIndex ,表示在 fromIndex 指定的索引范围中找到了)则返回 true 。
    
  • 实例

    var arr = [1,2,2,4,5,6,7];
    console.log(arr.includes(8));//false
    console.log(arr.includes(1));//true
    console.log(arr.includes(2));//true
    
every()

功能:判断数组中每一项是否都满足条件,只有所有项都满足条件,才会返回true。
参数:every()接收一个回调函数作为参数,这个回调函数需要有返回值,every(callback);callback默认有三个参数,分别为value,index,self。

功能1:当回调函数的返回值为true时,类似于forEach的功能,遍历所有;如果为false,那么停止执行,后面的数据不再遍历,停在第一个返回false的位置。

    //demo1:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.every(function(value,index,self){
        console.log(value + "--" + index + "--" + (arr == self))
    })
    // 打印结果为:
    // Tom--0--true
    //因为回调函数中没有return true,默认返回undefined,等同于返回false

    //demo2:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.every(function(value,index,self){
        console.log(value + "--" + index + "--" + (arr == self))
        return value.length < 4;
    })
    // 打印结果为:
    // Tom--0--true
    // abc--1--true
    // Jack--2--true
    //因为当遍历到Jack时,回调函数到return返回false,此时Jack已经遍历,但是后面数据就不再被遍历了

    //demo3:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.every(function(value,index,self){
        console.log(value + "--" + index + "--" + (arr == self))
        return true;
    })
    // 打印结果为:
    // Tom--0--true
    // abc--1--true
    // Jack--2--true
    // Lucy--3--true
    // Lily--4--true
    // May--5--true
    //因为每个回调函数的返回值都是true,那么会遍历数组所有数据,等同于forEach功能

功能2:当每个回调函数的返回值都为true时,every的返回值为true,只要有一个回调函数的返回值为false,every的返回值都为false

    //demo1:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.every(function(value,index,self){
        return value.length > 3;
    })
    console.log(a);           //false

    //demo2:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.every(function(value,index,self){
        return value.length > 2;
    })
    console.log(a);           //true
some()

功能:判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。
参数:some()接收一个回调函数作为参数,这个回调函数需要有返回值,some(callback);callback默认有三个参数,分别为value,index,self。

功能1:因为要判断数组中的每一项,只要有一个回调函数返回true,some都会返回true,所以与every正好相反,当遇到一个回调函数的返回值为true时,可以确定结果,那么停止执行,后面都数据不再遍历,停在第一个返回true的位置;当回调函数的返回值为false时,需要继续向后执行,到最后才能确定结果,所以会遍历所有数据,实现类似于forEach的功能,遍历所有。

    //demo1:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.some(function(value,index,self){
        console.log(value + "--" + index + "--" + (arr == self))
        return value.length > 3;
    })
    // 打印结果为:
    // Tom--0--true
    // abc--1--true
    // Jack--2--true

    //demo2:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.some(function(value,index,self){
        console.log(value + "--" + index + "--" + (arr == self))
        return true;
    })
    // 打印结果为:
    // Tom--0--true

    //demo3:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.some(function(value,index,self){
        console.log(value + "--" + index + "--" + (arr == self))
        return false;
    })
    // 打印结果为:
    // Tom--0--true
    // abc--1--true
    // Jack--2--true
    // Lucy--3--true
    // Lily--4--true
    // May--5--true

功能2:与every相反,只要有一个回调函数的返回值都为true,some的返回值为true,所有回调函数的返回值为false,some的返回值才为false

    //demo1:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.some(function(value,index,self){
        return value.length > 3;
    })
    console.log(a);             //true

    //demo2:
    var arr = ["Tom","abc","Jack","Lucy","Lily","May"];
    var a = arr.some(function(value,index,self){
        return value.length > 4;
    })
    console.log(a);             //false
reduce()

功能:从数组的第一项开始,逐个遍历到最后,迭代数组的所有项,然后构建一个最终返回的值。

参数:reduce()接收一个或两个参数:第一个是回调函数,表示在数组的每一项上调用的函数;第二个参数(可选的)作为归并的初始值,被回调函数第一次执行时的第一个参数接收。
reduce(callback,initial);callback默认有四个参数,分别为prev,now,index,self。
callback返回的任何值都会作为下一次执行的第一个参数。
如果initial参数被省略,那么第一次迭代发生在数组的第二项上,因此callback的第一个参数是数组的第一项,第二个参数就是数组的第二项。

    //demo1:不省略initial参数,回调函数没有返回值
    var arr = [10,20,30,40,50];
    arr.reduce(function(prev,now,index,self){
        console.log(prev + "--" + now + "--" + index + "--" + (arr == self))
    }, 2019)
    // 打印结果为:
    // 2019--10--0--true
    // undefined--20--1--true
    // undefined--30--2--true
    // undefined--40--3--true
    // undefined--50--4--true
    // 此时回调函数没有return,所以从第二次开始,prev拿到的是undefined

    //demo2:省略initial参数,回调函数没有返回值
    var arr = [10,20,30,40,50];
    arr.reduce(function(prev,now,index,self){
        console.log(prev + "--" + now + "--" + index + "--" + (arr == self))
    })
    // 打印结果为:第一次,回调函数的第一个参数是数组的第一项。第二个参数就是数组的第二项
    // 10--20--1--true
    // undefined--30--2--true
    // undefined--40--3--true
    // undefined--50--4--true
    // 此时回调函数没有return,所以从第二次开始,prev拿到的是undefined

    //demo3:不省略initial参数,回调函数有返回值
    var arr = [10,20,30,40,50];
    arr.reduce(function(prev,now,index,self){
        console.log(prev + "--" + now + "--" + index + "--" + (arr == self));
        return "hello";
    }, 2019)
    // 打印结果为:
    // 2019--10--0--true
    // hello--20--1--true
    // hello--30--2--true
    // hello--40--3--true
    // hello--50--4--true
    // 此时回调函数有return,所以从第二次开始,prev拿到的是回调函数return的值

    //demo4:省略initial参数,回调函数有返回值
    var arr = [10,20,30,40,50];
    arr.reduce(function(prev,now,index,self){
        console.log(prev + "--" + now + "--" + index + "--" + (arr == self));
        return "hello";
    })
    // 打印结果为:第一次,回调函数的第一个参数是数组的第一项。第二个参数就是数组的第二项
    // 10--20--1--true
    // hello--30--2--true
    // hello--40--3--true
    // hello--50--4--true
    // 此时回调函数有return,所以从第二次开始,prev拿到的是回调函数return的值

    //demo5:使用reduce计算数组中所有数据的和
    var arr = [10,20,30,40,50];
    var sum = arr.reduce(function(prev,now,index,self){
        return prev + now;
    })
    console.log(sum);      //150
    // 回调函数的最后一次return的结果被返回到reduce方法的身上

    //demo6:使用reduce计算数组中所有数据的和
    var arr = [10,20,30,40,50];
    var sum = arr.reduce(function(prev,now,index,self){
        return prev + now;
    }, 8)
    console.log(sum);      //158
    // 回调函数的最后一次return的结果被返回到reduce方法的身上
    // 因为reduce有第二个参数initial,在第一次执行时被计算,所以最终结果被加上8
reduceRight()

功能:(与reduce类似)从数组的最后一项开始,向前逐个遍历到第一位,迭代数组的所有项,然后构建一个最终返回的值。
参数:同reduce。
demo:同reduce

数组的排序
冒泡排序
var arr = [5,99,2,9,1,5,67,7,10,23]      //定义一个杂乱的数组
    for(var i=0;i<arr.length-1;i++){         //大循环,用于遍历数组每个元素
        for(var j=0;j<arr.length-i-1;j++){   //小循环,用于将数组中的某个元素与其它所有元素相比较
            var temp;                         //声明一个局部变量,当作第三个空瓶子
            if(arr[j]>arr[j+1]){           //判断当前元素和后一个元素的大小,如果当前元素比后一个元素大
                temp = arr[j+1];           //将后一个元素(小元素)放在空瓶子里
                arr[j+1] = arr[j];         //将当前元素(大元素)放在后一个元素的位置
                arr[j] = temp;             //将小元素从空瓶子中拿出来,放在当前元素的位置
            }
        } 
    }
    console.log(arr);                      //完成循环之后,初始数组的顺序已经发生改变
选择排序
    var arr = [5,99,2,9,1,5,67,7,10,23]
    for(var i=0;i<arr.length-1;i++){       //大循环,需要比对的次数
        var min = arr[i];                  //假定一个最小值
        var minIndex = i;                  //假定最小值的索引
        for(var j=i+1;j<arr.length;j++){   //小循环,每次需要比对的次数
            if(min>arr[j]){                //判断最小值是否为真的最小值
                min = arr[j];              //获取真正的最小值
                minIndex = j;              //获取真正最小值的索引
            }
        }

        arr[minIndex] = arr[i];            //将当前元素放在最小值的位置
        arr[i] = min;                      //将最小值放在当前元素的位置
    }
    console.log(arr);                      //输入排序好的数组 

数组的方法some和includes

some() 方法用于检测数组中的元素是否满足指定条件(函数提供)。

some() 方法会依次执行数组的每个元素:

  • 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
  • 如果没有满足条件的元素,则返回false。

注意: some() 不会对空数组进行检测。

​ some() 不会改变原始数组。

includes() 方法用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false

两者经常会搭配使用。

js-基本数据类型

基本数据类型

字符串

字符串的标志:引号

  • 字符串的拼接过程中:引号要配对,变量不能放在引号中

    var a = "很好";
    console.log("今天天气"+ a +"适合出去玩");
    
  • 创建字符

    • 字面量创建
    • 构造函数创建
    var str = "";
    var str2 = new String("");
    console.log(str);
    console.log(str2);
    

String.prototype方法

indexOf()

indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。

  • 语法

    stringObject.indexOf(searchvalue,fromindex)
    
  • 实例

    var str = "hello world";
    str.indexOf("o");//4,存在即返回索引
    str.indexOf("o",5);//7,从索引为5的数据开始往后找
    str.indexOf("a");//-1,不存在即返回-1
    
charAt()

charAt() 方法可返回指定位置的字符。

请注意,JavaScript 并没有一种有别于字符串类型的字符数据类型,所以返回的字符是长度为 1 的字符串。

  • 语法

     stringObject.charAt(index)
    
  • 实例

    var str = "hello world";
    str.charAt(2);//"l"
    str.charAt(-1);//""
    
slice()

slice() 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。

  • 语法

    stringObject.slice(start,end)
    
  • 实例

    var str="Hello happy world!";
    document.write(str.slice(6));//"happy world!"
    document.write(str.slice(2,4));//"ll"
    
substr()

substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符。

  • 语法

    stringObject.substr(start,length)
    
  • 实例

    var str="Hello happy world!";
    document.write(str.substr(6));//"happy world!"
    document.write(str.substr(2,4));//"lo h"
    
substring()

substring() 方法用于提取字符串中介于两个指定下标之间的字符。

  • 语法

    stringObject.substring(start,stop),取start到(stop-1)范围内的字符
    
  • 实例

    var str="Hello world!"
    document.write(str.substring(3));//"lo world!"
    document.write(str.substring(3,7))//"lo w"
    
split()

split() 方法用于把一个字符串分割成字符串数组。

  • 语法

    stringObject.split(separator,howmany)
    
  • 实例

    var str="How are you doing today?"
    console.log(str.split(" ") + "<br />")//"How,are,you,doing,today?<br />"
    console.log(str.split("") + "<br />")//"H,o,w, ,a,r,e, ,y,o,u, ,d,o,i,n,g, ,t,o,d,a,y,?<br />"
    console.log(str.split(" ",3))//(3) ["How", "are", "you"]
    
    "2:3:4:5".split(":")    //将返回["2", "3", "4", "5"]
    "|a|b|c".split("|")    //将返回["", "a", "b", "c"]
    
    "hello".split("", 3)    //可返回 ["h", "e", "l"]
    
toLowerCase()

toLowerCase() 方法用于把字符串转换为小写。

  • 语法

    stringObject.toLowerCase()
    
  • 返回值

    ​ 一个新的字符串,在其中 stringObject 的所有大写字符全部被转换为了小写字符。

  • 实例

    var str="Hello World!"
    console.log(str.toLowerCase());//"hello world!"
    
toUpperCase()

toUpperCase() 方法用于把字符串转换为大写。

  • 语法

    stringObject.toUpperCase()
    
  • 返回值

    ​ 一个新的字符串,在其中 stringObject 的所有小写字符全部被转换为了大写字符。

  • 实例

    var str="Hello World!"
    console.log(str.toUpperCase());//"HELLO WORLD!"
    
concat()

concat() 方法用于连接两个或多个字符串。

  • 语法

    stringObject.concat(stringX,stringX,...,stringX)
    
  • 实例

    var str1="Hello "
    var str2="world!"
    document.write(str1.concat(str2));//"Hello world!"
    
includes()

includes() 方法用于判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false。

  • 语法

    str.includes(searchString[, position])
    
  • 返回值

    如果当前字符串包含被搜寻的字符串,就返回 true;否则返回 false。
    
  • 实例

    var str = 'To be, or not to be, that is the question.';
    
    console.log(str.includes('To be')); // true
    console.log(str.includes('question')); // true
    console.log(str.includes('not tobe')); // false
    console.log(str.includes('To be', 1)); // false
    console.log(str.includes('o be', 1)); // true
    console.log(str.includes('TO BE')); // false
    
replace()

replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

  • 语法

    stringObject.replace(regexp/substr,replacement)
    
  • 返回值

    ​ 一个新的字符串,是用 replacement 替换了 regexp 的第一次匹配或所有匹配之后得到的。

  • 实例

    var str="Visit Microsoft!,Microsoft"
    console.log(str.replace(/Microsoft/, "W3School"));//"Visit Microsoft"
    

字符编码的介绍和转换

ASCII
  • American Standard Code for Information Interchange,美国信息交换标准代码。
Unicode
  • Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。
  • Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。 Unicode目前普遍采用的是UCS-2,它用两个字节来编码一个字符。
GBK
  • GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification)
  • GBK 向下与GB2312编码兼容,向上支持 ISO 10646.1国际标准,是前者向后者过渡过程中的一个承上启下的产物。
UTF-8
  • UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码。
  • UTF-8用1到4个字节编码UNICODE字符。用在网页上可以同一页面显示中文简体繁体及其它语言(如英文,日文,韩文)

字符串常见API

myStr.charCodeAt(num)

返回指定位置的字符的Unicode(是字符编码的一种模式)编码。

var str="Hello world!"
console.log(str.charCodeAt(1));//"101"
String.fromCharCode()

String的意思就是不能用自己定义的字符串名字来调用,只能用String来定义调用。可以识别十进制和十六进制的编码,但是不识别u编码然后返回一个或多个字符串。(把unicode编码转换为字符串)。

var n = String.fromCharCode(65);//A

ES6新增

str.codePointAt()

codePointAt() 方法返回 一个 Unicode 编码点值的非负整数。

  • 语法

    str.codePointAt(pos)//支持5位unicode编码
    
  • 实例

    'ABC'.codePointAt(1);          // 66
    '\uD800\uDC00'.codePointAt(0); // 65536
    
    'XYZ'.codePointAt(42); // undefined
    
    `𠮶`.codePointAt();//134070
    
String.fromCodePoint()

String.fromCodePoint() 静态方法返回使用指定的代码点序列创建的字符串。**

  • 语法

    String.fromCodePoint(num1[, ...[, numN]])
    
  • 返回值

    使用指定的 Unicode 编码位置创建的字符串。

  • 实例

    String.fromCodePoint(42);       // "*"
    String.fromCodePoint(65, 90);   // "AZ"
    String.fromCodePoint(0x404);    // "\u0404"
    String.fromCodePoint(0x2F804);  // "\uD87E\uDC04"
    String.fromCodePoint(194564);   // "\uD87E\uDC04"
    String.fromCodePoint(0x1D306, 0x61, 0x1D307) // "\uD834\uDF06a\uD834\uDF07"
    
str.includes()

includes() 方法用于判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false。

  • 语法

    str.includes(searchString[, position])
    
  • 返回值

    如果当前字符串包含被搜寻的字符串,就返回 true;否则返回 false。
    
  • 实例

    var str = 'To be, or not to be, that is the question.';
    
    console.log(str.includes('To be')); // true
    console.log(str.includes('question')); // true
    console.log(str.includes('not tobe')); // false
    console.log(str.includes('To be', 1)); // false
    console.log(str.includes('o be', 1)); // true
    console.log(str.includes('TO BE')); // false
    
str.startsWith()

startsWith() 方法用来判断当前字符串是否以另外一个给定的子字符串开头,并根据判断结果返回 truefalse

  • 语法

    str.startsWith(searchString[, position])
    
  • 返回值

    如果在字符串的开头找到了给定的字符则返回true;否则, 返回false.
    
  • 实例

    var str = "To be, or not to be, that is the question.";
    
    alert(str.startsWith("To be"));         // true
    alert(str.startsWith("not to be"));     // false
    alert(str.startsWith("not to be", 10)); // true
    
str.endsWith()

endsWith()方法用来判断当前字符串是否是以另外一个给定的子字符串“结尾”的,根据判断结果返回 truefalse

  • 语法

    str.endsWith(searchString[, length])
    
  • 返回值

    如果传入的子字符串在搜索字符串的末尾则返回true;否则将返回 false。
    
  • 实例

    var str = "To be, or not to be, that is the question.";
    
    alert( str.endsWith("question.") );  // true
    alert( str.endsWith("to be") );      // false
    alert( str.endsWith("to be", 19) );  // true
    
str.repeat()

repeat() 构造并返回一个新字符串,该字符串包含被连接在一起的指定数量的字符串的副本。

  • 语法

    /** 
     * str: String
     * count: Number
     */
    
    let resultString = str.repeat(count);
    
  • 返回值

    包含指定字符串的指定数量副本的新字符串

  • 实例

    "abc".repeat(-1)     // RangeError: repeat count must be positive and less than inifinity
    "abc".repeat(0)      // ""
    "abc".repeat(1)      // "abc"
    "abc".repeat(2)      // "abcabc"
    "abc".repeat(3.5)    // "abcabcabc" 参数count将会被自动转换成整数.
    "abc".repeat(1/0)    // RangeError: repeat count must be positive and less than inifinity
    
反引号语法
  • 支持换行

    var name = "root";
    var str = `hello
    world`;
    console.log(str);
    
  • 配合${}支持变量拼接

    var name = "root";
    var str = `hello""'''""${name}"
    world`;
    console.log(str)
    

js原生-Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
Object.assign(target, ...sources)    【target:目标对象】,【souce:源对象(可多个)】
举个栗子:
const object1 = {
  a: 1,
  b: 2,
  c: 3
};

const object2 = Object.assign({c: 4, d: 5}, object1);

console.log(object2.c, object2.d);
console.log(object1)  // { a: 1, b: 2, c: 3 }
console.log(object2)  // { c: 3, d: 5, a: 1, b: 2 }

注意:
1.如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性
2.Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标
对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如
果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到
原型,应使用Object.getOwnPropertyDescriptor()和Object.defineProperty() 。

二、Object.assign()对象的深拷贝

针对深拷贝,需要使用其他办法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。
let obj1 = { a: 0 , b: { c: 0}}; 
let obj2 = Object.assign({}, obj1); 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 

obj1.a = 1; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 

obj2.a = 2; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
 
obj2.b.c = 3; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}} 
最后一次赋值的时候,b是值是对象的引用,只要修改任意一个,其他的也会受影响

// Deep Clone (深拷贝)
obj1 = { a: 0 , b: { c: 0}}; 
let obj3 = JSON.parse(JSON.stringify(obj1)); 
obj1.a = 4; 
obj1.b.c = 4; 
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}

3、对象的合并

const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };

const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。
其实就是对象的拷贝,o1就是目标对象,后面的是源对象,后面的属性等会拷贝到目标对象

4、合并具有相同属性的对象

const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };

const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
1.属性被后续参数中具有相同属性的其他对象覆盖。
2.目标对象的属性与源对象的属性相同,源的会覆盖目标的属性

5.继承属性和不可枚举属性是不能拷贝

const obj = Object.create({foo: 1}, { // foo 是个继承属性。
    bar: {
        value: 2  // bar 是个不可枚举属性。
    },
    baz: {
        value: 3,
        enumerable: true  // baz 是个自身可枚举属性。
    }
});
创建对象时,如果没有设置enumerable的值,默认为false(不可枚举属性),设置为true,则为可枚举属性
const copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }

6.原始类型会被包装为对象

const v1 = "abc";
const v2 = true;
const v3 = 10;
const v4 = Symbol("foo")

const obj = Object.assign({}, v1, null, v2, undefined, v3, v4); 
// 原始类型会被包装,null 和 undefined 会被忽略。
// 注意,只有字符串的包装对象才可能有自身可枚举属性。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

7.异常会打断后续拷贝任务

const target = Object.defineProperty({}, "foo", {
    value: 1,
    writable: false
}); // target 的 foo 属性是个只读属性。

Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4});
// TypeError: "foo" is read-only
// 注意这个异常是在拷贝第二个源对象的第二个属性时发生的。

console.log(target.bar);  // 2,说明第一个源对象拷贝成功了。
console.log(target.foo2); // 3,说明第二个源对象的第一个属性也拷贝成功了。
console.log(target.foo);  // 1,只读属性不能被覆盖,所以第二个源对象的第二个属性拷贝失败了。
console.log(target.foo3); // undefined,异常之后 assign 方法就退出了,第三个属性是不会被拷贝到的。
console.log(target.baz);  // undefined,第三个源对象更是不会被拷贝到的。

js-ie8 浏览器 js兼容问题

因为项目需要,客户设备上都是IE8,总结了一些IE8上容易出现的兼容性错误

\1. jQuery使用2.0以下版本

2.document.getElementsByClassName 不能使用

3.console.log()不支持

4.iframe 的 onload 事件,需要通过 attachEvent 来注册

5.因为jq使用版本低,所以注意on ,是在1.7版本才出现的

6.IE8(Q) 中的 getElementById 方法能以 name 属性为参数获取某些元素

7.使用apped动态加载元素时候,注意标记元素必须是规范的html标记,不能是自创元素或者标记未关闭

8.remove()不能再IE8中正常使用,使用removeNode(true);