JS系统学习

01、javascrip浏览器发展史

1.js的逼格(特点):

1.解释性语言

(不需要编译成文件直接执行)跨平台

2.单线程:同一时间只能做一件事——js 引擎是单线程
                 同一时间做很多事叫(多线程)

  同步:计算机所说的同步是现实中的异步执行

  异步:计算机所说的异步是现实中的同步执行

3.ECMA标注:

                                                        JavaScript

                ECMAScript                                                        WebAPIs

                                                                                  DOM                BOM

  1. js 是解释性语言:(不需要编译成文件)跨平台
  2. java 先通过 javac,编译成.class 文件,通过 jvm(Java 虚拟机)进行解释执行
    .java→javac→编译→.class→jvm→解释执行(java 可以跨平台)(java 是 oak 语言)
  3. link rel = “”是异步加载
  4. 单线程:同一时间只能做一件事——js 引擎是单线程
    (同一时间做很多事叫多线程)

2.浏览器的组成

1.shell部分

2.内核部分

        >渲染引擎(语法规则和渲染)

        >JS引擎

        >其他模块

3.主流浏览器

       浏览器                                                内核

        IE                                                     trident

        chrome                                            webkit/blink

        Firefox                                             Gecko

        opera                                               presto      

        Safari                                               webkit

02、 JS介绍入门,JS引入,变量,值类型,运算符

1.JS引入方法

1.页面JS(页面嵌套<script></script>标签)

  <script type="text/javascript">
    document.write('hello world!!!')
  </script>

小技巧:

(把type属性改为text/tpl故意让js运行不了把其当做一个库存)

  <script type="text/tpl">
    document.write('hello world!!')
  </script>

2.外部JS(外部引入<script src=“地址”></script>)

  <script type="text/javascript" src="lesson6.js"></script>

lesson6.js

 document.write('hello world')

为了符合web标注(w3c标准中的一项)结构、样式、行为相分离,通常会采用外部引入

解释:

        结构         样式        行为        相分离

        html           css          js

2.js基本语法

1.变量(存放数据,以便后续使用)

        >变量声明

  <script type="text/javascript">
    var b //变量声明
    var a = 100
  </script>

        >声明多个变量(单一var模式)

  <script type="text/javascript">
    var a = 10,
        b = 20,
        c = 30,
        d = 40,
        e
  </script>

命名规则

1.变量名必须以英文字母、_、$开头

2.变量名可以包括英文字母、_、$、数字

3.不可以用系统的关键字(有特殊语法含义)、保留字(未来可能会有含义的)作为变量名 

下面是变量,例:

var a = 10;
var b = 20;
var c;
c = a + b;

先运算等号右边的 a+b,运算完后,再赋值给左边 c
先取值,再赋值

2.基本语法

值类型——数据类型

        >不可改变的原始值(栈数据)

 Number       String        Boolean       undefined(声明一个变量没赋值)        null(占位用)

        > 引用值

array 数组, Object, function … data,RegExp 正则

  

var arr = [1,2,3,4,5,false,”abc”]; //这是数组
//例:
var arr = [1];
var arr1 = arr;
arr.push(2);
document.write(arr1);
//答案:arr 是 1,2   arr1 是 1,2

js 由值决定类型 

在这里插入图片描述
var a = 10;var b =a;是 a 先取出 10,copy 一份放到 b 里面,改变 a 的值,b 的值是不变的,再把 a=20;时 b 的值还是 10,不发生改变。

var arr = [1,2];
var arr1 =arr;
arr.push(3);
//答案:这往[1,2]放 3,arr 和 arr1 都是[1,2,3]

引用值是在栈内存里面放堆的地址,拷贝的也是地址,所以改变 arr,arr1 也变了

var arr = [1,2]; 
var arr1 =arr; 
arr = [1,3]; 
document.write(arr1)
//答案:arr = [1,3];

新建了一个新的房间。arr1 是 1,2,现在是插入新引入值”房间”,会在堆里面重新申请一间房,并指向新房间

3.js 语句基本规
  1. 语句后面要用分号结束“;”但 function test(){},for(){},if(){}后面都不用加分号
  2. js 语法错误会引发后续代码终止,但不会影响其它 js 代码块
  3. 书写格式要规范,“= + / -”两边都应该有空格
    错误分为两种
    1)低级错误(语法解析错误),不能写中文
    2)逻辑错误(标准错误,情有可原,错的那个执行不了)
4.js运算符 

运算操作符

1. +

  1. “+”作用:数学运算、字符串链接

  2. 任何数据类型加字符串都等于字符串

例 var a = “a”+ true + 1; //打印 atrue1
例 var a = 1 + “a” + 1 + 1; //打印 1a11
例 var a = 1 + 1 + “a” + 1 + 1; //打印 2a11,从左向右运算
例 var a = 1 + 1 + “a” +( 1 + 2); //打印 2a3

2. *、- 、/

