js知识梳理五

js严格模式

1.在严格模式下不支持使用 “arguments.callee / arguments.callee.caller” (Uncaught TypeError: ‘caller’, ‘callee’, and ‘arguments’ properties may not be accessed on strict mode functions or the arguments objects for calls to them)

2.在严格模式下ARGUMENTS和形参没有映射机制

3.在严格模式下不允许给一个对象设置重复属性名的:“obj={n:10,n:20}”

4.在严格模式下,函数执行,如果没有明确指定执行的主体(函数前面没有点),不再像非严格模式下一样,统一都交给window,而是让this指向undefined,代表没有执行主体:“严格模式下,有执行主体this就指向谁,没有执行主体,this就是undefined”

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
36
37
38
~function () {
/*function fn(x) {
arguments[0]=100;
console.log(x);//=>100 存在映射机制
}
fn(10);*/

/*var obj={
n:10,
n:20
};
console.log(obj.n);*/

function fn() {
console.log(this);//=>window
}
fn();
}();

~function () {
"use strict";
/*function fn(x) {
arguments[0]=100;
console.log(x);//=>10 不存在映射机制
}
fn(10);*/

/*var obj={
n:10,
n:20
};
console.log(obj.n);*/

function fn() {
console.log(this);//=>undefined
}
fn();
}();

原型设计模式

