JS笔记

JS变量

  • 类型
    a、值类型:Number、String、Boolean、Null、Undefined、Symbol(ECMAScript中定义)

    存在栈中(占据空间固定,按值访问)
    

    b、引用类型:Object、Array、Function等

    存在堆中(值大小会变化,变量存储的是其指针)
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //对象深度复制问题
    window.deepClone = function(obj){
    var newobj = obj.constructor === Array ? [] : {};
    if(typeof obj !== 'object'){
    return obj;
    } else if(window.JSON){
    newobj = JSON.parse(JSON.stringify(obj));
    } else {
    for(var i in obj){
    newobj[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
    }
    }
    return newobj;
    };

    c、判断

    1、typeof [{},[],null,new Function(),new Date()]  // object
        能有效判断string,number,symbol,boolean,undefined,function
    2、A instanceof B 判断A是否B的实例
        [] instanceof Array;  //true
        [] instanceof Object;  //true
        注意网页中多个框架(iframe)情况,各自有不同的构造函数
        ES5提供了Array.isArray(arr)方法确认某个对象本身是否为Array类型
    3、constructor 在Fn的prototype属性下并指向Fn本身(只能函数和其直接构造函数)
        null,undefined不存在constructor,
        constructor不稳定,当重写prototype后,原有的constructor引用会丢失,constructor会默认为Object
        var f = new F();
        f.constructor === F  //true 因为f是F的实例,F.prototype上的constructor传递到了f上
    4、toString
        对于Object对象,直接调用toString(),就能返回字符串[object Object],其他需要用call/apply
        Object.prototype.toString() ;   // [object Object]
        Object.prototype.toString.call('') ;   // [object String]
        Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
        Object.prototype.toString.call(document) ; // [object HTMLDocument]
        Object.prototype.toString.call(window) ; //[object global] window 是全局对象global的引用
    
        
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function type(sth){
    var ty=Object.prototype.toString.call(sth);
    var res=ty.slice(8,ty.length-1);
    return res;
    }
    var o={};
    var arr=[1,2];
    console.log(type(o)); // Object 实测object也可调用call判断
    console.log(type(arr)); // Array

    d、原文链接参考

  • 计算
    强制类型转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //字符串拼接
    var a=10+10 // 20
    var b=10+'10' // 1010
    //==
    100 == '100' // true
    0 == '' // true
    null == undefined //true
    //if判断(除以下六种情况,全部转换为true)
    if(undefined || null || 0 || NaN || '' || false){
    alert(true);
    }

    // === 和 == 使用,除以下情况外,尽量全部用 ===
    if(obj.a == null){
    //jquery源码写法,相当于(obj.a === null || obj.a === undefined)
    }
  • JS内置函数及对象
    函数:Object,Array,Boolean,Number,String,Function,Date,RegExp,Error等
    对象:JSON,Math

    JSON.stringify({a:10,b:20})    //对象转字符串
    JSON.parse('{"a":10,"b":20}')  //字符串转对象
    

    数组API:

    forEach 遍历所有元素
    every 判断所有元素是否都符合条件
    some 判断是否有元素符合条件
    sort 排序
    map 对元素重新组装,生成新数组
    filter 过滤符合条件的元素
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    var arr = [1,3,2];
    arr.forEach(function(item,index){
    console.log(index,item);
    })
    var res = arr.every(function(item,index){
    if(item < 4){
    return ture; //若所有元素都小于4,返回true
    }
    })
    console.log(res); //true
    var res = arr.some(function(item,index){
    if(item < 2){
    return ture; //若有元素小于2,返回true
    }
    })
    console.log(res); //true
    arr.sort(function(a,b){ //此方法会改变自身
    //从小到大(默认)
    return a - b;
    //从大到小
    //return b - a;
    })
    console.log(arr); //[1,2,3]
    var arrm = arr.map(function(item,index){ //此方法返回新数组,原数组不变
    return '<h1>' + item + '</h1>';
    })
    console.log(arr); //[1,2,3]
    console.log(arrm); //["<h1>1</h1>","<h1>2</h1>","<h1>3</h1>"]
    var arrf = arr.filter(function(item,index){ //此方法返回新数组,原数组不变
    if(item >= 2){
    return true;
    }
    })
    console.log(arr); //[1,2,3]
    console.log(arrf); //[2,3]

    对象API:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var obj = {
    x:1,
    y:2,
    z:3
    }
    var key;
    for(key in obj){
    if(obj.hasOwnProperty(key)){
    console.log(key,obj[key]);
    }
    }

原型

  • 构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    function Foo(name){  //构造函数一般大写
    this.name = name;
    this.other = 'otherAttr';
    // return this //默认有此行
    }
    var f = new Foo('zhangsan');
    //new Foo()的时候,Foo里面的this变为空对象,属性赋值后返回this(this指向创建的新对象f)
    f instanceof Foo //判断f的直接构造函数是否为Foo
  • 原型规则
    所有引用类型(数组,对象,函数),都有对象特性:可自由扩展属性
    所有引用类型(数组,对象,函数),都有__proto__属性:属性值是普通对象
    所有的函数,都有一个prototype属性:属性值是普通对象
    所有引用类型(数组,对象,函数),__proto__属性值指向它的构造函数的”prototype”属性值
    当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它构造函数的prototype)中找

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    循环遍历自身属性
    var item;
    for(item in foo){
    //高级浏览器已经在for in中屏蔽了来自原型的属性,但还是建议加上以下判断
    if(foo.hasOwnProperty(item)){
    console.log(item);
    }
    }
    //原型继承实例,封装DOM查询
    function Emt(id){
    this.emt = document.getElementById(id);
    }
    Emt.prototype.html = function(val){
    var emt = this.emt;
    if(val){
    emt.innerHTML = val;
    return this //此句可用于链式操作
    }else{
    return emt.innerHTML;
    }
    }
    Emt.prototype.on = function(type,fn){
    var emt = this.emt;
    emt.addEventListener(type,fn);
    return this //此句表示其后还可跟链式调用
    }
    var div1 = new Emt('div1');
    //console.log(div1.html());
    //链式操作
    div1.html('<h1>Hello</h1>').on('type',function(){
    alert('clicked');
    })

