zoukankan      html  css  js  c++  java
  • javascript 学习笔记

    1. typeof判断类型

    javascript 的原始类型包括:

    两个未定义类型:undefined,null;

    常用三种:number boolean string

    JavaScript的引用类型 object

    其中object包括了:function array date

    2

     

    问题三:

    3.1 如何判断一个变量是数组类型

    3.2 写一个原型链继承的例子

    3.3 描述 new 一个对象的过程

    3.4 zepto(或其他框架)源码中如何使用原型链

     背景知识介绍:

    // 构造函数 首字母大写 类似于模板
    
    function Foo(name,age){
        this.name = name;
        this.age = age;
        this.class = 'class-1';
        // return this //默认有这一行
    }
    // 每次new一个类的时候,this先变成空对象,然后在赋值this的name等值,最后在return 出来给new出来的f,则f.name=zhangsan
    var f = new Foo('zhangsan',20); //创建多个对象 var f1 = new Foo('lisi',22);

    所有的引用类型(数组/对象/函数),都具有对象特性,即可以自由扩展属性(除了null以外)如 var obj = {}; obj.a=1000;

    所有的引用类型(数组、对象、函数),都有一个 _proto_ (隐式原型)属性,属性值是一个普通的对象。

    所有的引用类型(数组、对象、函数),_propto_属性值指向它的构造函数的 “protptype”属性值

    其中this指向对象本身。

    上面f有三个属性: name,alertName,printName;

    为了拿到它自身的属性name,printName:

    例如在实例f中调用,本来没有定义过的 f.toString()方法,就按照下图所示,一级一级原型链的往上找:(注意Object的原型是null,避免导致死循环)

     instanceOf 用于判断 引用类型 属于哪个 构造函数的方法;

    判断f是否输入对象,首先根据原型链找到父级 Foo,无法判断,则再找上一级,一直找到Object

     

    或者把Animal类的方法提取出来:

    function Animal(){
    }
    
    Animal.prototype.eat = function(){
        console.log('eat');
    }
    
    function Dog(){
        this.bark = function(){
            console.log('dog bark');
        }
    }
    
    Dog.prototype = new Animal();
    
    var hashiqi = new Dog();
    
    hashiqi.bark();
    hashiqi.eat();

     

    zepto设计和源码分析

    写一个原型继承的例子:

    function Elem( id ){
        this.elem = document.getElementById(id);
    }
    
    Elem.prototype.html = function (val){
        var elem = this.elem;
        if(val){
            elem.innerHTML = val;
            return this; //链式操作
        }else{
            return elem.innerHTML;
        }
    }
    
    Elem.prototype.on = function (type,fn){
        var elem = this.elem;
        elem.addEventListener(type,fn);
        return this;
    }
    var div1 = new Elem('div1');
    div1.html('<p> hello </p>');
    div1.on('click',function(){
        alert('clicked');
    })
    /*可以链式操作:
    div1.html('<p> hello </p>').on('click',function(){
        alert('clicked');
    })*/

    问题四:

    4.1 说一下对变量提升的理解

    4.2 说明this几种不同的使用场景

    4.3 创建10个<a>标签,点击的时候弹出来对应的序号

    4.4 如何理解作用域

    4.5 实际开发过程中闭包的应用

    =======================

    4.1.1 执行上下文

    范围: 一段<script>或者一个函数

    全局:变量定义/函数声明

    函数:变量定义,函数声明/this/arguments

    console.log(a); //undefined
    var a = 100;
    
    fn('zhangsan'); //'zhangsan' 20
    function fn(name){
        age = 20;
        console.log(name,age);
        var age;
    }

    函数和变量的声明先提取到前面,不同的是变量的提升会用undefined占位,如 var a = undefined 占位,尚未执行到var a = 100 赋值;

    而函数声明会把整个函数先提取到前面:在执行到函数 fn(‘zhangsan’)的时候 在看函数内部: 首先提升age变量;

    4.2 this要在执行时才能确认值,定义时无法确认:

    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:一般是会被改变this的指向;

    function Foo(name){
        this.name = name;//这里的this表示实例化的f的属性:f.name
    }
    var f = new Foo('zhangsan');
    =============================
    var obj = {
        name:"aa",
        printName:function(){
            console.log(this.name);//这里的this表示obj
        }
    }
    obj.printName();
    =============================
    function fn(){
        console.log(this); //this===window
    }
    fn();
    =============================
    function fn1(name,age){
        alert(name);
        console.log(this);//下面使用的是call,所以改变了this的指向,指向了call的第一个对象
    }
    
    //fn1.call({x:1},'zhangsan',20);
    fn1.apply({x:1},['zhangsan',20]);//apply 和call类似,只不过第二个参数变成了数组
    
    ==============================
    var fn2 = function(name,age){//bind方法必须是函数表达式的形式
        alert(name);
        console.log(this);//如果不做call applay或bind的操作,这里的this指向window
    }.bind({y:200});//bind改变this的指向
    fn2('zhangsan',20);

     作用域:

    //无块级作用域,所以外面的name可以拿到这个数据     
    if(true){
        var name = "zhangsan"
    }
    console.log(name);
    
    ==========
    //函数和全局作用域
    var a = 100;//全局作用域
    function fn(){
        var a = 200;//函数作用域
        console.log('fn',a);
    }
    function fn1(){
        console.log('fn1',a);
    }
    console.log('global',a);//global 100
    fn();// fn 200
    fn1();// fn1 100

     作用域链:自由变量一直往上找

    //当前作用域没有定义的变量,即自由变量
    //注意的是定义的时候,而不是执行的时刻
    var a = 100;
    function F1(){
        var b = 200;
        function F2(){
            var c = 300;
            console.log(a);
            console.log(b);
            console.log(c);
        }
        F2();
    }
    F1(); 
    //结果是 100 200 300
    {
        var a = 100;
    }
    console.log(a); //可以获取到a
    
    
    function fn2(){
        var a = 100;
    }
    fn2();
    console.log(a);//获取不到a,是函数内部的局部变量

    4.3 创建10个<a>标签,点击的时候弹出来对应的序号

    因为变量i放在了全局作用域,每次循环之执行后,都会覆盖之前的值。

    而上述方法,每次循环都在一个函数体里,相当于局部作用域,i都是独立的。

    5. 异步

    5.1 同步和异步的区别是什么?分别举一个同步和异步的例子

    5.2 一个关于setTimeout的笔试题;

    5.3 前端使用异步的场景有哪些;

    (1)定时任务:setTimeout setInterval

    (2)网络请求: ajax请求,动态<img>标签

    (3)事件绑定

    例如:

    console.log('start');
    var img = document.createElement('img');
    img.onload = function (){
        console.log('loaded');//图片加载完才执行这里
    }
    console.log('end');

    执行顺序为:

    start--end--loaded

    5.4 获取2017-02-01格式的日期(视频4-5)

    5.5 获取随机数,要求是长度一致的字符串格式

    5.6 写一个能遍历对象和数组的通用forEach函数

    数组API:

    forEach 遍历所有元素
    
    every 判断所有元素是否都符合条件
    
    some 判断是否有至少一个元素符合条件
    
    sort 排序
    
    map 对元素重新组装,生成新数组
    
    filter 过滤符合条件的元素
    var arr = [1,2,3];
    arr.forEach((item,index)=>{
        console.log(item);
    });
    
    ==============
    var arr = [1,2,3,4];
    var result = arr.every((item,index)=>{
        //用来判断所有的数组元素,都满足一个条件,只要一个不满足,则返回false
        if(item<4){
             return true 
        }
    })
    console.log(result);//false
    ==============
    var arr = [1,2,3,4];
    var result = arr.some((item,index)=>{
        //用来判断所有的数组元素,只要有一个满足条件即可
        if(item<4){
             return true 
        }
    })
    console.log(result);//true
    ===============
    var arr = [1,4,3,5,2];
    var arr2 = arr.sort((a,b)=>{
        return a - b;//从小到大排序
        return b - a;//从大到小排序
    })
    console.log(arr2); 
    
    ===============
    //map和forEach不同在于可以返回生成一个新的数组
    var arr = [1,2,3,4];
    var arr2 = arr.map((item,index)=>{
        return '<b>'+item+'</b>'
    })
    console.log(arr2);
    //[ "<b>1</b>", "<b>2</b>", "<b>3</b>", "<b>4</b>" ]
    ============
    //类似的使用forEach则不会返回新数组
    var arr = [1,2,3,4];
    var arr2 = arr.forEach((item,index)=>{
        return '<b>'+item+'</b>'
    })
    console.log(arr); // [1,2,3,4]
    console.log(arr2);//undefined
    
    =============
    //类似的使用filter 也可以返回一个新的数组
    var arr = [1,2,3,4];
    var arr2 = arr.filter((item,index)=>{
        if(item>2){
            return true;
        }
    })
    console.log(arr2);//[3,4]
    =============
    //对象api
    var obj = {
        x:100,
        y:200,
        z:300
    }
    var key;
    for(key in obj){
        if(obj.hasOwnProperty(key)){//这里表示是obj的原生属性而不是集成父级
            console.log(key,obj[key]);
        }
    }

    forEach:

    6.1 通用事件绑定

    //简单来写
    var btn  = document.getElementById('btn1');
    btn.addEventListener('click',function(event){
        console.log('clicked')
    })
    
    //封装函数的形式
    function bindEvent(elem,type,fn){
        elem.addEventListener(type,fn);
    }
    var a = document.getElementById('link1');
    bindEvent(a,'click',function(e){
        e.preventDefault();//组织a标签的默认行为
        alert('click');
    })

    6.2 在一个不断动态增加<a>标签的区域,给a上绑定事件,如何做?

    <div id="div1">
        <a href="#">a1</a>
        <a href="#">a2</a> 
        <a href="#">a3</a> 
        <a href="#">a4</a> 
        <a href="#">a5</a>  
       ... </div>

    使用代理:也就是给包裹a标签的div增减点击的监听事件,如果点击的目标是a则触发事件。这样不用给每一项增加点击事件了。

    var div1= document.getElementById('div1');
    div1.addEventListener('click',function(e){
        var target = e.target;
        if(target.nodeName === "A"){
            alert(target.innerHTML)
        }
    })

    7 跨域。(所有的跨域请求必须经过信息提供方允许)

    可以允许跨域的有三个标签:

    <img src="xxx">, <link href="xxx">,<script src="xxx">

    JSONP的工作原理:  jsonp原理详解——终于搞清楚jsonp是啥了

    注意几点:

    1. 允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,
    这样客户端就可以随意定制自己的函数来自动处理返回数据了。
    2. 请求服务端地址,会动态生成一个js文件,包含了一个客户端提供的回调函数。

    <script>
        //这里定义回调函数
        window.callback = function (data){
            //这是我们跨域得到的信息
            console.log(data);
        }
    </script>
    <script src="http://www.coding.com/api.js"></script>
    <!--上面返回的是 回调函数的 执行  callback({x:100,y:200})-->

    也就是在服务器端返回的回调函数 让其执行。在客户端定义改回调函数。

    3 服务器端设置可以跨域:

    response.setHeader("Access-Control-Allow-Origin","http://a.com,http://b.com"); //允许的域名 或者是*
    response.setHeader("Access-Control-Allow-Headers","X-Requested-With"); //在服务器端判断request来自Ajax请求(异步)还是传统请求(同步): 
    response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); //请求方式
    response.setHeader("Access-Control-Allow-Credentials","true"); //接受跨域的cookies

    8 书写ajax的基本原理;

    要完整实现一个AJAX异步调用和局部刷新,通常需要以下几个步骤:

          (1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.

          (2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.

          (3)设置响应HTTP请求状态变化的函数.

          (4)发送HTTP请求.

          (5)获取异步调用返回的数据.

          (6)使用JavaScript和DOM实现局部刷新.

    var xhr = new XMLHttpRequest();
    xhr.open("GET","/api",false);
    xhr.onreadystatechange = function(){ //onreadystatechange  每次状态改变所触发事件的事件处理程序。
        //这里是函数异步执行
        if(xhr.readyState == 4){   
            if(xhr.status == 200){  //status 从服务器返回的数字代码,比如常见的404(未找到)和200(已就绪)
                alert(xhr.responseText); //responseText 从服务器进程返回数据的字符串形式。
            }
        }
    }
    xhr.send(null);
    //只有在使用send()方法之后,XMLHttpRequest对象的readyState
    //属性值才会开始改变,也才会激发readystatechange事件,并调用函数。

    对于XmlHttpRequest的两个方法,open和send,其中open方法指定了:

    a、向服务器提交数据的类型,即post还是get。

    b、请求的url地址和传递的参数。

    c、传输方式,false为同步,true为异步。默认为true。如果是异步通信方式(true),客户机就不等待服务器的响应;如果是同步方式(false),客户机就要等到服务器返回消息后才去执行其他操作。
    我们需要根据实际需要来指定同步方式,在某些页面中,可能会发出多个请求,甚至是有组织有计划有队形大规模的高强度的request,而后一个是会覆盖前一个的,这个时候当然要指定同步方式。

    readyState       对象状态值

        0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)

        1 (初始化) 对象已建立,尚未调用send方法

        2 (发送数据) send方法已调用,但是当前的状态及http头未知

        3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误,

        4 (完成) 数据接收完毕,此时可以通过通过responseXml和responseText获取完整的回应数据

    9.   cokie 用于存储的缺点
    1 存储量很小 只有4kb
    2 所有的http请求都会带着,会影响获取资源的效率
    3 api简单,需要封装才能使用 document.cookie="name="+username;

    10  localStorage 和 sessionStorage

    • Html5专门为本地存储而设计,最大容量是5M
    • API简单易用 localStorage.setItem(key,value),localStorage.getItem(key)
    • 目前所有的浏览器中都会把localStorage的值类型限定为string类型
    • localStorage在浏览器的隐私模式下面是不可读取的
    • localStorage与sessionStorage的唯一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对会被清空

    11 js 模块化的好处

    比如上面三个js文件 逐层引用;

     使用方式:

    所以用到模块化:

    12

    commonjs是用在服务器端的,同步的,如nodejs
    amd, cmd是用在浏览器端的,异步的,如requirejs和seajs
    其中,amd先提出,cmd是根据commonjs和amd基础上提出的。

    12.1 AMD模式:

    使用方式:

    12.2 CommonJS 规范

    CommonJS 属于 node.js 模块化规范,现在被大量用于前端,原因:
    1 前端开发依赖的插件和库,都可以从npm中获取;
    2 构建工具的高度自动化,使得使用npm的成本非常低;
    3 CommonJS 不会异步加载JS,而是同步一次性的加载出来,

     

     需要异步加载js 使用AMD

    使用了npm之后建议使用commonJS

  • 相关阅读:
    python 编码问题
    关于网页划词翻译
    clang 编译 c++
    Java流(Stream)操作实例筛选、映射、查找匹配
    JAVA系列笔记十八之nohup实现后台运行程序
    VSCode汇总
    java jdk 国内下载镜像地址及安装
    LocalDate、LocalDateTime与timestamp、Date的转换
    List.sort()排序功能
    Java Array、List、Set互相转化
  • 原文地址:https://www.cnblogs.com/xiaozhumaopao/p/10741075.html
Copyright © 2011-2022 走看看