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

posted @ 2019-04-20 15:20  小猪冒泡  阅读(194)  评论(0编辑  收藏  举报