在实际项目基于面向对象开发的时候(构造原型设计模式),我们根据需要,很多时候会重定向类的原型(让类的原型指向自己开辟的堆内存

  • 自己开辟的堆内存中没有constructor属性,导致类的原型构造函数缺失(解决:自己手动在堆内存中增加constructor属性)
  • 当原型重定向后,浏览器默认开辟的那个原型堆内存会被释放掉,如果之前已经存储了一些方法或者属性,这些东西都会丢失(所以:内置类的原型不允许重定向到自己开辟的堆内存,因为内置类原型上自带很多属性方法,重定向后都没了,这样是不被允许的)

less

它是CSS预编译语言,和它类似的还有sass/stylus…

css是标记语言,不是编程语言,没有类、实例、函数、变量等东西;而less等预编译语言就是让css具备面向对象编程的思想;但是浏览器不能直接识别和渲染less代码,需要我们把less代码预先编译为正常的css后,再交给浏览器渲染解析;

less的编译

  • 在开发环境下编译(产品没有开发完,正在开发中,这个是开发环境)

    导入less.js即可

    1
    2
    3
    4
    5
    //=>rel="stylesheet/less" 这块有修改
    <link rel="stylesheet/less" href="css/demo1.less">

    //=>导入JS文件即可
    <script src="js/less-2.5.3.min.js"></script>
  • 在生产环境下编译(产品开发完成了,需要部署到服务器上)

    项目上线,不能把less部署,这样用户每一次打开页面都需要重新的编译,非常耗性能,我们部署到服务器上的是编译后的css

    1
    2
    3
    4
    5
    6
    7
    8
    9
    1.在当前电脑的全局环境下安装less模块
    $ npm install less -g

    验证是否安装成功:$ lessc -v

    2.基于命令把我们的less编译成css
    $ lessc xxx/xxx.less xxx/xxx.min.css -x

    把指定目录中的less编译成为css(并且实现了代码的压缩),把编译后的css存入到具体指定路径中的文件中;上线前在HTML中导入的是css文件;
  • 目前基于webpack和框架实现工程化开发的时候,我们都是在webpack配置文件中,配置出less的编译(需要安装less/less-loader等模块),这样不管是开发环境下的预览,还是部署到生产环境下,都是基于webpack中的less模块编译的

  • less语法:[http://lesscss.cn/]

call、aplly、bind

call

      [fn].call([this],[param]…)
fn.call:当前实例(函数FN)通过原型链的查找机制,找到Function.prototype上的call方法 =>function call(){[native code]}
,当call方法执行的时候,内部处理了一些事情

1、首先把要操作函数中的THIS关键字变为CALL方法第一个传递的实参值

2、把CALL方法第二个及第二个以后的实参获取到

3、把要操作的函数执行,并且把第二个以后的传递进来的实参传给函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// call 原理
Function.prototype.es3Call = function (context) {
var content = context || window;
content.fn = this;
var args = [];
// arguments是类数组对象,遍历之前需要保存长度,过滤出第一个传参
for (var i = 1, len = arguments.length ; i < len; i++) {
// 避免object之类传入
args.push('arguments[' + i + ']');
}
var result = eval('content.fn('+args+')');
delete content.fn;
return result;
}

call细节

  • 非严格模式下,如果参数不传,或者第一个传递的是null/undefined,THIS都指向WINDOW
  • 在严格模式下,第一个参数是谁,THIS就指向谁(包括null/undefined),不传THIS是undefined
1
2
3
4
5
fn.call(obj, 10, 20);//=>this:obj a=10 b=20
fn.call(10, 20);//=>this:10 a=20 b=undefined
fn.call();//=>this:window a=undefined b=undefined
fn.call(null);//=>this:window
fn.call(undefined);//=>this:window

apply

和call基本上一模一样,唯一区别在于传参方式

  • fn.call(obj,10,20)
  • fn.apply(obj,[10,20]) APPLY把需要传递给FN的参数放到一个数组(或者类数组)中传递进去,虽然写的是一个数组,但是也相当于给FN一个个的传递

bind:

语法和call一模一样,唯一的区别在于立即执行还是等待执行

  • fn.call(obj,10,20) 改变FN中的THIS,并且把FN立即执行
  • fn.bind(obj,10,20) 改变FN中的THIS,此时的FN并没有执行(不兼容IE6~8)

解构赋值

对象解构赋值

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
  let obj = {name: 'xxx', age: 25, sex: 0};
let {name, age} = obj;//=>对象解构赋值默认情况下要求:左侧变量名和对象中的属性名一致才可以
console.log(name, age);

let {sex} = obj;
console.log(sex);//=>0

let {age: ageAA} = obj;
console.log(age);//=>Uncaught ReferenceError: age is not defined
console.log(ageAA);//=>25 给解构的属性名起别名作为我们使用的变量

let {friend = 0} = obj;
console.log(friend);//=>0 给不存在的属性设置默认值

let fn = function ({
name = '珠峰',
age = 0
} = {}) {//=>把传递的对象解构了(不传递值,默认赋值为空对象:现在传递对象或者不传递,形参接收到的都是对象),解构的时候,可以把传递进来对象中,如果某个属性不存在,我们赋值默认值
console.log(name, age);

};
fn({
name: 'xxx',
age: 25
});

数组解构赋值

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
36
37
38
39
 let a = 12,
b = 13;
//=>a&b互换位置
[a, b] = [b, a];//=>[13,12]
console.log(a, b);

/*let c=a;
a=b;
b=c;
console.log(a, b);*/

/*a=a+b;
b=a-b;
a=a-b;
console.log(a, b);*/


let ary = [12];
let [a, b = 0] = ary;//=>在解构的时候可以给变量设置默认值:如果当前变量对应结构中的这一项没有值,变量用默认值
console.log(a, b);//=>12 0


let ary = [12, 23, 34, 45, 56];
//=>需求:获取第一项,把剩下的项作为一个数组返回
let [a, ...b] = ary;
console.log(a, b);//=>12 [23,34,45,56] “...”在此处称之为剩余运算符:除了前面以外的项,都放在一个数组中
// let [a, ...b, c] = ary;//=>Uncaught SyntaxError: Rest element must be last element 剩余运算符处于解构中最后的位置
-------------------------------------
let a=ary[0],
b=ary[1],
c=ary[2];
let [a, b, c] = ary;//=>让等号左边出现和右边相同的数据结构,左边可以创建一些变量快速获取到右侧对应位置的值(解构赋值)
console.log(a, b, c);

let [a] = ary;
console.log(a);//=>12

let [a, , c] = ary;
console.log(a, c);//=>12 34

‘…’运算符

“…”在ES6的语法中,三个点有三种含义

  • 1.剩余运算符
  • 2.拓展运算符
  • 3.展开运算符:把数组(对象/类数组)中的每一项展开 xxx,xxx,xxx…
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     let ary = [12, 23, 34];
    let [...arg] = ary; //=>ary.slice(0)

    function fn(context, ...arg) {
    //=>获取传递值中的第一个和剩下的
    console.log(context, arg);
    //=>ARG是一个数组 / ARGUMENTS是类数组
    }
    function sum(...arg) {
    //=>传递几个实参,ARG中就存储多少个,此时的ARG和ARGUMENTS一样的,区别是ARG是一个数组,ARGUMENTS是一个类数组
    }
    -------------------------------------------------------
    let ary = [12, 23, 34];
    let fn = function (a, b, c) {
    console.log(a, b, c);
    };
    // Math.max(...ary);//=>Math.max(12,23,34)
    // fn(ary);//=>a:ary b/c:undefined
    fn(...ary);//=>fn(12, 23, 34) 把数组中的每一项分别传递给一个函数,此时我们使用展开运算符把数组展开即可
    let obj = {name: 'xxx', age: 20};
    let newObj = {...obj, sex: 0};//=>{name: 'xxx', age: 20,sex:0} 把原有对象展开(克隆)放到新对象中

    // let ary = [12, 23];
    // let newAry = [...ary, 100];//=>[12, 23, 100]

DOM的映射机制

  • 页面中的HTML元素,和JS中通过相关方法获取到的元素集合或者元素对象存在映射关系(一个改另外一个会跟着自动修改)
    *
  • xxx.style.color=’red’ : 把xxx元素对象对应堆内存中的style属性下的color属性值修改为’red’(本质操作的是JS堆内存) ;但是由于DOM映射关系,页面中的标签和XXX元素对象是绑在一起的,我们修改元素对象空间的值,页面中的元素会按照最新的值进行渲染;
    *
  • 在元素绑定前,我们获取容器中元素,得到一个空的元素集合,元素数据绑定后,我们不需要重新获取,DOM的映射机制会帮我们把新增加的元素映射到之前获取的空集合中,让其变为有元素的集合(querySelectorAll获取的集合是静态集合(staticNodeList),不存在上述所谓的映射机制,所以基于这种办法,数据绑定完成后需要重新的获取一次才可以)
    *
  • appendChild在追加元素对象的时候,如果这个元素之前容器中已经存在,此时不是克隆一份新的追加到末尾,而是把原有的元素移动到末尾位置
-------------本文结束感谢您的阅读-------------