例 var a = 0 – 1; //等于-1
例 var a = 2 * 1; //等于 2
例 var a = 0 / 0; //答案是 NaN,应该得出一个数字类型的数,但是没法表达,
就用 NaN (NaN 是 Not a Number 非数,不是数,但是是数字类型
例 var a = 1 / 0; //是 infinity
例 var a = -1 / 0; /是-infinity

3. %

摩尔,模,是取余数的意思

例 var a =5%2 //5%2 是五除二的余数,商二余一
例 var a =5%1 //是五除一的余数,结果是 0
例 var num = 1 % 5; //意思是 1 除以 5 的余数。商 0 余 1
例 var a =4%6 //是四除六的余数,结果是 4
例 var a = 4;a % = 5;document.write(a); // 4
例 var a = 0;a % = 5;document.write(a); //0
例 var a = 10;a %= 2;document.write(a); //0
例 var a = 3;a % = 4; //4

优先级”=“最弱【赋值符号优先级最低】,”()”优先级较高

4. ++

例 var a = 10; a = a + 1; //结果 11
例 var a = 1;

a = a + 1;写成 a ++是一种简化形式“++”,是自身加一,再赋值给自身
a++是 a=a+1 的简化形式

例 var a =10;document.write(++a );document.write(a); //答案 11;11
是先执行++,再执行本条语句 document.write(++a)
例 var a =1;document.write(a ++);document.write(a); //答案 1;2。是先执行
语句(document.write(a)),再++,所以第一次打印的还是 a,第二次打印 a++后的值
例 var a =10;var b=++a -1+a++;document.write(b + “ ” + a) //答案 21 12
先++a,这个时候 a=11,再-1,再加 a,b 就是 21,最后++,a 就是 12

赋值的顺序自右向左,计算的顺序自左向右(按数学来)

例 var a =1;var b = a ++ + 1;document.write(b); //答案 2,先执行 var b =a+1,
再 a++
例 var a =1;var b = a ++ + 1;document.write(a);document.write(b); //答案 2,2
例 var a =1;var b = ++a + 1;document.write(a);document.write(b); //答案 2,3
例 var i = 1;var a = i++; //答案 a = 1; 此时 i 先将值 1 赋给 a,然后自己+1,i=2;
var b = ++i; //答案 b = 3;此时 i 先自己+1 为 3.再给 b 赋值,b=3;

5. –

“- -”,是自身减一,在赋值给自身

例 var a = 1;var b = a-- + -- a;document.write(b); //答案 0,先执行--a;此时 a 变成
0,然后第一个 a 也变成 0,那么 b = 0-- + --a
例 var a = 1;var b = --a + --a;document.write(b); //答案-1
例 var a = 1;document.write(a++);document.write(a); //答案 1;2
例 var a = 1;document.write(++a);document.write(a); //答案 2;2
例 var a =1; var b = a ++ +1;document.write(b); //答案 2
a 写在后面就后运行,先计算 a+1=2 赋值给 b 后再++
例 var a = 1;var b= ++a + 1;document.write(a);document.write(b); //答案 2;3

6. += -=

例 var a =10;a ++;a ++;a ++;加十个
简化写法:a +=10;也是 a = a+10;
例 var a =10;a += 10 + 1; //答案 21
例 var a = 1;a = a + 10;等于 a+=10
a++是 a +=1 的写法

7. /=

例 var a=10;a/=2; //答案 5,是除二赋给自身的意思

8. *=

例 var a =10;a *=2; //答案:20,是乘二赋给自身的意思

9. %=

例 var a=10;a%=2; //答案:0, 10 能整除 2,余数是 0,取余,余数赋给自身。
例 var a=3;a%=4; //答案:3,3 除以 4,余数为 3,余数赋给自身。
例 var a=0;a%=4; //答案:0,0 除以 4,余数为 0,余数赋给自身。
例 var a = 1;a% =10; //答案:1,1 除以 10,余数为 1,余数赋给自身。

10.小测

法一:

var a = 123;
var b = 234;
var t;
t = a;
a = b;
b = t;

法二:

var a = 123;
var b = 234;
a = a + b;
b = a - b;
a = a - b;

03、比较运算符,逻辑运算符

1. 比较运算符

1、“>”,”<”,”==”,“>=”,“<=”,”!=”比较结果为 boolean 值

但凡是运算符,都是要有运算的
用到布尔值,true 或 false
字符串的比较,比的是 ASCII 码(七位二进制 0000000)

1.>, <
例 var a = "a">"b";document.write(a); //答案是 false
例 var a = 1 > 2;document.write(a); //答案是 false
例 var a = 1 < 2;document.write(a); //答案是 true
例 var a = "1">"8";document.write(a); //答案是 false
例 var a = "10">"8";document.write(a); //答案 false,不是十和八比,是字符串一
零和八比,先用开头的一和八比,比不过就不看第二位了;一样的就拿零和八比
例 var a = 123;document.write(a); //答案 false
运算结果为真实的值
2. = =,等不等于
例 var a = 1 == 2; //答案是说 1 等不等于 2,因为 1 肯定不等于 2,所以值为 false
例 var a = NaN == NaN; //答案是 false,NaN 不等于任何东西,包括他自己
例 var a = undefined == underfined; //答案是 true
例 var a = infinity == infinity; //答案是 true
例 var a = NaN == NaN; //答案是 false。非数 NaN 是不等于自己的
NaN 得不出数,又是数字类型,就是 NaN

3. >=,<=,!=是否不等于,非等

比较结果为 boolean 值:true 和 false

4. “&&”与运算符

两个表达式:先看第一个表达式转换成布尔值的结果是否为真,如果结果为真,那么它会看第二个表达式转换为布尔值的结果,然后如果只有两个表达式的话,只看第二个表达式,就可以返回该表达式的值了,如果第一位布尔值为 false,不看后面的,返回第一个表达式的值就可以了

例 var a = 1 && 2; //答案 2,如果第一位 1 为真,结果就为第二位的值 2
例 var a = 1 && 2 + 2; //答案 4,如果 1 为真,结果就为 4
例 var a = 0 && 2 + 2; //答案 0
例 var a = 1 && 1 && 8; //答案 8,先看第一个是否为真,为真再看第二个,
中途如果遇到 false,那就返回 false 的值
例 var a =1 + 1 && 1 – 1;document.write(a); //答案 0

如果是三个或多个表达式,会先看第一个表达式是否为真,如果为真,就看第二个
表达式,如果第二个也为真,就看第三个表达式(如果为真就往后看,一旦遇到假
就返回到假的值),如果第三个是最后一个表达式,那就直接返回第三个的结果
如果第一个是假,就返回第一个值,当是真的时候就往后走,一旦遇到假,就返回

例:2>1 && document.write(‘成哥很帅’) //意思是如果 2 大于 1,那么就打印成哥很帅,如果前面真才能执行后面的(相当于短路语句使用)

&&与运算符是有中断作用的,当短路语句使用(如果。。那么。。)

例 var data = ...; //执行一个语句,会用到 data
data&&执行一个语句全用到 data
例 data && function(data);
5.&与运算 我们一般不用
上下一与不同为0,相同为1
1在二进制中是1,(为了对齐补的0)01
3在二进制中是1111
运算结果01
例 var num = 1 & 2;document.write(num); //答案 0
例 var num = 1 & 1;document.write(num); //答案 1
例 var num = 1 & 3;document.write(num); //答案 1
6. “||”或运算符

看第一个表达式是否为真,如果为真,则返回第一个值,碰到真就返回
如果第一个表达式是假,就看第二个表达式,如果第二个是最后一个,就返回第二个的值

例 var num = 1 || 3; //答案 1
例 var num = 0 || 3; //答案 3
例 var num = 0 || false; //答案是 false

关于真假的说法:全假才为假,有一个真就为真

例 var num = 0 || false || 1;document.write(num); //答案 1
例 div .onclick = function(e){
 非 IE 浏览器直接取 e 值
 var event = e;
 IE 浏览器存在 window.event;
}
写成下面这样就解决了兼容性。在所有的浏览器中都好使
div .onclick = function(e){var event = e || window.event;}
7.“!“非运算符,否的意思。

先转成布尔值,再取反

例 var a = ! 123;document.write(a); //答案 false。123 的布尔值是 true,取反是 false
例 var a = ! “”;document.write(a); //答案 true。空串””布尔值是 false,取反是 true
例 var a = ! !“”;document.write(a); //答案 false,取反后,再反过来,结果不变
例 var a = true;a =!a;document.write(a) //答案 false,自身取反,再赋值给自身

被认定为 false 的值:转换为布尔值会被认定为 false 的值 undefined,null,NaN,
“”(空串), 0, false

04、条件语句和循环语句

1. If 语句 与&&

if(条件判断){
当条件成立时,执行里面的执行语句
}
当 if 的条件成立时,才能执行{}内的语句
当条件转化为布尔值,如果为 true 就执行;如果为 false 就不执行

例 if ( 1 > 0 && 8 > 9){}

&&放在 if 中的,全真才为真,&&是并且的意思

例 if ( 1 > 0 || 8 > 9){}

||放在 if 中是或者的意思,有一个是真就可以了

2.IF 和&&的互相转化

if (1 > 2) {
document.write.(‘a’);
}
上面与右边效果完全一样 1 > 2 && document.write(‘a’);

&&和 II 比较常用在条件判断中

3.for 循环(for 循环不固定,非常灵活)

格式 for (var i = 0; i < 10; i++) {}
for 是关键字,()括号里面三个语句用两个分号隔开,{}里面是循环体

打印十个a写成:
法一:
for(var i = 0; i<10 ; i++){
	console.log('a');
}
执行顺序如下:
(1)var i= 0;
(2)if(i <10){
 console.log(‘a’)
}
法二:
var i=0;
for(;i<10;){
	console.log('a');
	i++;
}
法三:
var i=1;
var count = 0;
for(; i ; ){
	console.log('a');
	count++;
	if(count == 10){
 	i=0;
 }
}
法四:
var i = 1;
for( ; i ; ){
	console.log('a');
	i++;
	if(i==11){
		i=0;
		}
}

把条件判断放到 if 里面,条件判断成立,就执行{}中间的执行体

4.while, do while
  1. while 循环是 for 循环的简化版 for( ; ; ){},while 循环底层机制是 for 循环。
    for ( ; 只在这一部分写,前后不写 ; ){}
    在这里插入图片描述
  2. do while 是不管满不满足条件都会先执行一次,再判断成不成立,如果成立才会执行第二次,不成立就停止 一般没人用
do{
document.write('a');
 i ++;
}while(i < 10)
5.作业

1.

    let n = window.prompt('input');
    let result = 1;
    for (let i = 1; i <= n; i++) {
      result *= 2;
    }
    document.write(result);

2.

    let n = window.prompt('input');
    let result = 1;
    for (let i = 1; i <= n; i++) {
      result *= i;
    }
    document.write(result)

3.

法一: 

    let n = parseInt(window.prompt('input'))
    let arr = [1, 1];
    for (let i = 1; i < n; i++) {
      arr[i + 1] = arr[i] + arr[i - 1]
    }
    document.write(arr[n - 1])

 法二:

    let n = parseInt(window.prompt('input'))
    let f = 1,
      s = 1,
      t;
    if (n > 2) {
      for (i = 2; i < n; i++) {
        t = f + s;
        f = s;
        s = t;
      }
      document.write(t);
    }
    else {
      document.write('1')
    }

4.

    let n = parseInt(window.prompt('请输入一个三位数的正整数'));
    while (n > 0) {
      let t = parseInt(n % 10);
      document.write(t);
      n = parseInt(n / 10);
    }

 5.

    let a = +window.prompt('a');
    let b = +window.prompt('b');
    let c = +window.prompt('c');
    let max;
    if (a > b) {
      if (a > c) {
        max = a;
      } else {
        max = c;
      }
    } else {
      if (b > c) {
        max = b;
      } else {
        max = c;
      }
    }
    document.write(max)

6. 

    let count = 0;
    for (let i = 1; i < 100; i++) {
      for (let n = 1; n <= i; n++) {
        if (i % n == 0) {
          count++;
        }
      }
      if (count == 2) {
        document.write(i + ' ');
      }
      count = 0;
    }
6.switch case 条件判断语句
if(条件判断)
switch(条件){
 case 写条件:里面判是否相符:
如果相符合就执行 case 后面的语句比如 console.log(‘a’)
}

switch 不负责任,如果判断了 a 是符合条件的,也会把后面的连带打印出来(穿透)
加个 break,就可以终止语句

7.break
var i = 0;
while(1){
	i++;
	console.log(i)
	if(i>100){
	break;
	}
}

break终止的是while,对if没有影响(break只能终止循环)

8.continue 继续

终止本次循环,后面的都不执行了,来进行下一次的循环

js 里面是没有 goto 的,c 语言里面有

例当 i 是 7 的倍数,或尾数是 7 的时候,不打印

for ( var i = 0; i < 100; i++){
 if( i % 7 == 0 || i % 10 == 7){
}else{
console.log(i);
}
}
下面的写法更好
for ( var i = 0; i < 100; i++){
 if( i % 7 == 0 || i % 10 == 7){
 continue;
}
console.log(i)
}

05.初始引用值

1.数组

例 var arr = [1,2,3,4,5,6,7,”abc”,undefined];

arr [0] 代表查数组的第一位,因为计算机是从 0 开始的算的
arr [0] = 3; 是指把数组的第一位改成 3,显示 3,2,3,4,5,6,7, ”abc”,undefined
arr.length;是数组的长度,有多少位就有多少
console.log(arr.length); //答案是 8 位

例:利用 for 循环把数组中的每一位都拿出来——遍历

var arr = [1,2,3,4,5,6,7,”abc”,undefined];
for (var i = 0 ;  i < arr.length ; i++){
	console.log(arr[i])
}

例:把数组中的每一位都改成 1

var arr = [1,2,3,4,5,6,7,”abc”,undefined];

for ( var i = 0 ; i < arr.length ; i++){
	arr[i]=1;
} 

例:把数组中的每一位都加 1

var arr = [ 1 , 2 , 3 , 4 , 5 ,6 , 7]
for (var i =  0 ; i < arr.length ; i++){
	arr[i]+=1
}

2. 对象 object

1.面向对象的编程方法

var obj = {
里面存属性和方法
key 属性名:value 属性值;
}

1在{}面用。属性与属性之间用逗号隔开
2属性值可以双引号或单引号;属性名是为了方便找到他,只是一个辅助

在这里插入图片描述

06、编程形式的区别

1.面向过程,如 c
第一步干嘛,第二步干嘛
2.面向对象(对象 object)
现在 js 是一半面向过程,一半面向对象,前面学的都是面向过程

07、typeof 操作符

typeof 能返回的六种数据类型(区分数字类型)
number、string、boolean、undefined、object、function

例 var num = 123;console.log(typeof(num)); //返回 number
写成 console.log(typeof num );//也可以不过最好加括号
例 var num = {}; console.log(typeof(num)); //泛泛的引入值都返回 object
例 var num = [];console.log(typeof(num)); //泛泛的引入值都返回 object
例 var num = null;console.log(typeof(num)); //答案 null 返回 object,最早是代替空对象的
例 var num = undefined;console.log(typeof(num)); //答案返回 undefined
例 var num = fuction(){};console.log(typeof(num)); // 答案返回 function

typeof 返回的 值是string类型

08、类型转换

例 var num = 1 +“1”; //显示 11
例 var num = 1 *“1”;console.log(typeof(num) + “:” + num); //显示 number:1
例 var num = 1 -“1”;console.log(typeof(num) + “:” + num); //显示 number:0
例 var num = “2” -“1”;console.log(typeof(num) + “:” + num); //显示 number:1
例 var num = “2” *“1”;console.log(typeof(num) + “:” + num); //显示 number:2

以上例子说明 js 有类型转换

1. 显示类型转换

1.Number(mix) 是想把里面的东西转换成数字
例 var num = Number(‘123’);
console.log(typeof(num) + “:” + num);
答案显示 Number:123,把字符串类型的 123 转换成了 number 类型
例 var demo = “123”;
var num = Number(demo); 
console.log(typeof(num) + “:” + num);
答案显示 Number:123,上面那一行的 Number 是为了把()里面转换成数字类型
例 var demo = true;
var num = Number(demo); 
console.log(typeof(num) + “:” + num);
答案显示 Number:1
例 var demo = false;
var num = Number(demo); 
console.log(typeof(num) + “:” + num);
答案显示 Number:0
例 var demo = null;
var num = Number(demo); 
console.log(typeof(num) + “:” + num);
答案显示 Number:0
例 var demo = undefined;
var num = Number(demo); 
console.log(typeof(num) + “:” + num);
答案显示 Number:NaN
例 var demo = “abc”;
var num = Number(demo); 
console.log(typeof(num) + “:” + num);
答案显示 Number:NaN
例 var demo = “-123”;
var num = Number(demo); 
console.log(typeof(num) + “:” + num);
答案显示 Number:-123
例 var demo = “123abc”;
var num = Number(demo); 
console.log(typeof(num) + “:” + num);
答案显示 Number:NaN

2.parseInt(string,radix)

parse 是转化,Int 是整型,整数,目的是把里面转换成整数

例 var demo =”123”;
var num = parseInt(demo);
console.log(typeof(num) + “:” + num);
答案显示 number:123
例 var demo = true;
var num = parseInt(demo);
console.log(typeof(num) + “:” + num);
答案显示 number: NaN
例 var demo = false;
var num = parseInt(demo);
console.log(typeof(num) + “:” + num);
答案显示 number: NaN
例 var demo = 123.9;
var num = parseInt(demo);
console.log(typeof(num) + “:” + num);
答案显示 number: 123,此处是直接去掉小数,不是四舍五入
例 var demo = “10”;
var num = parseInt(demo ,16);
console.log(typeof(num) + “:” + num);
答案显示 number: 16

var num = parseInt(demo ,radix); //radix 是基底的意思
radix 写成 16,系统会认为是以 16 进制为基底, 10(一零)是 16 进制的一零,是
以 16 进制为基底,把他转成为 10 进制的数字(就是 16),上面是以目标进制为基底,
转换成十进制(radix 范围是 2-36)

例 var demo = “3”;
var num = parseInt(demo ,2);
console.log(typeof(num) + “:” + num);
答案显示 number: NaN
例 var demo = “b”;
var num = parseInt(demo ,16);
console.log(typeof(num) + “:” + num);
答案显示 number: 11
例 var demo = “123abc”;
var num = parseInt(demo);
console.log(typeof(num) + “:” + num);
答案显示 number: 123
例 var demo = “100px”;
var num = parseInt(demo);
console.log(typeof(num) + “:” + num);
答案显示 number: 100

parseInt 从数字类开始看,看到非数字类为止,返回原来的数

3.parseFloat(string)

parseFloat(string)转换成浮点数字,就是正常小数

例 var demo = “100.2”;
var num = parseFloat (demo);
console.log(typeof(num) + “:” + num);
答案显示 number: 100.2
例 var demo = “100.2.3”;
var num = parseFloat (demo);
console.log(typeof(num) + “:” + num);
答案显示 number: 100.2
例 var demo = “100.2abc”;
var num = parseFloat (demo);
console.log(typeof(num) + “:” + num);
答案显示 number: 100.2

parseFloat 从数字类开始看,看到除了第一个点以外的非数字类为截止,返回前面的数

4.toString
例 var demo = 123;
var num = demo.toString();
console.log(typeof(num) + “:” + num);
答案显示 string: 123。相当于把 123 转换字符串。

想把谁转换成字符串,就写成谁.toString,上面是想把 demo 转换成 toString,写成
demo.toString

demo.toString(radix)可以把10进制转换成目标进制

例 var demo = undefined;
var num = demo.toString();
console.log(typeof(num) + “:” + num);
答案显示报错,undefined 和 null 不能用 toString
例 var demo = 123;
var num = demo.toString(8);
console.log(typeof(num) + “:” + num);
答案 173,把 123 转成为八进制
这里的 radix 意思是以十进制为基底,转换成目标进制(即 8 进制)
例 var demo = 10;
var num = demo.toString(8);
console.log(typeof(num) + “:” + num);
答案 12
例 var demo = 20;
var num = demo.toString(8);
console.log(typeof(num) + “:” + num);
答案 24。以十进制为基底,把 20 转换成 8 进制,就是 24
例给你一个二进制的数,转换成十六进制,是先从二进制到十进制再到十六进制
var num = 10101010;
var test = parseInt(num, 2);
console.log(test.toString(16));
答案 aa
例 var num = 10000;
var test = parseInt(num, 2);
console.log(test.toString(16));
答案 10

undefined 和 null 不能用 toString

5.String(mix)

String(mix)转换成字符串,写什么都成了字符串

例 var demo = 123.234;
var num = String (demo);
console.log(typeof(num) + “:” + num);
答案显示 string: 123.234
例 var demo = undefined;
var num = String (demo);
console.log(typeof(num) + “:” + num);
答案显示 string: undefined
6.Boolean()

Boolean()转换成布尔值 false 和 true

例 var demo = “”;
var num = String (demo);
console.log(typeof(num) + “:” + num);
答案显示 boolean: false

2. 隐式类型转换

  1. 隐式类型转换是跟你转换了也不知道
  2. 隐式类型转换内部隐式调用的是显示的方法
  3. 隐式类型转换包括 isNaN () ,++,–, +/-(一元正负),+,*,% ,,&&,|| ,!,
    <,>,<= ,>= ,== ,!=
1. isNaN ();

isNaN ();当你把一个数放到()里,它能判断是不是 NaN,先比括号里面的放到 number里面转换,然后返回来

例 console.log(isNaN(NaN); //答案 true
例 console.log(isNaN(“123”); //答案 false
例 console.log(isNaN(“abc”); //答案 true。会调用 number,先把“abc”
放 number 里面转换,通过 number 的转换再和 NaN 比对,如果相等就是 true
例 console.log(isNaN(null); //答案 false,在 number 里面放 null 是 0,不是 NaN
例 console.log(isNaN(undefined); //答案 true
2.++/–(加加减减) +/-(一元正负)
例 var a = “123”;
a ++;
答案 124,++这个符号放到这里,还没运算之前,先把前面的 a 转换成 number 的 123
例 var a = “abc”;
a ++;
答案 NaN

+/-(一元正负)
+a;-a;正 a 和负 a 都会变换成数字

例 var a =+”abc”;
console.log(a + “:” + typeof(a));
答案 NaN:number。

尽管转换不成数字,也会转换成数字类型,因为里面隐式的调用
了一个 number

3. +

+隐式类型会转换成 string,当加号两侧有一个是字符串,就用调用 string,把两个都变成字符串

例 var a = “a” +1
console.log(a + “:” + typeof(a));
答案:a1:string
4. * %

*和% 乘和模都会转换成 number.

例 var a = “1” *1; console.log(a + “:” + typeof(a));
答案 1:number
例 var a = “a” *1; console.log(a + “:” + typeof(a));
答案 1:number,先是 number(“a”)的结果乘以 number(1)的结果,最后是 NaN*1,
还是 NaN,但是数据类型是 number
5. && || !

与或非,都是有类型转换的,不过是返回的是表达式的值,不是隐士类型转换的值,但是判断是一个类型转换的值

6. < > <= >=
例 var a =1 > “2”; console.log(a + “:” + typeof(a));
答案 false:boolean,有数字相比较的,就会隐士类型转换成数字类型
例 var a =”3” > “2”; console.log(a + “:” + typeof(a));
答案这个没类型转换,这个比的是 ASCⅡ
例 var a =”3” > 2; console.log(a + “:” + typeof(a));
答案 true:boolean 会转换成数字,因为数字优先
7.== !=
例 var a = 1 == “1”; console.log(a + “:” + typeof(a));
答案 true:boolean,也有隐士类型转换
例 var a = 1 == true; console.log(a + “:” + typeof(a));
答案相等
!=也是这样

特殊的东西在控制台操作

例 false>true //答案 false,会先转换成数字,0>1 当然是错的
例 2>1>3 //答案 false
例 2>3<1 //答案 true
例 10>100>0 //答案 false
例 100>10>0 //答案 true

以上都是挨个算的,先看前面的是 true 还是 false,再和后面的比,不是顺着下来

例 undefined>0 //答案 false
例 undefined==0 //答案 false
例 undefined<0 //答案 false
例 null>0 //答案 false
例 null==0 //答案 false
例 null<0 //答案 false
例 undefined == null //答案 true
例 NaN ==NaN //答案 false,NaN 是唯一一个连自己都不等于的

3. 不发生类型转换

1.绝对等于(三个等号) !==绝对不等于
例 1 === 1 //答案 true
例 1 === “1” //答案 false
例 1 !== “1” //答案 true
例 1 !== 1 //答案 false
例 NaN =NaN //答案 false 特殊的
例 console.log(a); //如果定量没定义就直接访问,就 a is not defined 报错;
有一种特殊情况,当且仅当把未定义的变量放到 console.log(typeof(a));里面就访问,
不报错,返回 undefined
例 console.log(typeof(a)); //答案 undefined,这个 undefined 是字符串
例 console.log(typeof(typeof(a))); //答案 string。console.log(typeof(typeof(a)));
可以先解析成 console.log(typeof(“undefined”));再返回一次就是 string 字符串

上面考的是 typeof(a)返回的六种类型的值(number、string、boolean、undefined、object、function)都是 undefined 字符串

4.作业

    alert(typeof (a));//string 
    alert(typeof (undefined));//undefined
    alert(typeof (NaN));//number
  X alert(typeof (null));//object
    alert(typeof (NaN));//number
    var a = "123abc";
    alert(typeof (+a));//number
  X alert(typeof (!!a));//boolean
    alert(typeof (a + ""));//string
    alert(1 == "1");//true
    alert(NaN == NaN);//false
    alert(NaN == undefined); //false
    alert("11" + 11); //1111
    alert(1 === "1");//false
    alert(parselnt("123abc"));//123【parseInt 是截断数字】
    var num = 123123.345789;
    alert(num.toFixed(3));//123123.346【toFixed(3)是保留三位小数的意思,四舍五入】
    typeof (typeof (a));//string

09. 函数function

function 随便起个名(){}
在这里插入图片描述
以上情况就是偶合,偶合度非常高,偶合代码就是低效代码
编程讲究高内聚,弱偶合
右上方是简便写法:可以用 test 调用执行,写几个 test 就调用执行几次

function text() {
	var a = 123;
	var b = 234;
	var c = a+ b;
	console.log(c)
} 
test()

答案 357。写了一个 test();就执行了一遍函数语句,如果不写 test();就相当于有一个框来存东西,但是不执行

1.定义

定义一个函数可以先写一个 function,函数就是另一个类型的变量
我声明一个函数 test,test 是函数名。写成下面
function test(){
函数体
}

例 function theFirstName(){}
document.write(theFirstName);
答案 function theFirstName(){}。打印出来的是函数体
这与 c 语言和 c++,他们打印指针,会输出指针的地址,而 js 这种弱数据语言(解
释性语言)永远不输出地址,输出地址指向房间

函数名起名:开发规范要求,函数名和变量名如果由多个单词拼接,必须符合小驼
峰原则(第一个单词首字母小写,后面的首字母大写)

2.函数表达式

例 var test = fuction test (){
document.write(‘a’);
}
test();
答案 a。这种方式像定义一个变量
上面这种方式,可以演变成第三种,匿名表达式【不写 test 这种函数名】
例 var demo = fuction (){
document.write(‘a’);
}
(1)命名函数表达式
var test = function abc() {
	console.log('a');
}

在这里插入图片描述

上面这个函数的函数名 name 是 abc
在控制台 console 直接输出 test 就会出现
在控制台 console 直接输出 abc 会报错,表达式就会忽略他的名字 abc。
在上面例子中,fuction abc(){document.write(‘a’);}这一部分叫表达式,是会忽略
abc 这个地方的名字,会变成匿名函数表达式,不如直接写成匿名函数

(2)匿名函数表达式(常用,一般说的函数表达式就是匿名函数表达式)

function test() {}
test.name 输出 test

3. 组成形式

1、函数名称

function test(){}其中 function 是函数关键字,test 是函数名,必须有(){},参数可有可
没有,参数是写在()括号里面的。
如果写成 function test(a,b){},相当于隐式的在函数里面 var a,var b 申明了两个变
量,()括号里面不能直接写 var

例 function test(a, b){
 document.write(a + b)
}
test(1, 2)
答案 3。上面这个例子,1 就会到 a 里面去,2 就会到 b 里面去,这是传参的形式
2、参数(可有可没有,但是高级编程必有)

(1)形参(形式参数):指的是 function sum(a,b){}括号里面的 a 和 b
(2)实参(实际参数):指的是 sum(1,2);里面的 1,2

天生不定参,形参可以比实参多,实参也可以比形参多

function sum(a,b){
	var c =  a + b;
	console.log(c)
};
sum(1,2)
sum(3,4)
答案 3   7,参数把函数抽象了,可以组成很多形
例 function sum(a,b){
 document.write(a);
}
sum(11, 2, 3)
答案 11 
例 function test(a, b, c,d) {
 document.write(a);
document.write(d);
}
sum(11, 2, 3)
答案 11,undefined,上面这道题是形参多,实参少

js 参数不限制位置,天生不定参数
在每一个函数里面都有一个隐式的东西 arguments 这个是实参列表

console.log();是把信息展示在控制台
document.write();是把信息展示到网页

例 function test(a) {
 console.log(arguments);
 console.log(arguments.length);
}
sum(11, 2, 3)
答案[11, 2, 3],3
例 function test(a) {
 for(var i = 0; i < argument.length; i++){
 console.log(arguments[i]);
 }
}
sum(11, 2, 3)
答案 11,2,3

例:形参长度求法

function sum(a, b, c, d) {
 console.log(sum.length);
 }
sum(11, 2, 3)
答案 4

例任意个数求和(不定参才能求出来)

function sum () {
	var result= 0;
	for (var i = 0;i<arguments.length;i++)|
		results + = arguments[i]
	} 
	consoel.log(result)
}
sum(1,2,3,4,5,6,7,8,9)

形参永远有尽头,要实现任意的数求和,无法定义形参。

function sum (a,b){
	//arguments [1 , 2 ]
	a = 2 ;
	console.log(arguments[0])  
}
sum (1,2)
//答案是2,a变,arguments跟着变,有一个映射关系。
function sum (a,b){
	//arguments [1, 2 ]
	//var a = 1;
	a= 2;
	arguments[0] = 3 ; 
	console.log(a) 
}
sum (1,2)
答案是3,arguments里面一个变,一个跟着变,但【1,2】是两个人的,相当于映射关系

例当形参两个,实参一个

function sum(a, b){
//arguments[1]没值
 b = 2;
 console.log(arguments[1]);
}
sum(1);
答案 undefined,实参列表出生时有几个,就有几个,在写 b=2,也不加在 arguments[1]
里面了,此处的 b 就当变量用,他和实参不映射。

4. 返回值 return

结束条件和返回值 return,return 有终止函数的功能
没写 return,实际上是加上了一个隐式的 return

例 function sum(a, b){
 console.log(‘a’);
 console.log(‘b’);
 return;
}
答案 a,b
例 function sum(a, b){
 console.log(‘a’);
return;
 console.log(‘b’);
}
答案 a

return 最常用的是返回值。本意是把一个值返回到函数以外

自己定义的函数也能返回,return 空格 123

例 function sum(){
 return 123;
 console.log(‘a’)
 }
var num = sum();
答案这里的 num 就是 123,而且 console.log(‘a’);无效,这里的 return 又终止函数,又返回变量

例把 target 转成数字

例把 target 转成数字
function myNumber(target){
 return +target; //利用+隐式的转换成了数字类型
}
var num = myNumber(‘123’);
console.log(typeof(num) + “” + num);
答案 number 123

一般函数处理完一个参数,是为了返回
typeof()也是返回值,也是函数
typeof(123)也可以写成 typeof 123【typeof 空格 123】,只是看起来不方便

10.作用域初探

1.作用域定义

变量(变量作用于又称上下文)和函数生效(能被访问)的区域全局、局部变量

作用域的访问顺序
作用域:函数里面的可以访问外面的全局变量

函数外面不能用函数里面的。里面的可以访问外面的,外面的不能访问里面的,彼此独立的区间不能相互访问

例 function test(){
 var a =123;
 function demo(){
var b = 234;
document.write(a);
}
demo();
document.write(b);
}
上面的 document.write(b);不能访问 var b ,
上面的 document.write(a);可以访问 a

外层函数不能访问里层的,里层的可以访问外层的,越往里权限越大

2.js 运行三部曲

1 语法分析 → 2 预编译 → 3 解释执行

3.预编译前奏

例 function test(){
 console.log(‘a’);
}
test();
上面能执行
例 test();
function test(){
 console.log(‘a’);
}
也能执行,因为有预编译的存在
例 var a = 123;
console.log(a);
答案 123
例 console.log(a);
var a = 123;
答案 undefined
例只写 console.log(a);就会报错

函数声明整体提升:函数不管写到哪里,都会被提到逻辑的最前面。所以不管在哪里调用,本质上都是在后面调用

变量声明提升:把 var a 提升到最前面
var a = 123;这是变量声明再赋值。
变量 声明提升是把他拆分成 var a; a = 123;然后把 var a 提升到最前面
上面这两句话没办法解决下面例子的问题

例 function a(a){
var a = 234;
var a = function(){
}
a();
}
var a =123;
  1. imply global 暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为全局对象(就是 window)所有。
例 window.a = 10;
例 a = 10; ===> windows.a = 10;
  1. 一切声明的全局变量,全是 window 的属性。
例 var a = 123; ===> window.a = 123;
  1. window 就是全局的域
    如果在全局变量在 var a = 123;那么就会返回到 window
例 var a = 123
console.log(a) ===> window.a
例 var a = b = 234;是把 234 的值赋给 b,在把 b 的值赋给 a
例 function test(){
 var a = b = 123;
}
test()
写 test()代表执行 test,赋值是自右向左的,上面先把 123 赋给 b 的时候,b 未经声明,
然后再声明 a,再 b 的值赋给 a,导致 b 未经声明,所以 b 归 window 所有
访问 window.a 是 undefined,访问 window.b 是 123
例 function test(){
 var b = 123;
}
test();
console.log(window.b);
答案 undefined
window 就是全局
例 var a = 123;
console.log(a); → console.log(window.a);
例 var a = 123;
var b = 234;
var c = 345;
window{
 a : 123,
 b : 234,
 c : 345
}
如果 var a 对应会有 window.a

4.预编译(解决执行顺序问题)

例 function fn(a){
 console.log(a);
 var a = 123;
 console.log(a);
 function a (){}
 console.log(a);
 var b = function (){}
 console.log(b);
 function d() {}
}
fn(1);
答案是 function a(){}//123//123//function (){}

这个例子的形参是(a),变量声明也是 a
上面的例子按四部曲变化如下:
找形参和变量声明,将变量和形参(a)名作为 AO 属性名,值为 undefined ,AO{
a : undefined,
b : undefined,
}
(把实参值传到形参里)AO{
a : 1
b : undefined,
}
function a () {}和 function d () {}都是函数声明,但是 var b = function (){}不是。AO{
a : function a () {},
b : undefined,
d : function d () {}
}
执行第一行 console.log(a);时,用的是 AO{
a : function a () {},
b : undefined,
d : function d () {}
}
执行 var a =123;改变的是 AO{
a : 123,
b : undefined,
d : function d () {}
}
在 b = function (){}时 AO{
a : 123,
b : function () {},
d : function d () {}
}
预编译发生在函数执行的前一刻

5.(函数)预编译的四部曲:

1.创建 AO 对象 Activation Object(执行期上下文,作用是理解的作用域,函数产生的执行空间库)
2.找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined
相当于 AO{
a : undefined,
b : undefined
}
3.将实参值和形参统一(把实参值传到形参里)
4.在函数体里面找函数声明,值赋予函数体
(先看自己的 AO,再看全局的 GO)

例子 function test (a, b){
 console.log(a);
 c = 0;
 var c;
 a = 3;
 b = 2;
 console.log(b);
 function b (){};
 function d (){};
 console.log(b);
}
test(1);
答题过程:找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined, AO{
 a : 1,
 b : undefined,
 c : undefined
}
函数声明 function b(){}和 function d(){},AO{
 a : 1,
 b : function b(){},
 c : undefined,
 d : function d(){}
}
执行 console.log(a);答案是 1
执行 c = 0;变 AO{
 a : 1,
 b : function b(){},
 c : 0,
 d : function d(){}
}
var c 不用管,因为 c 已经在 AO 里面了
执行 a = 3;改 AO{
 a : 3,
 b : function b(){},
 c : 0,
 d : function d(){}
}
执行 b = 2;改 AO{
 a : 3,
 b : 2,
 c : 0,
 d : function d(){}
}
执行 console.log(b);答案是 2
function b () {}和 function d(){}已经提过了,不用管
执行 console.log(b);答案是 2

例 function test(a , b){
 console.log(a);
 console.log(b);
 var b = 234;
 console.log(b);
 a = 123;
 console.log(a);
 function a (){}
 var a;
 b = 234;
 var b = function(){}
 console.log(a);
 console.log(b);
}
test(1);

一旦有重名的,一但有 a 变量又有 a 函数【如 function a (){}】,又在第一条访问的是a,一定是函数

答题过程: 将变量和形参名作为 AO 属性名,AO{
a : undefined,
b : undefined
}
将实参值和形参统一,AO{
a : 1,
b : undefined
}
找函数声明 function a (){},AO{
a : function a (){},
b : undefined
}
执行 console.log(a);答案是 function a (){}
执行 console.log(b);答案是 undefined
执行 var b = 234;变 AO{
a : function a (){},
b : 234
}
执行 console.log(b);答案是 234
执行 a = 123;变 AO{
a : 123,
b : 234
}
执行 console.log(a);答案是 123
然后 function a (){};var a ;都可以不看了
执行 b = 234,b 值还是 234,不变
执行 var b = function (){},变 AO{
a : 123,
b : function (){}
}
执行 console.log(a);答案是 123
执行 console.log(b);答案是 function (){}

6.全局的预编译

例 console.log(a);
var a = 123;
答案 undefined
例 console.log(a);
var a = 123;
function a (){}
答案是打印 a 是 function a (){}

7.全局的预编译三部曲:

1、生成了一个 GO 的对象 Global Object(window 就是 GO)
2、找形参和变量声明,将变量和形参名作为 GO 属性名,值为 undefined
3、在函数体里面找函数声明,值赋予函数体

例 console.log(a);
var a = 123;
function a (){}
答案过程,GO{
 a : undefined
}
函数声明 GO{
 a : function a (){}
}
执行 var a = 123;变 GO{
 a : 123
}
执行 console.log(a);就是 123
GO === window, GO 和 window 是一个东西
console.log(a);和 console.log(window.a);和 console.log(go.a);是一样

1.任何全局变量都是 window 上的属性
2.没有声明就是赋值了,归 window 所有,就是在 GO 里面预编译

例 function test(){
 var a = b =123;
 console.log(window.b);
}
test();
答案 a 是 undefined,b 是 123
先生成 GO{
 b : 123
}
再有 AO{
a : undefined
}

先生成 GO 还是 AO?
想执行全局,先生成 GO,在执行 test 的前一刻生成 AO
在几层嵌套关系,近的优先,从近的到远的,有 AO 就看 AO,AO 没有才看 GO

例 console.log(test);
function test(test){
 console.log(test);
 var test = 234;
 console.log(test);
 function test(){
}
}
test(1);
var test = 123;

答题过程:想执行全局,先有 GO,GO{
 test : undefined
 }
发现有函数声明 GO{
 test : function (){
..... }
}
执行 console.log(test)
,
执行 test(1)之前生成 AO{
 test : function (){} }
执行 var test = 234;变成 234
AO 上面有就用 AO 的,没有就看 GO
的
例 var global = 100;
function fn(){
 console.log(global); }
fn(); 答题过程 GO{
 global : undefined,
 fn : function(){.....} }
执行 var global = 100;
变 GO{
 global : 100,
 fn : function(){.....} }
不看 function fn(){...}里面的东西
执行 fn()之前 AO{
 访问 GO
的 global
}

例子:
global = 100 
function fn(){
	console.log(global)
	global=200
	console.log(global)
	var gloval = 300 ;
}
fn();
var global;
答题过程,GO{
 global : undefined
 fn : undefined(没用可以不写
)
}变 GO{
 global : 100
 fn : undefined }
执行 fn()之前,AO{
 global : undefined }
执行结果是 undefined
,200

例子:
function test(){
	console.log(b)//undefined
	if(a){
	var b = 100;
}
console.log(b) //undefined
c=234;
console.log(c)//234
}
var a ;
test()
//AO{
// b:undefined
//}
a=10;
console.log(c);//234

例现在在 if 里面定义函数声明 function 是不允许的,但是过去可以,下面就是过去的旧题,按可以来做
在这里插入图片描述

GO{
 a : undefined
}
GO{
 a : undefined
 demo : function (){}
}
开始执行 a=100,GO{
 a : 100
 demo : function (){}
}
AO{
 e : undefined,
 b : undefined,
 c : undefined,
 a : undefined
}
形参实参相统一,AO{
 e : 1,
 b : undefined,
 c : undefined,
 a : undefined
}
赋值 AO{
 e : function e (){},
 b : undefined,
 c : undefined,------旧规则里面可以提出 function(){}
 a : undefined
}
执行 arguments[0] = 2;实参列表和传参是否相映射,变 AO{
 e : 2,
 b : undefined,
 c : undefined,
 a : undefined
}
执行 console.log(e);答案 2
if(a)由于 a 在 AO 里面是 undefined,所以不走 if
执行 a = 10;变 AO{
 e : 2,
 b : undefined,
 c : undefined,
 a : 10
}
执行 console.log(b),答案 undefined
执行 f = 123,变 GO{
 a : 100,
demo : function (){},
 f : 123
}
执行 console.log(c); 之前打印 function(){},改语法后打印 undefined
执行 console.log(a); 答案 10
执行 console.log(a); 因为在外面是全局的,答案 100
执行 console.log(a); 答案 123

在这里插入图片描述

答题//1 false+1 因为有+,两边都不是字符串,就转换成数字,false 是 0
//false false==1,false 肯定不等于 1,所以把 false 再赋给 demo
//undefined 
typeof(a) 出现”undefined” -true 转换成数字是-1 +undefined 显示“NaN”
-1 + NaN = NaN
-1 + NaN + “” = “NaN”
“undefined” && “NaN”转换成 boolean,就都是 true
“11”* 2 是*把两边转换成了数字,所以 11 +“11”* 2 =33,33 == 33,两边相等
!!非非就是正
“ ”这不是空串,是空格字符串
!!” ”转换成 Boolean 为 true
!!””非非空串,转换为 Boolean 为 false
!!false 就是 false
true + false - false = 1 + 0 – 0 =1
11|| document.write(‘你觉得能打印?’)
||遇到真就听,1 为真,所以返回 1

例(window.foo || (window.foo = ‘bar’));求 window.foo
答案”bar”
这道题要先看(window.foo = ‘bar’)这一边的,再看左边的 window.foo,因为运算
符的顺序;但是这道题错误的读法(从左到右)也是 bar
(window.foo || window.foo = ‘bar’);这么写就报错;||或运算符优先级高于=等号

8.作用域精解

[[scope]]:每个 javascript 函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供 javascript 引擎存取,[[scope]]就是其中一个。[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。

作用域链:[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。

运行期上下文:当函数在执行的前一刻,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,执行上下文被销毁。

查找变量:在哪个函数里面查找变量,就从哪个函数作用域链的顶端依次向下查找。函数类对象,我们能访问 test.nametest.[[scope]]隐式属性——作用域

例 function test (){
}
第一次执行 test(); → AO{} //AO 是用完就不要的
第二次执行 test(); → AO{} //这是另外的 AO
例 function a (){
function b (){
 var bb = 234;
 aa = 0;
}
var aa = 123;
b();
console.log(aa)
}
var glob = 100;
a();
0 是最顶端,1 是次顶端,查找顺序是从最顶端往下查

在这里插入图片描述
在这里插入图片描述

function a () {
	function b(){
	var bb=234;
	aa=0;
	}
	var aa=123;
	b();
	console.log(aa)
}
var glob=100;
a();
答案:0 
理解过程:bb 的 AO 是拿到 aa 的 AO,就是同一个 AO,bb 只是引用了 aa 的 AO,
GO 也都是同一个。function b(){}执行完,干掉的是 b 自己的 AO(销毁执行期上下
文)(去掉连接线),下次 function b 被执行时,产生的是新的 b 的 AO。b 执行完只
会销毁自己的 AO,不会销毁 a 的 AO。function a(){}执行完,会把 a 自己的 AO 销毁
【会把 function b 也销毁】,只剩 GO(回归到 a 被定义的时候),等下次 function a
再次被执行时,会产生一个全新的 AO,里面有一个新的 b 函数。。。。。。周而复始
理解过程
a 被定义 a.[[scope]] → 0 : GO{}
a 被执行 a.[[scope]] → 0 : aAO{}
1 : GO{}
b 被定义 b.[[scope]] → 0 : aAO{}
 1 : GO{}
b 被执行 b.[[scope]] → 0 : bAO{}
1 : aAO{}
2 : GO{}
c 被定义 c.[[scope]] → 0 : bAO{}
1 : aAO{}
2 : GO{}
c 被执行 c.[[scope]] → 0 : cAO{}
1 : bAO{}
2 : aAO{}
3 : GO{}
当 c 执行完后,会干掉自己的 cAO,回到 c 被定义的状态,当 c 再被执行时,会生
成一个新的 newcAO{},其余都一样,因为基础都是 c 的被定义状态
c 被执行 c.[[scope]] → 0 : newcAO{}
1 : bAO{}
2 : aAO{}
3 : GO{}
如果 function a 不被执行,下面的 function b 和 function c 都是看不到的(也不会被执
行,被折叠)。只有 function a 被执行,才能执行 function a 里面的内容
a();不执行,根本看不到 function a (){}里面的内容

11.闭包

当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露。

内存泄漏就是内存占用,内存被占用的越多,内存就变得越来越少了,就像内存被
泄露了一样

例
fucntion a (){
	function b (){
	var bbb=234;
	console.log(aaa)
}
var aaa=123;
return b;
}
var glob=100;
var demo = a();
demo();

return b 以后,就返回出去,再销毁 fn a
答案 123。因为没有 b();此时 b 还是被定义的状态,和 a 执行的状态是一样的。function a(){}是在 return b 之后才执行完,才销毁。return b 让 a 执行时的 AO 被保存在外面。

在这里插入图片描述
return b 是把 b(包括 a 的 AO)保存到外部了(放在全局)
当 a 执行完砍掉自己的 AO 时,b 依然可以访问到 a 的 AO(因为 return b)

但凡是内部的函数被保存到外部,一定生成闭包

例子
function a(){
	var num =100;
	function b (){

	num ++;
	console.log(num);
}
return b ;

}
var demo = a();
demo()
demo()
答案 101,102 理解过程
a 被执行 0 : a AO: num = 100;
 1 : GO: demo = a();
b 被执行 0 : bAO :
 1 : aAO : num = 100; 
 2 : GO: demo = a();
在第一次执行 function b 时,num ++就把 aAO 变成{num : 101},当 function b 执行完毕时,剪断的是 bAO,而 aAO 不变,当执行 function a 的 return b 时就把 aAO,GO 都存在了外部,执行完 a 销毁 scope 时去掉 a 的连接线,但是因为 return b 把 aAO,GO存在了外部,所以依然还是可以访问值
在第二次执行 function b 时,aAO{num : 101},在 num ++就是 102

function a(){
	var aa=345;
	function b(){
	var bb=234;
	function c(){
	var cc=123;
}
c()
}
b()
}
a();
执行过程:
先执行 function a(){ var aa = 345;function b (){}b();}
想要执行完上面的 b();就需要执行完 function b(){var bb = 234; function c(){}c();},
想要执行 c();就要先执行完 function c(){var cc =123;},
b();是一个复合语句,执行完 b 里面的每一句话,才能执行 b();
销毁顺序:
哪个先被执行完,哪个先被销毁
当 c 执行完,先销毁 c 自己的执行期的上下文,
当 c();执行完,那么 b 也执行完了,就销毁 b 的执行期上下文;
当 b();执行完,那么 a 也执行完了,就销毁 a 的执行期上下文

1.闭包的作用

1、实现公有变量

例子:函数累加器
在这里插入图片描述
每回调用 counter 就会在原有基础上加一次

2.可以做缓存(存储结构)

eg:eater。缓存是外部不可见的,但是确实有存储结构
在这里插入图片描述

答案 101 和 100,思考过程:说明两个用的是一个 AO
test doing test[[scope]] 0:testAO
 1:GO
a defined a.[[scope]] 0 : testAO
 1 : GO
b defined b.[[scope]] 0 : testAO
 1 : GO
return[a, b]将 a 和 b 同时被定义的状态被保存出来了
当执行 myArr[0]();时
a doing a.[[scope]] 0 : aAO
 1 : testAO
 2 : GO
当执行 myArr[1]();时
b doing b.[[scope]] 0 : bAO
 1 : a 运行后的 testAO
 2 : GO
a 运行后的 testAO, 与 a doing 里面的 testAO 一模一样
a 和 b 连线的都是 test 环境,对应的一个闭包
function a 和 function b 是并列的,不过因为 function a 在前,所以先执行 num ++,在
执行 num --
myArr[0]是数组第一位的意思,即 a,myArr[0]();就是执行函数 a 的意思;
myArr[1]是数组第二位的意思,即 b,myArr[1](); 就是执行函数 b 的意思

例缓存的应用,对象里面可以用属性和方法
在这里插入图片描述

答案 i am eating banana,eat 和 push 操作的是同一个 food
在 function eater(){里面的 food}就相当于一个隐式存储的机构
obj 对象里面是可以有 function 方法的,也可以有属性,方法就是函数的表现形式
3.可以实现封装,属性私有化

eg: Person();

4.模块化开发,防止污染全局变

12.立即执行函数

1.定义:

此类函数没有声明,在一次执行过后即释放(被销毁)。适合做初始化工作。
针对初始化功能的函数:只想让它执行一次的函数
立即执行的函数也有参数,也有返回值,有预编译

例(function (){ //写成(function abc(){}())也调用不到
var a = 123;
var b = 234;
console.log(a + b);
}())
例(function (a, b, c){
 console.log(a + b + c * 2);
}(1, 2, 3))这一行里面的(1,2,3)是实参
例 var num = (function (a, b, c){
var d = a + b + c * 2 – 2;
return d;
}(1, 2, 3)) 
答案 num = 7

2.立即执行函数的两种写法

  1. (function (){}()); //在 W3C 建议使用这一种
  2. (function (){})();

1.只有表达式才能被执行
2.能被执行符号执行的表达式,这个函数的名字就会被自动忽略(放弃名字)
3.能被执行符号执行的表达式基本上就是立即执行函数
4.函数声明和函数表达式是两个东西,虽然都能定义函数

函数声明和函数表达式是两个东西,虽然都能定义函数
函数声明:function test ( ){}
函数表达式:var test = function( ){}

例 function (){
 var a = 123;
}()
答案这是函数声明,不能执行,报语法错误,因为只有表达式才能被执行符号执行
例 function test(){
 console.log(‘a’);
}
答案这也是函数声明
例 function (){
 var a = 123;
}
test();
答案 test();就是表达式,所以能执行
例 var test = function (){
 console.log(‘a’);
}()
答案这是表达式,可以被执行,此时在控制台执行 test 的结果是 undefined,这个函
数的名字就会被放弃
例+ function test(){
 console.log(‘a’);
}()
答案加了个“正“,在趋势上要把他转换成数字,就是表达式了,既然是表达式就
能被执行,就会放弃名字,此时 console.log (test),就会报错;这就是立即执行函数
同样放了正号,负号,!就会放弃函数名字,转换成表达式;但是*和/不行,&&||前
面放东西也行
例 var test = function (){}
其中= function (){}把 function 赋到 test 里面去叫表达式,var test 是声明
在执行时,会放弃这个函数,储存到 test 里面储存引用,让这个 test 恢复到被声明的状态

例(function test(){console.log(‘a’);})()
这个被()包起来的 function 函数声明变表达式了,就能被外面的最后的()执行
例(function test(){console.log(‘a’);} ())
最外面的大括号是数学运算符号,是最先被执行,其余的括号都是有语法意义的,
就把函数变表达式了
()也是数学执行符,能打印 a,但是执行 test 就报错,所以干脆就不写 test
例 function test (a, b, c, d){
 console.log(a + b + c + d);
}(1, 2, 3, 4); //写成(1)也是这种效果
理论上不能执行,只写()就会被当成执行符,但是(1, 2, 3, 4);这样写暂时不会当成运
算符,没意义,但是不会执行,也不报错。还能调用 test
例先定义一个 10 位数的数组,就是在 var arr = [function () {console.log(i);}有十个]并
且把数组返回
function test (){ //定义个函数 test
 var arr = []; //定义一个空数组
 for (var i = 0; i < 10; i ++){ 
//丰满空数组,让空数组添加十条数组,
每一条都是一个 function(){}
arr[i] = function () { //随着 for 循环 i 变,
数组 i 也变,arr 每一次都等于一个全新的函数体
 document.write(i + “ ”);
}
}
return arr; //把 arr 返回到外部
}
var myArr = test(); 
for (var j = 0; j < 10; j ++){ //分别执行十个函数体,函数体里面定义了 document.write
 myArr[j]();
}
答案 10 10 10 10 10 10 10 10 10 10
第二个 for 是为了打印这个数组,麻烦写法 myArr[0](); myArr[1](); 。。。myArr[9]();
过程 for (var i = 0; i < 10; i ++){}执行了十次,产生了十个彼此独立的函数。并且把这
十个函数放在数组里面去,还把数组返回了,这十个函数和 test 一起产生了一个闭
包。
既然是闭包,那么访问 test 里面的变量时,实际上访问的是同一套,而 test 产生了
arr 和 i 变量(写在 for 循环里面的 i 变量),而这十个函数在外边要访问 i 变量,其实
访问的是同一个 i。
什么时候访问的?在 test 执行完以后,在下面 for(j)访问的
第一个 i=0,转到 9 的时候,i ++变 10 终止 for 循环,结束的时候 i=10,结束之后把
return arr 返回,arr;
这十个函数都是为了打印 i 的,在外部访问 i 的时候 i=10,所以打印的是 10
arr[i] = function () {
 document.write( i + “ ”);
}
理解过程:在这个函数体中,当 arr[0] 时,document.write(i)的 i 是不变的,还是 i,
等函数保存到外部之后,等执行的时候,才会去找 i 的值。
这个赋值语句中,arr[0] = 函数;把一个函数体或者说是一个函数引用赋给数组的当前
位,数组的当前位需要马上被索取出来的(数组现在是当前第几位,我们是知道的,
因为这个是执行语句),当 for(var i = 0)时,arr[i]会变成 arr[0],但是这个 i 跟函数体
里面的 d.w(i+“”)里面的 i 是没有关系的,因为函数体 function(){}不是现在执行,
不会在意函数里面写的是什么,不是现在执行那么里面的 document.write 不会变成现
实的值,不是现在执行就是函数引用(函数引用就是被折叠起来的,系统不知道里
面写的是什么)
在执行 myArr[j]();的时候,系统才会读 document.write(i +””)里面的语句
在定义函数的时候是不看里面的,在执行的时候才看
例我们让上面这个变成打印 0,1,2,3,4,5,6,7,8,9,用立即执行函数解决
function test (){ 
 var arr = []; 
 for (var i = 0; i < 10; i ++){ 
 (function (j) {
arr[j] = function () { 
 document.write( j + “ ”);
}
}(i));
return arr; 
}
var myArr = test();
for (var j = 0; j < 10; j ++){
 myArr[j]();
}
理解过程:相当于在 for 循环里面有十个立即执行函数 function(j){}
在第一圈 i 是 0,j 也是 0,function(){document.write( j + “ ”)}拿着 j=0,进行循环
的第二圈 i 是 1,又有了一个新的 j 是 1,反复循环
形成了十个立即执行函数,有十个 j 对应
例 for(var i = 0; i < 10; i ++){
 console.log(i);
}
答案 0,1,2,3,4,5,6,7,8,9
例 for(var i = 0; i < 10; i ++){
 (function(){
}())
}
中间 function 这个会执行 10 次

13.对象

1.对象的创建方法

  1. var obj = {} 对象字面量/对象直接量 plainObject
  2. 构造函数
    1. 系统自带的构造函数 Object()
      new Object();Array();Number();Boolean();Date();
      系统自带的构造函数 Object()可以批量生成对象,每一个对象都一样,但是彼此相互独立。在 Object()前面加个 new,变成 new Object()的执行,就会真正的返回一个对象,通过 return 返回,拿变量接受。var obj = new Object();
      var obj = new Object();和 var obj = {};这样写区别不大
例 var obj = new Object();
obj.name = ‘abc’;
obj.sex = “male”;

双引号和单引号都是表示的字符串,写双引号也可以写单引号,但是为了跟后端 php
配合最好写单引号。如果要打印一个单个的引号,用正则表达式转义字符

注意:等号和冒号的用法
obj.say = function(){}
var obj = { name : ‘abc’}

  1. 自定义
    Object.create(原型)方法
例 function Person(){}
Person 是可以随便写的,也是构造函数
构造函数跟函数结构上没有任何区别
例 var person1 = new person();
必须用 new 这个操作符,才能构造出对象
构造函数必须要按照大驼峰式命名规则,但凡是构造函数就要大写,例如 TheFirNa

2.构造函数内部原理

前提必须要加 new,以下三步都是隐式的:

  1. 在函数体最前面隐式的加上 var this = {} 空对象
  2. 执行 this.xxx = xxx;
  3. 隐式的返回 return this
例 function Person(name, height){
//隐式的 var this = {},下面正常执行 this
 this.name = name;
 this.height = height;
 this.say = funtion (){
 console.log(this.say); 
//此处的 this 和外面的 this 不同
}
// 隐式的 return this;
}
//例也可以这样显式的写出来
function Person (name, height){
 var that = {}; //显式写出来
 that.name = name;
 that.height = height;
 return that; //显式写出来

14.包装类

new String(); new Boolean(); new Number()
var num =123; → 原始值数字
只有原始值数字是原始值,原始值不能有属性和方法
属性和方法只有对象有,包括对象自己,数组,function

字符串类型的对象
var num = new Nunber(123); //数字类型对象
var str = new String(‘abcd’); //字符串类型对象
var bol = new Boolean(‘true’); //布尔类型对象

不能写成 undefined.abc = 123;会报错

undefined 和 null 不可以有属性


原始值不可能有属性和方法,但经过了包装类(加隐式)可以调用一些属性与方法

var num = 4;
num.len = 3;
//系统隐式的加上 new Number(4).len = 3; 然后 delete
console.log(num.len);
//系统隐式的加上 new Number(4).len; 但是这个 new number 和上面的 new number
不是同一个,所以返回 undefined

而上面这些隐式的过程就是包装类

例子

例 var str = “abcd”;
str.length = 2;
//隐式的加上 new string(‘abcd’).length = 2; delete
console.log(str); 
console.log(str.length);
答案是 abcd,4

例子

var str = "abc";
str +=1
var test = typeof(str)
if(test.length==6){
  test.sign='typeof的返回结果可能为String'
}
console.log(test.sign)//undefined
解析
str += 1; //abc1
var test = typeof(str); //test == “string”,返回 string,string 长度是 6
if(test.length == 6){ 
test.sign = “typeof 的返回结果可能为 String”; //这是原始值,原始值要赋属性
值需要调用包装类,赋了跟没赋值是一样的,new String(test).sign=’xxx’;
}
conlogo.log(test.sign); //new String(test).sign
答案 undefined

在这里插入图片描述
在这里插入图片描述
例:请问以下表达式的结果是什么?

parseInt(3, 8)
parseInt(3, 2)
parseInt(3, 0)

A 3,3,3
B 3,3,NAN
C 3 NAN,NAN
D other

答案选 3 或 4,值为 3,NaN,3(有的浏览器遇到 0 是报 NaN)

例:以下哪些是 JavaScript 语言 typeof 可能返回的结果:

A.string B.array C.object D.null
答案:A

例:看看下面 alert 的结果是什么?

function b (x, y, a) {
 arguments[ 2 ] = 10;
 alert( a );
}
b(1, 2, 3);
如果函数体改成下面,结果又会是什么?
a = 10;
alert(arguments[ 2 ]);
答案 10,10

15.原型

1.定义

  1. 原型是 function 对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。
  2. 利用原型特点和概念,可以提取共有属性。
  3. 对象属性的增删和原型上属性增删改查。
  4. 对象如何查看原型 ==> 隐式属性 proto
  5. 对象如何查看对象的构造函数 ==> constructor。

person.prototype //原型(描述一种继承关系),出生时就被定义好了
person.prototype ={} //是祖先 

在这里插入图片描述

右上的 person 和 person1 都有一个共有的祖先 Person.prototype


在这里插入图片描述

自己身上有属性,原型上也有属性,取近的,用自己的


在这里插入图片描述

将左上的共有的东西提取出来放在原型里面,如右上图

在这里插入图片描述

上面通过对象(后代)改原型(祖先)是不行的,在对象里面修改,只作用给自己
改原型都不行,增加肯定也不行。对象可以删除属性

在这里插入图片描述

左上的简化写法见右上 // construnctor 是构造的意思(隐式是浅粉色)

在这里插入图片描述

浅粉色是系统帮你设置的,深紫色是自己设置的

在这里插入图片描述

在原型内部自带 constructor,指的是 Car。通过 constructor 能找的谁构造的自己

在这里插入图片描述

constructor 可以被人工手动更改

在这里插入图片描述

1.浅粉色的__proto__是系统的隐式的属性,前面两个_后面两个_,可以修改,尽量不改。
2.在开发的时候,如果很私人可以写成_private,告诉同事别动。
3.上面的__proto__放的是原型。__proto__存的对象的原型
4.上面的 var this ={proto:person.prototype};这个对象并不是空的,这个 proto,当你访问这个对象的属性时,如果对象没有这个属性,那么就会访问 proto 索引,看看有
没有。有一个连接的关系,原型和自己连接到一起

在这里插入图片描述

Person 的原型是可以被修改的

在这里插入图片描述

Person.prototype.name 这种.的写法是在原有的基础上把值改了。改的是属性,也就是
房间里面的东西。
而 Person.prototype={name:’cherry’}是把原型改了,换了新的对象。改了个房间。
上面在 new 的时候 var this = {proto:Person.prototype}里面的指向 Person,此时
Person.prototype 与__proto__指向的是一个空间,把他返回给 var person。
先 new 再 Person.prototype={name:’cherry’}已经晚了
在 Person.prototype={name:’cherry’}时,Person.prototype 空间改了,但是__proto
指向的空间不变。

上面的步骤实际上是在这里插入图片描述

在这里插入图片描述
上面这种思考过程:程序执行顺序
1.先把 function Person(){}在预编译的过程中提到最上面
2.再执行 Person.prototype.name = ‘sunny’这一样行
3.再执行 Person.prototype = {name:’cherry’}
4.最后执行 var person = new Person();执行到 new 的时候,才会发生//var this ={proto:Person.prototype}
5.下面的把上面的覆盖了
6.答案是 cherry

在这里插入图片描述
执行 son.toString //返回 function toString( ){ [native code] },这里返回的是原型链
终端的 toString
Grand.prototype.proto = Object.prototype // Object.prototype 是原型链的终端

2.原型链

1、如何构成原型链?(见上一个例子)
2、原型链上属性的增删改查
原型链上的增删改查和原型基本上是一致的。只有本人有的权限,子孙是没有的。
3、谁调用的方法内部 this 就是谁-原型案例
4、绝大多数对象的最终都会继承自 Object.prototype
5、Object.create(原型);
6、原型方法上的重写


在这里插入图片描述
son.fortune.card2=’master’这种改,这是引用值自己的修改。属于 fortune.name 给
自己修改,这是一种调用方法的修改


在这里插入图片描述

在这里插入图片描述
console.log(this.name); //如果写成 name 就会错,没有这个变量


在这里插入图片描述
a.sayName ( )方法调用,就是 say.Name 里面的 this 指向,是谁调用的这个方法,this就指向谁

在这里插入图片描述
this.height ++; //这后面默认有一个 return undefined

例 var obj = { };也是有原型的

var obj = { };与 var obj1 = new Object( );效果是一样的
写 var obj = { }; 系统会在内部来一个 new Object( );
obj1.__proto__ → Object.ptototype;
但是在构造对象时,能用对象自变量 var obj = { };就不要用 var obj1 = new Object( );


在这里插入图片描述
对像自变量的原型就是 Object.ptototype;

3.Object.create(原型);

var obj = Object.create(原型);
Object.create 也能创建对象。var obj = Object.create(这里必须要有原型)
在这里插入图片描述

绝大多数对象的最终都会继承自 Object.prototype


html 里面没有添加任何东西
这样就报错
在这里插入图片描述


html 里面没有添加任何东西
只在控制台加上 null
在这里插入图片描述

在这里插入图片描述

原型是隐式的内部属性,你加是没有用的


在这里插入图片描述

Object.create()在括号里面只能放 null 或者 Object,其余会报错


undefined 和 null 没有原型,也就不可能有 toString 方法
在这里插入图片描述


下面 123.toString 首先会识别成浮点型,所以在后面直接加.toString 是不行的
在这里插入图片描述

数字想用 toString 方法,要经过包装类包装 new Number(num)然后. toString


加深上面的理解
在这里插入图片描述
而 new Number(num). toString 的原型是 Nunber.prototype,而 Nunber.prototype 上面有
一个.toString 方法,Nunber.prototype 也有原型 Nunber.prototype.proto,原型是
Object.prototype
假如 new Number 上面的 prototype 上面有这个 toString,那么就不用 Object.prototype
的 toString。而这个 number 上面有这个 toString。
然后 number 上面的 toString 调用的是自己重写的 toString。
原型上有这个方法,我自己又写了一个和原型上同一名字,但不同功能的方法,叫
做重写(同一名字的函数,不同重写方式)
通过返回值,形参列表不同传参
同样的名实现不同功能的,就是重写
在这里插入图片描述


在这里插入图片描述

和原型链上终端方法名字一样,但实现不同的功能,叫做方法的重写。也就是覆盖

例子
在这里插入图片描述

下面这个也是重写

在这里插入图片描述

让 object 上面的 toString 重写了。
所以 num.toString()调用的是 number. prototype.toString。
在这里插入图片描述
如果调用的是 object. prototype.toString 结果会不一样。
在这里插入图片描述

例子
在这里插入图片描述

document.write 会隐式的调用 toString 方法,其实打印的是 toString 的结果

在这里插入图片描述

没有原型就不能 toString

在这里插入图片描述
上面这个例子表示:我要打印的是 obj,实际上打印出来的是 toString 方法,也证明
了 document.write 调用的是 toString 方法

16.call/apply

1.作用

改变 this 指向。

2.区别

后面传的参数形式不同。


任何一个方法都可以.call
.call 才是一个方法执行的真实面目
在这里插入图片描述
在这里插入图片描述
接执行 Person.call ( )和 Person ( )没有区别
Person.call( );括号里面可以传东西
如果 Person.call( obj );里面的 call 让 person 所有的 this 都变成 obj不 new 的话,this 默认指向 window。
call 的使用必须要 new
call 的第一位参数用于改变 this 指向,第二位实参(对应第一个形参)及以后的参数
都当做正常的实参,传到形参里面去
借用别人的方法,实现自己的功能。


A写 test()和写 test.call()是一样的,
在这里插入图片描述


两个人的需求
有重复部分
在这里插入图片描述
call 改变 this 指向,借用别人的函数,实现自己的功能。
只能在你的需求完全涵盖别人的时候才能使用
如果不想要 age 这个,就不能使用这种方法
在这里插入图片描述
Person.call(this, name, age, sex);里面的 this 现在是 new 了以后的 var this={}
利用 Person 方法,实现了 Student 自己的封装


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
apply 也是改变 this 指向的,只是传参列表不同,第一位也是改变 this 指向的人,第
二位,apply 只能传一个实参,而且必须传数组 argunments
call 需要把实参按照形参的个数传进去
new 以后才有意义
在这里插入图片描述

3.继承发展史

1.传统形式 ==> 原型链

问题:过多的继承了没用的属性
在这里插入图片描述

2.借用构造函数 =>利用 call、apply 所以不算标准的继承模式
  1. 不能继承借用构造函数的原型
  2. 每次构造函数都要多走一个函数 =>浪费效率

this 放进去的前提,这个函数必须是 new 来的
在这里插入图片描述

3.共享原型(较好的继承方法)

不能随便改动自己的原型

Son.prototype=Father.prototype
让 son 和 father 共享原型
在这里插入图片描述
在这里插入图片描述

可以用上面的方式封装函数,实现一个继承
extend 和 inherit 都是继承的意思。
inherit 是 css 的一个值,也是继承的意思。
文字类属性都有一个传递的特性:子元素没有设置文字类属性,子元素默认继承父元素的属性。
font-size:inheit;我没有就继承父亲的
在 inherit(Target,Origin)里面传进去的值是构造函数,需要大驼峰式书写,origin
是原始的意思,让 target(目标)继承 origin
在这里插入图片描述
上面这种方式让 son 里面有了 father 原型的属性
应该是先 inherit 继承,后使用
下面这种方式就是先继承了,后改变原型已经晚了,因为他继承的还是原来的空间
在这里插入图片描述

下面这种写法,son.prototype 和 father.prototype 指向的是一个房间,改 son 就改了
father。我们希望 son 用的 father 的原型,但是改变 son 自己的属性不影响 father
在这里插入图片描述

4.圣杯模式

圣杯模式是在方法三的共有原型,但是在共有原型的基础上有改变。
共享原型是:son.prototype=father.prototype

圣杯模式是:另外加个构造函数 function F(){}当做中间层,然后让 F 和 father 共
有一个原型 F.prototype=father.prototype,然后 son.prototype = new F();使用原
型链形成了继承关系,现在改 son.prototype 就不会影响 father.prototype
在这里插入图片描述
在这里插入图片描述


原型上默认有个 constructor
constructor 默认指向他的构造函数
son. constructor 应该指向 Son

在这里插入图片描述
指向 father 就是混乱了
所以要指一下
在这里插入图片描述
我们希望我们构造出的对象,
能找到自己的超类,超级父级
(究竟继承自谁)应该起名为
super 但这个是保留字,我们
就以 uber

例:
左下这种方法就不好使了,相当于右下。还是原型指向有问题,new 的时候用
的是原来的原型,再 F.prototype =father.prototype 没用,son.prototype 没发生改变
在这里插入图片描述

例,
在雅虎时代,封装了 YUI3 库来解决方法三的不足,与圣杯模式相似。现在不用
YUI3 库,现在用 jq
在这里插入图片描述
上面的 var inherit 与右边
的 var inherit 是一样的意思
建议写上面的这
在这里插入图片描述

4.联系到闭包作用

可以实现封装,属性私有化。


为什么在外部执行的 divorce 能用内部的变量?能换成 xiaozhang?
因为 this.divorce 在对象上,由于对象被返回了,这个方法也被返回了。
因为闭包。这个函数被储存到了外部,所以储存了这个函数的执行期上下文。所以
可以用这个闭包。所以 var prepareWife 被下面的 this=fn 三个函数共用,这三个函数
分别与 fn Deng 形成了闭包,共同用 Deng 的 AO,所以可以在外部随意存取。

在这里插入图片描述
deng.prepareWife 是 undefined 的,表面上看起来不是自己的,但是实际上只有对象
自己通过对象自己设置的方法可以去操作他。外部用户通过对象. prepareWife 是看不
到的。只有自己能看到,就是闭包的私有化的运用。

在这里插入图片描述
最后执行完是这个样的
在这里插入图片描述
上面的 var F 这个 F 形成了闭包,成为了这个函数的私有化变量,而且变成私有化变
量就更好

17.操作数字的方法

1.toFixed 是保留两位有效数字


有个 bug,在控制台 0.14*100
出现 14.0000000000002,是 js 开发精度不准
在这里插入图片描述

2. 向上取整


向上取整 Math.ceil(123.234)
答案 124

3. 向下取整


向下取整 Math.floor(123.999)
答案 123

4. 随机数


Math.random()是产生一个 0 到 1 区间的开区间 随机数


在这里插入图片描述
在这里插入图片描述
所以一般在这种情况下,我们不用 toFixed,因为精度不准确


用这种方法取整更好,就不会精度不准确
在这里插入图片描述

4.极限

在这里插入图片描述

之前 js 在小数点后面最多能容纳 15-17 位,但是升级后能用科学计数法表示 如 2e-17(是 2 乘以 10 的负 17 次方)
而小数点前面只能容纳 16 位的运算, 可正常计算的范围是小数点前后 16 位

18.数组 

1.数组的常用方法

改变原数组

  • arr.push(); 向数组的末尾追加元素

    • 会修改原数组

    • 返回值:修改后的length值

    • 可以追加多个

      arr[1,2,3];
      arr1[4,5,6];
      arr2[...arr,...arr1];       //  ...扩展运算符,将数组展开
      
  • arr.unshift(); 向数组的开头添加元素

    • 会修改原数组
    • 返回值:修改后的length值
    • 可以追加多个
  • arr.pop(); 删除末尾的元素

    • 会修改原数组
    • 返回值:被删除的数据
    • 只能删除一个
  • arr.shift(); 开头删除一个元素

    • 会修改原数组
    • 返回值:被删除的数据
    • 只能删除一个
  • arr.splice(位置,删除元素的个数,要追加的元素); 任意位置添加删除

    • 添加或者删除包含对应下标
    • 添加数据时:删除元素的个数写0;
    • 可以同时删除和添加(先删除,后添加)
    • 修改原数组
  • arr.join(“分隔符”) 使用分隔符将数组数据隔开变为字符串

    • 不修改原数组
    • 返回值是分隔好的字符串
  • arr.slice(截取的起始下标,结束下标) 数组的截取

    • 截取时,包含起始下标,不包含结束下标
    • 不修改原数组
    • 返回值是截取到的数组
    • 参数可以是负数,负数表示倒数,只传一个参数表示从起始下标截取到最后
  •   arr.reverse() 数组倒序
    • 返回修改后的数组

    • 改变原数组

      var arr=[1,5,8,6,9,4,2,3];
      console.log(arr.reverse());     // (8) [3, 2, 4, 9, 6, 8, 5, 1]
      console.log(arr);               // (8) [3, 2, 4, 9, 6, 8, 5, 1]

不改变原数组 

arr.concat 多个数组的连接

  • 不修改原数组

  • 返回值是连接之后的新数组

    var arr1=[1,2,3];
    var arr2=[4,5,6];
    console.log(arr1.concat(arr2,[7,8,9]));
    
    // 控制台输出
    // (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]

arr.sort() 数组的排序

  • 如果没有参数,则从字符的编码开始按顺序排

  • 如果有参数,这个参数必须是一个函数(回调函数)这个回调函数有两个参数,分别是a,b

  • 修改原数组

  • 返回值是排序之后的数组

    var arr3=[1,5,6,99,52,663,22,66,552,6,622];
    arr3.sort(function(a,b){
    //a-b 正序,
    //b-a 倒序,  
    return a-b;
    })
    console.log(arr3);
    // 控制台输出
    // (11) [1, 5, 6, 6, 22, 52, 66, 99, 552, 622, 663]
    //箭头函数
    arr.sort((a,b)=>a-b)     //正序,
    arr.sort((a,b)=>b-a)     //倒序,
    
    
    //箭头函数
    arr3.sort((a,b)=>{return a-b});
    arr3.sort((a,b)=>a-b);

2.类数组 

一旦给一个对象加上splice方法,至此对象就会长的和数组一样变为类数组

push内部原理:

题:

答案:

obj {

"2" : "c"

"3" : "d"

"length" : 4

}

3.数组去重(哈希法)

19.This 

 20.try...catch

 在try的里面发生错误,不会执行错误后的try里面的代码,但是会执行catch里面的代码

 

错误信息  错误名称(catch只能打印一个错误)  

 

21.es5.0严格模式:

 

 (要写在整个页面代码的最顶端)

也可以写在局部:

 

22.with(){}

 with(){}可以改变作用域链,可以让里面代码最顶端的AO变为()里面的AO(缺点:会使代码运行速度大大降低)

打印obj

23.eval()方法:可以将字符串当做代码执行

打印123

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值