作用域和闭包

  • 执行上下文
    范围:一段< script>或一个函数
    全局:变量定义、函数声明 (一段< script>)
    函数:变量定义、函数声明、this、arguments (函数)
    执行前,变量定义和函数声明被提前,this要在执行时才能确认

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var a = {
    name:'A';
    fn:function(){
    console.log(this.name);
    }
    }
    a.fn() //this === a
    a.fn().call({name:'B'}) //this ==={name:'B'}
    var fn1 = a.fn
    fn1() // this === window

    this:作为构造函数执行,作为对象属性执行,作为普通函数执行(window),call apply bind

    1
    2
    3
    4
    5
    6
    //call,apply,bind都能改变this指向(bind必须用函数表达式形式)
    var fn2 = function(name){
    alert(name);
    console.log(this) //this === {y:20}
    }.bind({y:20})
    fn2('zhangsan')
  • 作用域
    无块级,只有函数和全局作用域

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    if(true){
    var name = 'zhangsan'; //name不属于if代码块私有,在if外面能访问到此变量
    }
    console.log(name) //zhangsan
    var a = 100; //全局变量
    var b = 200;
    function fn(){
    var a = 200; //函数内部变量,与全局变量a互不影响
    console.log('fn',a); // fn 200
    //b在此函数作用域中未定义(会去父级作用域找),它是自由变量
    console.log(b); // 200
    }
    console.log('global',a); // global 100
    fn();
  • 闭包

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //函数作为返回值
    function F1(){
    var a = 100;
    return function(){
    console.log(a); //100
    }
    }
    var f1 = F1();
    var a = 200;
    f1(); //100
    //函数作为参数传递
    function F2(fn){
    var a = 200;
    fn();
    }
    F2(f1); //100
  • 异步和单线程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //同步会阻塞程序运行(区别与异步)
    console.log(1);
    alert(2); //程序在此卡住,什么时候点击,什么时候继续
    console.log(3)
    //异步不会阻塞
    console.log(1);
    setTimeout(function(){ //程序跳过定时任务,继续执行后面代码,空闲时提出来执行
    console.log(2);
    },1000)
    console.log(3);

    单线程特点:一次只能干一件事
    在可能发生等待的情况并且等待过程不能像alert一样阻塞程序运行的时候需要异步

    定时任务:setTimeout,setInterval
    网络请求:ajax请求,动态<img>加载
    事件绑定
    

    JS-Web-API

  • JS基础
    ECMA262标准
    类型,原型,作用域,异步
    
    特点:表面看并不能用于工作中开发代码
  • JS-web-api
    W3C标准中关于JS的规定有:
    DOM操作
    BOM操作
    事件绑定
    ajax请求(包括http协议)
    存储
    
    JS内置全局函数和对象
    JS变量中提到的和window,document,navigator等
    
  • JS(浏览器执行的JS)构成
    JS基础(ECMA262标准)
    JS-web-api(W3C标准)
    (服务器执行的js,如nodejs包含”ECMA262标准”,但不包含”W3C标准”)
  • DOM
    本质:浏览器把拿到的html文件结构化成浏览器和JS都可识别的模型,即为DOM
    数据结构:树结构
    节点操作:

    获取DOM节点
        document.getElementById('id') //元素
        document.getElementsByTagName('body')[0]; //集合
        document.getElementsByClassName('.con'); //集合
        document.querySelectorAll('p'); //集合
    prototype(JS对象属性)
        var pList = document.querySelectorAll('p');
        var p = pList[0]; //p为js对象
        console.log(p.style.width); //获取样式
        p.style.width =  '100px';  //修改样式
        console.log(p.className); //获取class
        p.className = 'p1';  //修改class
        //获取nodeName和nodeType
        console.log(p.nodeName); //P
        console.log(p.nodeType);
    Attribute(改html文档标签属性)
        var pList = document.querySelectorAll('p');
        var p = pList[0]; //p为js对象
        p.getAttribute('data-name');
        p.setAttribute('data-name','imooc');
        p.getAttribute('style');
        p.setAttribute('style','font-size:30px;');
    

    结构操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //新增节点
    var div1 = document.getElementById('div1');
    var p1 = document.createElement('p'); //创建新节点
    p1.innerHTML = 'this is p1';
    div1.appendChild(p1); //添加新节点到div1
    var p2 = document.getElementById('p2');
    div1.appendChild(p2); //移动已存在的节点p2到div1
    //获取父元素
    var parent = div1.parentElement;
    //获取子元素
    var child = div1.childNodes; //注意text节点
    var child = div1.childNodes[0].nodeType; // 3 (通用)
    var child = div1.childNodes[1].nodeType; // 1
    var child = div1.childNodes[0].nodeName; // #text (浏览器差异)
    var child = div1.childNodes[1].nodeName; // P
    //删除节点
    div1.removeChild(child[1]); //注意空text节点
  • BOM
    浏览器类型
    解析url
    内置对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //navigator
    var ua = navigator.userAgent; //此信息可被浏览器公司修改,不能保证真实性
    console.log(ua); //"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36"
    var isChrome = ua.indexOf('Chrome'); //简单判断浏览器
    //screen(获取屏幕像素,与浏览器缩放比有关,不同浏览器又有差异)
    console.log(screen.width); //1920(Edge,100%), 1536(Edge,125%), 1536(Chrome,控制台下调整缩放比无效)
    console.log(screen.height); //1080(Edge,100%), 864(Edge,125%), 864(Chrome)
    //location(浏览器会将url中的中文编码,以谷歌搜索vuejs为例,自定义hash:#123)
    console.log(location.href); // https://www.google.com/search?q=vuejs&oq=vuejs&aqs=chrome..69i57j0j35i39j0l2j69i65.1977j0j8&sourceid=chrome&ie=UTF-8#123
    console.log(location.protocol); // https:
    console.log(location.host); // www.google.com
    console.log(location.pathname); // /search
    console.log(location.search); // ?q=vuejs&oq=vuejs&aqs=chrome..69i57j0j35i39j0l2j69i65.1977j0j8&sourceid=chrome&ie=UTF-8
    console.log(location.hash); // #123
    //history
    history.back(); //前进
    history.forward(); //后退
  • 事件
    通用事件绑定:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var btn = document.getElementById('btn1');
    //IE低版本使用attachEvent绑定事件
    btn.addEventListener('click',function(event){
    console.log('clicked');
    })
    function bindEvent(ele,type,fn){
    ele.addEventListener(type,fn);
    }
    var a = docunment.getElementById('link1');
    bindEvent(a,'click',function(e){
    e.preventDefault(); //阻止默认事件
    e.stopPropatation(); //阻止事件冒泡
    alert('clicked');
    })

    事件冒泡(默认)

    Element.addEventListener('click',fn,false); //第三个参数不写默认为false,即默认冒泡
    点击子元素,会依次触发自身和父级元素的对应事件
    e.stopPropatation(); //阻止事件冒泡
    

    事件捕获

    Element.addEventListener('click',fn,true);
    点击子元素,如果父元素注册了事件捕获,则会先触发父元素事件
    

    代理(点击div1里面的多个a元素):代码简洁、减少浏览器内存占用

    1
    2
    3
    4
    5
    6
    7
    var div1 = document.getElementById('div1');
    div1.addEventListener('click',function(e){
    var target = e.target; //获取点击的html元素
    if(target.nodeName === 'A'){
    alert(target.innerHTML)
    }
    })
  • ajax

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    var xhr = new XMLHttpRequest;
    //open方法
    xhr.open('get,'/api',true); //默认异步true
    xhr.send(null);
    //post方法
    xhr.open('post','/api');
    xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    xhr.send('username=name&&pwd=123');

    xhr.onreadystatechange = function(){
    if(xhr.readyState == 4 && xhr.status == 200){
    alert(xhr.responseText);
    }
    }
    //readyState=0,(未初始化)还未调用send()方法
    //readyState=1,已调用send()方法,正在发送请求
    //readyState=2,send()执行完成,已收到全部响应内容
    //readyState=3,解析相应内容
    //readyState=4,完成解析,可调用
    //status=2XX,成功处理请求,(200)
    //status=3XX,需要重定向,浏览器直接跳转
    //status=4XX,客户端请求错位,(404)
    //status=5XX,服务器端错误

持续更新