目录
- referer、prototype、array、json笔记整理
- referer
- Referrer-policy
- 如何设置referer
- 绕过图片防盗链
- 1、利用https网站盗链http资源网站,refer不会发送
- 2、设置meta
- 3、设置referrerpolicy="no-referrer"
- 4、利用iframe伪造请求referer
- 5、客户端在请求时修改header头部
- 1、利用XMLHttpRequest
- 2、利用fetch
 
 
 
- prototype
- 对象的继承
- 原型对象概述
- 构造函数的缺点
- prototype 属性的作用
- 原型链
- constructor 属性
- instanceof 运算符
- 构造函数的继承
- 多重继承
 
 
- array
- Array 对象
- 构造函数
- 实例方法
- valueOf(),toString()
- push(),pop()
- shift(),unshift()
- join()
- slice()
- sort()
- map()
- filter()
 
- 总结
- 那些方法会改变原数组
- 那些方法不会改变原数组
 
 
- json
- JSON 对象
- JSON 格式
- JSON 对象
- JSON.stringify()
- 第二个参数
 
- 参数对象的 toJSON() 方法
- JSON.parse()
 
- 总结
- 1、JSON.parse()可以**将一个字符串转为 JSON值 **
- 2、JSON.stringify()可以**将一个值转为 JSON 字符串**
 
 
 
referer、prototype、array、json笔记整理
referer
Referrer-policy
Referrer-policy作用就是为了控制请求头中referer的内容
包含以下值:
- no-referrer : 整个referee首部会被移除,访问来源信息不随着请求一起发送。
- no-referrer-when-downgrade : 在没有指定任何策略的情况下用户代理的默认行为。在同等安全级别的情况下,引用页面的地址会被发送(HTTPS->HTTPS),但是在降级的情况下不会被发送 (HTTPS->HTTP).
- origin: 在任何情况下,仅发送文件的源作为引用地址。例如 https://example.com/page.html 会将 https://example.com/ 作为引用地址。
- origin-when-cross-origin: 对于同源的请求,会发送完整的URL作为引用地址,但是对于非同源请求仅发送文件的源。
- same-origin: 对于同源的请求会发送引用地址,但是对于非同源请求则不发送引用地址信息。
- strict-origin: 在同等安全级别的情况下,发送文件的源作为引用地址(HTTPS->HTTPS),但是在降级的情况下不会发送 (HTTPS->HTTP)。
- strict-origin-when-cross-origin: 对于同源的请求,会发送完整的URL作为引用地址;在同等安全级别的情况下,发送文件的源作为引用地址(HTTPS->HTTPS);在降级的情况下不发送此首部 (HTTPS->HTTP)。
- unsafe-url: 无论是同源请求还是非同源请求,都发送完整的 URL(移除参数信息之后)作为引用地址。(最不安全了):
  
如何设置referer
- 在HTML里设置meta
<meta name="referrer" content="origin">
- 在<a>、<area>、<img>、<iframe>、<script> 或者 <link> 元素上的 referrerpolicy 属性为其设置独立的请求策略。
<script src='/javascripts/test.js' 
referrerpolicy="no-referrer"></script>


绕过图片防盗链
1、利用https网站盗链http资源网站,refer不会发送
2、设置meta
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-56nvO5Hb-1673295301886)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230107214522955.png)]](https://img-blog.csdnimg.cn/0c339ebf73be47309204a0dff9c261df.png)
3、设置referrerpolicy=“no-referrer”
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o6JeMPoM-1673295301887)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230107214906463.png)]](https://img-blog.csdnimg.cn/f5fdf3826f0b4aa3acd09bc9fe949640.png)
4、利用iframe伪造请求referer
#index.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <!-- <meta name="referer" content="no-referrer" > -->
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <img src="https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg" >
<!--  <iframe src="./2.html" width="20%" height="200" frameborder="1" sandbox="allow-scripts allow-same-origin allow-modals "></iframe>-->
    </body>
   <script src="./1.js" ></script>
</html>
#js
function showImg(src, wrapper ) {
    let url = new URL(src);
    let frameid = 'frameimg' + Math.random();
    window.img = `<img id="tmpImg" width=400 src="${url}" alt="图片加载失败,请稍后再试"/> `;
    // 构造一个iframe
    iframe = document.createElement('iframe')
    iframe.id = frameid
    iframe.src = "javascript:parent.img;" // 通过内联的javascript,设置iframe的src
    // 校正iframe的尺寸,完整展示图片
    iframe.onload = function () {
        var img = iframe.contentDocument.getElementById("tmpImg")
        if (img) {
            iframe.height = img.height + 'px'
            iframe.width = img.width + 'px'
        }
    }
    iframe.width = 10
    iframe.height = 10
    iframe.scrolling = "no"
    iframe.frameBorder = "0"
    wrapper.appendChild(iframe)
}
showImg('https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg', document.querySelector('#container'))
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oB3i1IcU-1673295301888)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230107215545769.png)]](https://img-blog.csdnimg.cn/80d20059683849049930245b7217c5cd.png)
5、客户端在请求时修改header头部
1、利用XMLHttpRequest
    // 通过ajax下载图片
    function loadImage(uri) {
        return new Promise(resolve => {
            let xhr = new XMLHttpRequest();
            xhr.responseType = "blob";
            xhr.onload = function() {
                resolve(xhr.response);
            };
    
            xhr.open("GET", uri, true);
            // 通过setRequestHeader设置header不会生效
            // 会提示 Refused to set unsafe header "Referer"
            xhr.setRequestHeader("Referer", ""); 
            xhr.send();
        });
    }
    // 将下载下来的二进制大对象数据转换成base64,然后展示在页面上
    function handleBlob(blob) {
        let reader = new FileReader();
        reader.onload = function(evt) {
            let img = document.createElement('img');
            img.src = evt.target.result;
            document.getElementById('container').appendChild(img)
        };
        reader.readAsDataURL(blob);
    }
    
    const imgSrc = "https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg";
    
    loadImage(imgSrc).then(blob => {
        handleBlob(blob);
    });
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LgSAG2yn-1673295844182)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230107220133618.png)]](https://img-blog.csdnimg.cn/183ae4657fc24a0c95c219b7c5195931.png)
上述代码运行时会发现控制台提示错误:
Refused to set unsafe header “Referer”
可以看见setRequestHeader设置referer响应头是无效的,这是由于浏览器为了安全起见,无法手动设置部分保留字段,不幸的是Referer恰好就是保留字段之一
2、利用fetch
    // 将下载下来的二进制大对象数据转换成base64,然后展示在页面上
    function handleBlob(blob) {
        let reader = new FileReader();
        reader.onload = function(evt) {
            let img = document.createElement('img');
            img.src = evt.target.result;
            document.getElementById('container').appendChild(img)
        };
        reader.readAsDataURL(blob);
    }
    
    const imgSrc = "https://tiebapic.baidu.com/forum/w%3D580%3B/sign=f88eb0f2cf82b9013dadc33b43b6ab77/562c11dfa9ec8a135455cc35b203918fa1ecc09c.jpg";
    function fetchImage(url) {
        return fetch(url, {
            headers: {
                // "Referer": "", // 这里设置无效
            },
            method: "GET",  
            referrer: "", // 将referer置空
            // referrerPolicy: 'no-referrer', 
        }).then(response => response.blob());
    }
    
    fetchImage(imgSrc).then(blob => {
        handleBlob(blob);
    });
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KH64NS5g-1673295301889)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230107221202535.png)]](https://img-blog.csdnimg.cn/cbb4db8ec76941309dfde24e5bb47e77.png)
 ![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l1EbxUyr-1673295301889)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230110015422336.png)]](https://img-blog.csdnimg.cn/2b344a030b22444ca20accacb9a3f91f.png)
prototype
对象的继承
面向对象编程很重要的一个方面,就是对象的继承。A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法。这对于代码的复用是非常有用的。
大部分面向对象的编程语言,都是通过“类”(class)实现对象的继承。传统上,JavaScript 语言的继承不通过 class,而是通过“原型对象”(prototype)实现,本章介绍 JavaScript 的原型链继承。
ES6 引入了 class 语法,基于 class 的继承不在这个教程介绍,请参阅《ES6 标准入门》一书的相关章节。
原型对象概述
构造函数的缺点
JavaScript 通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法,可以定义在构造函数内部。
function Person (name){
    this.name = name;
}
Person.prototype.color = 'white';
var Aferican_a = new Person('person_a');
var Aferican_b = new Person('person_b');
var American_a = new Person('person_c');
American_a.color ='black';
console.info(Aferican_a.color ===American_a.color);
console.info(Aferican_a.color ===Aferican_b.color);
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oOTZ5Y50-1673296061806)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109194855590.png)]](https://img-blog.csdnimg.cn/0d6114d649bc46dcbb0b24bd486e0584.png)
上面代码中,person函数是一个构造函数,函数内部定义了name属性和color属性,所有实例对象都会生成这两个属性,即这两个属性会定义在实例对象上面。
 通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。
function Person (name){
    this.name = name;
}
Person.prototype.color = 'white';
var Aferican_a = new Person('person_a');
var Aferican_b = new Person('person_b');
var American_a = new Person('person_c');
American_a.color ='black';
Person.prototype.speak = function () {
    console.info('Speak English');
}
console.info(Aferican_a.color ===American_a.color);
console.info(Aferican_a.color ===Aferican_b.color);
Aferican_a.speak();

 上面代码中,ta们都具有speak方法。由于speak方法是生成在每个实例对象上面,所以两个实例就生成了两次。也就是说,每新建一个实例,就会新建一个speak方法。这既没有必要,又浪费系统资源,因为所有speak方法都是同样的行为,完全应该共享。
这个问题的解决方法,就是 JavaScript 的原型对象(prototype)。
prototype 属性的作用
JavaScript 继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享。也就是说,如果属性和方法定义在原型上,那么所有实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。
下面,先看怎么为对象指定原型。JavaScript 规定,每个函数都有一个prototype属性,指向一个对象。
function f() {}
typeof f.prototype // "object"
上面代码中,函数f默认具有prototype属性,指向一个对象。
对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型。
function Animal(name) {
  this.name = name;
}
Animal.prototype.color = 'white';
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
cat1.color // 'white'
cat2.color // 'white'
上面代码中,构造函数Animal的prototype属性,就是实例对象cat1和cat2的原型对象。原型对象上添加一个color属性,结果,实例对象都共享了该属性。
原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上。
Animal.prototype.color = 'yellow';
cat1.color // "yellow"
cat2.color // "yellow"
上面代码中,原型对象的color属性的值变为yellow,两个实例对象的color属性立刻跟着变了。这是因为实例对象其实没有color属性,都是读取原型对象的color属性。也就是说,当实例对象本身没有某个属性或方法的时候,它会到原型对象去寻找该属性或方法。这就是原型对象的特殊之处。
如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
cat1.color = 'black';
cat1.color // 'black'
cat2.color // 'yellow'
Animal.prototype.color // 'yellow';
上面代码中,实例对象cat1的color属性改为black,就使得它不再去原型对象读取color属性,后者的值依然为yellow。
总结一下,原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象。
Animal.prototype.walk = function () {
  console.log(this.name + ' is walking');
};
上面代码中,Animal.prototype对象上面定义了一个walk方法,这个方法将可以在所有Animal实例对象上面调用。
原型链
JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了Object.prototype的属性。这就是所有对象都有valueOf和toString方法的原因,因为这是从Object.prototype继承的。
那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是null。null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。
Object.getPrototypeOf(Object.prototype)
// null
上面代码表示,Object.prototype对象的原型是null,由于null没有任何属性,所以原型链到此为止。Object.getPrototypeOf方法返回参数对象的原型
 
 读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding)。
注意,一级级向上,在整个原型链上寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
举例来说,hasownProperty 有没有属于自己的属性
 
constructor 属性
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
function A() {}
A.prototype.constructor === A // true
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jZCrFYOK-1673296212463)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109203424591.png)]](https://img-blog.csdnimg.cn/d368fea443aa4923a002f5d7dbf0c75e.png)
 由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承。
function A() {}
var a = new A();
a.constructor === A // true
a.constructor === A.prototype.constructor // true
a.hasOwnProperty('constructor') // false
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TufrqtzS-1673296263478)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109203655639.png)]](https://img-blog.csdnimg.cn/aad9d3e7168c4f37b146ab7362f5c102.png)
上面代码中,p是构造函数P的实例对象,但是p自身没有constructor属性,该属性其实是读取原型链上面的P.prototype.constructor属性。
constructor属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的。
instanceof 运算符
instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例。
var v = new Vehicle();
v instanceof Vehicle // true
上面代码中,对象v是构造函数Vehicle的实例,所以返回true。
instanceof运算符的左边是实例对象,右边是构造函数。它会检查右边构造函数的原型对象(prototype),是否在左边对象的原型链上。
var d = new Date();
d instanceof Date // true
d instanceof Object // true
上面代码中,d同时是Date和Object的实例,因此对这两个构造函数都返回true。
由于任意对象(除了null)都是Object的实例,所以instanceof运算符可以判断一个值是否为非null的对象。
构造函数的继承
举例来说,下面是一个Shape构造函数。
function Shape() {
  this.x = 0;
  this.y = 0;
}
Shape.prototype.move = function (x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qz2TE9Rn-1673296318783)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109210153396.png)]](https://img-blog.csdnimg.cn/c61abafe261a49a98ba66eddedadf33b.png)
例如:我们需要让Rectangle构造函数继承Shape。
// 第一步,子类继承父类的实例
function Rectangle() {
  Shape.call(this); // 调用父类构造函数
}
// 另一种写法
function Rectangle() {
  this.base = Shape;
  this.base();
}
// 第二步,子类继承父类的原型
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
Rectangle.prototype继承了 Object.create(Shape.prototype)的属性;
Rectangle.prototype.constructor 继承了Rectangle的属性。
 
多重继承
JavaScript 不提供多重继承功能,即不允许一个对象同时继承多个对象。但是,可以通过变通方法,实现这个功能。
function M1() {
  this.hello = 'hello';
}
function M2() {
  this.world = 'world';
}
function S() {
  M1.call(this);
  M2.call(this);
}
// 继承 M1
S.prototype = Object.create(M1.prototype);
// 继承链上加入 M2
Object.assign(S.prototype, M2.prototype);
// 指定构造函数
S.prototype.constructor = S;
var s = new S();
s.hello // 'hello'
s.world // 'world'
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KKJuuGIC-1673296375560)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109211018865.png)]](https://img-blog.csdnimg.cn/39c2e605af104f09bc734196ad395434.png)
上面代码中,子类S同时继承了父类M1和M2。这种模式又称为 Mixin(混入)。
array
Array 对象
构造函数
Array是 JavaScript 的原生对象,同时也是一个构造函数,可以用它生成新的数组。
var arr = new Array(2);
arr.length // 2
arr // [ empty x 2 ]
上面代码中,Array()构造函数的参数2,表示生成一个两个成员的数组,每个位置都是空值。
如果没有使用new关键字,运行结果也是一样的。
var arr = Array(2);
// 等同于
var arr = new Array(2);
考虑到语义性,以及与其他构造函数用法保持一致,建议总是加上new。
Array()构造函数有一个很大的缺陷,不同的参数个数会导致不一致的行为。
// 无参数时,返回一个空数组
new Array() // []
// 单个正整数参数,表示返回的新数组的长度
new Array(1) // [ empty ]
new Array(2) // [ empty x 2 ]
// 非正整数的数值作为参数,会报错
new Array(3.2) // RangeError: Invalid array length
new Array(-3) // RangeError: Invalid array length
// 单个非数值(比如字符串、布尔值、对象等)作为参数,
// 则该参数是返回的新数组的成员
new Array('abc') // ['abc']
new Array([1]) // [Array[1]]
// 多参数时,所有参数都是返回的新数组的成员
new Array(1, 2) // [1, 2]
new Array('a', 'b', 'c') // ['a', 'b', 'c']
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e4hDvoSc-1673296846022)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109220255825.png)]](https://img-blog.csdnimg.cn/7dac630ed02e4844b4c2ee25c82035a4.png)
可以看到,Array()作为构造函数,行为很不一致。因此,不建议使用它生成新数组,直接使用数组字面量是更好的做法。
// bad
var arr = new Array(1, 2);
// good
var arr = [1, 2];
注意,如果参数是一个正整数,返回数组的成员都是空位。虽然读取的时候返回undefined,但实际上该位置没有任何值。虽然这时可以读取到length属性,但是取不到键名。
var a = new Array(3);
var b = [undefined, undefined, undefined];
a.length // 3
b.length // 3
a[0] // undefined
b[0] // undefined
0 in a // false
0 in b // true
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3XbxlMQk-1673296902675)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109220658917.png)]](https://img-blog.csdnimg.cn/6e96a944563849c7a7f458d5b63728c4.png)
上面代码中,a是Array()生成的一个长度为3的空数组,b是一个三个成员都是undefined的数组,这两个数组是不一样的。读取键值的时候,a和b都返回undefined,但是a的键名(成员的序号)都是空的,b的键名是有值的
实例方法
valueOf(),toString()
valueOf方法表示对该对象求值。不同对象的valueOf方法不尽一致,数组的valueOf方法返回数组本身。
var arr = [1, 2, 3];
arr.valueOf() // [1, 2, 3]
toString方法也是对象的通用方法,数组的toString方法返回数组的字符串形式。
var arr = [1, 2, 3];
arr.toString() // "1,2,3"
var arr = [1, 2, 3, [4, 5, 6]];
arr.toString() // "1,2,3,4,5,6"
push(),pop()
push`方法用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
var arr = [];
arr.push(1) // 1
arr.push('a') // 2
arr.push(true, {}) // 4
arr // [1, 'a', true, {}]
上面代码使用push方法,往数组中添加了四个成员。
pop方法用于删除数组的最后一个元素,并返回该元素。注意,该方法会改变原数组。
var arr = ['a', 'b', 'c'];
arr.pop() // 'c'
arr // ['a', 'b']
对空数组使用pop方法,不会报错,而是返回undefined。
[].pop() // undefined
push和pop结合使用,就构成了“后进先出”的栈结构(stack)。
var arr = [];
arr.push(1, 2);
arr.push(3);
arr.pop();
arr // [1, 2]
上面代码中,3是最后进入数组的,但是最早离开数组。
shift(),unshift()
shift()方法用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组。
var a = ['a', 'b', 'c'];
a.shift() // 'a'
a // ['b', 'c']
删除空数组会返回undefined
var a = ['a', 'b', 'c'];
a.shift()
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zGUlE3U6-1673296902676)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109221946062.png)]](https://img-blog.csdnimg.cn/60e547fc25a54d838227780d688c09d9.png)
 shift()方法可以遍历并清空一个数组。
var list = [1, 2, 3, 4];
var item;
while (item = list.shift()) {
  console.log(item);
}
list // []

 上面代码通过list.shift()方法每次取出一个元素,从而遍历数组。它的前提是数组元素不能是0或任何布尔值等于false的元素,因此这样的遍历不是很可靠。
push()和shift()结合使用,就构成了“先进先出”的队列结构(queue)。
unshift()方法用于在数组的第一个位置添加元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
var a = ['a', 'b', 'c'];
a.unshift('x'); // 4
a // ['x', 'a', 'b', 'c']
unshift()方法可以接受多个参数,这些参数都会添加到目标数组头部。
var arr = [ 'c', 'd' ];
arr.unshift('a', 'b') // 4
arr // [ 'a', 'b', 'c', 'd' ]
join()
join()方法以指定参数作为分隔符,将所有数组成员连接为一个字符串返回。如果不提供参数,默认用逗号分隔。
var a = [1, 2, 3, 4];
a.join(' ') // '1 2 3 4'
a.join(' | ') // "1 | 2 | 3 | 4"
a.join() // "1,2,3,4"
如果数组成员是undefined或null或空位,会被转成空字符串。
[undefined, null].join('#')
// '#'
['a',, 'b'].join('-')
// 'a--b'
slice()
slice()方法相当于切片
它的第一个参数为起始位置(从0开始,会包括在返回的新数组之中),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。
var a = ['a', 'b', 'c'];
a.slice(0) // ["a", "b", "c"]
a.slice(1) // ["b", "c"]
a.slice(1, 2) // ["b"]
a.slice(2, 6) // ["c"]
a.slice() // ["a", "b", "c"]
上面代码中,最后一个例子slice()没有参数,实际上等于返回一个原数组的拷贝。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IWt3NX8q-1673297170182)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109222541022.png)]](https://img-blog.csdnimg.cn/bb13391bb7c04c0a82ea21563c3abedf.png)
果slice()方法的参数是负数,则表示倒数计算的位置。
var a = ['a', 'b', 'c'];
a.slice(-2) // ["b", "c"]
a.slice(-2, -1) // ["b"]
上面代码中,-2表示倒数计算的第二个位置,-1表示倒数计算的第一个位置。
如果第一个参数大于等于数组长度,或者第二个参数小于第一个参数,则返回空数组。
var a = ['a', 'b', 'c'];
a.slice(4) // []
a.slice(2, 1) // []
slice()方法的一个重要应用,是将类似数组的对象转为真正的数组。
Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })
// ['a', 'b']
Array.prototype.slice.call(document.querySelectorAll("div"));
上面代码的参数都不是数组,但是通过call方法,在它们上面调用slice()方法,就可以把它们转为真正的数组。
sort()
sort方法对数组成员进行排序,默认是按照字典顺序排序。排序后,原数组将被改变。
['d', 'c', 'b', 'a'].sort()
// ['a', 'b', 'c', 'd']
[4, 3, 2, 1].sort()
// [1, 2, 3, 4]
[11, 101].sort()
// [101, 11]
[10111, 1101, 111].sort()
// [10111, 1101, 111]
上面代码的最后两个例子,需要特殊注意。sort()方法不是按照大小排序,而是按照字典顺序。也就是说,数值会被先转成字符串,再按照字典顺序进行比较,所以101排在11的前面。
 
map()
map()方法将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。
var numbers = [1, 2, 3];
numbers.map(function (n) {
  return n + 1;
});
// [2, 3, 4]
numbers
// [1, 2, 3]
上面代码中,numbers数组的所有成员依次执行参数函数,运行结果组成一个新数组返回,原数组没有变化。
filter()
filter()方法用于过滤数组成员,满足条件的成员组成一个新数组返回。
它的参数是一个函数,所有数组成员依次执行该函数,返回结果为true的成员组成一个新数组返回。该方法不会改变原数组。
[1, 2, 3, 4, 5].filter(function (elem) {
  return (elem > 3);
})
// [4, 5]
上面代码将大于3的数组成员,作为一个新数组返回。
var arr = [0, 1, 'a', false];
arr.filter(Boolean)
// [1, "a"]
上面代码中,filter()方法返回数组arr里面所有布尔值为true的成员。
filter()方法的参数函数可以接受三个参数:当前成员,当前位置和整个数组。
[1, 2, 3, 4, 5].filter(function (elem, index, arr) {
  return index % 2 === 0;
});
// [1, 3, 5]
上面代码返回偶数位置的成员组成的新数组。
总结
那些方法会改变原数组
1、push()
2、pop()
3、shift()
4、unshift()
5、sort()
那些方法不会改变原数组
1、map()
2、filter()
json
JSON 对象
JSON 格式
JSON 格式(JavaScript Object Notation 的缩写)是一种用于数据交换的文本格式,2001年由 Douglas Crockford 提出,目的是取代繁琐笨重的 XML 格式。
相比 XML 格式,JSON 格式有两个显著的优点:
1、书写简单,一目了然;
2、符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。所以,JSON 迅速被接受,已经成为各大网站交换数据的标准格式,并被写入标准。
每个 JSON 对象就是一个值,可能是一个数组或对象,也可能是一个原始类型的值。总之,只能是一个值,不能是两个或更多的值。
JSON 对值的类型和格式有严格的规定。
复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
原始类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和null(不能使用
NaN,Infinity,-Infinity和undefined)。NAN 不是一个数字
Infinity 无穷大 1/0
-Infinity 无穷小 -1/0
undefined 未定义
字符串必须使用双引号表示,不能使用单引号。
对象的键名必须放在双引号里面。
数组或对象最后一个成员的后面,不能加逗号。
以下都是合法的 JSON。
["one", "two", "three"]
{ "one": 1, "two": 2, "three": 3 }
{"names": ["张三", "李四"] }
[ { "name": "张三"}, {"name": "李四"} ]
以下都是不合法的 JSON。
{ name: "张三", 'age': 32 }  // 属性名必须使用双引号
[32, 64, 128, 0xFFF] // 不能使用十六进制值
{ "name": "张三", "age": undefined } // 不能使用 undefined
{ "name": "张三",
  "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
  "getName": function () {
      return this.name;
  }
} // 属性值不能使用函数和日期对象
注意,null、空数组和空对象都是合法的 JSON 值。
JSON 对象
JSON对象是 JavaScript 的原生对象,用来处理 JSON 格式数据。它有两个静态方法:JSON.stringify()和JSON.parse()。
JSON.stringify()
JSON.stringify()可以将一个值转为 JSON 字符串
JSON.stringify('abc') // ""abc""
JSON.stringify(1) // "1"
JSON.stringify(false) // "false"
JSON.stringify([]) // "[]"
JSON.stringify({}) // "{}"
JSON.stringify([1, "false", false])
// '[1,"false",false]'
JSON.stringify({ name: "张三" })
// '{"name":"张三"}'
上面代码将各种类型的值,转成 JSON 字符串。
注意,对于原始类型的字符串,转换结果会带双引号。
JSON.stringify('foo') === "foo" // false
JSON.stringify('foo') === "\"foo\"" // true
上面代码中,字符串foo,被转成了"\"foo\""。这是因为将来还原的时候,内层双引号可以让 JavaScript 引擎知道,这是一个字符串,而不是其他类型的值。
JSON.stringify(false) // "false"
JSON.stringify('false') // "\"false\""
上面代码中,如果不是内层的双引号,将来还原的时候,引擎就无法知道原始值是布尔值还是字符串。
JSON.stringify()`方法会忽略对象的不可遍历的属性。
var obj = {};
Object.defineProperties(obj, {
  'foo': {
    value: 1,
    enumerable: true
  },
  'bar': {
    value: 2,
    enumerable: false
  }
});
JSON.stringify(obj); // "{"foo":1}"
上面代码中,bar是obj对象的不可遍历属性,JSON.stringify方法会忽略这个属性。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pYTEsydp-1673296424516)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109232351262.png)]](https://img-blog.csdnimg.cn/2ed9e08bedc1410890de0ec7b69cdab0.png)
第二个参数
1、JSON.stringify()方法还可以接受一个数组,作为第二个参数,指定参数对象的哪些属性需要转成字符串。
var obj = {
  'prop1': 'value1',
  'prop2': 'value2',
  'prop3': 'value3'
};
var selectedProperties = ['prop1', 'prop2'];
JSON.stringify(obj, selectedProperties);
// "{"prop1":"value1","prop2":"value2"}"
上面代码中,JSON.stringify()方法的第二个参数指定,只转prop1和prop2两个属性。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3DS4tK9T-1673296424516)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109233738726.png)]](https://img-blog.csdnimg.cn/a2b44437d14e4343b29facbb2ee1fabe.png)
2、第二个参数还可以是一个函数,用来更改JSON.stringify()的返回值。
function f(key, value) {
  if (typeof value === "number") { //typeof 判断类型
    value = 2 * value;
  }
  return value;
}
JSON.stringify({ a: 1, b: 2 }, f)
// '{"a": 2,"b": 4}'
上面代码中的f函数,接受两个参数,分别是被转换的对象的键名和键值。如果键值是数值,就将它乘以2,否则就原样返回。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zfoVPt4q-1673296424517)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230109234559842.png)]](https://img-blog.csdnimg.cn/3b9567aee59a48d39d3fb32783a3d4c0.png)
参数对象的 toJSON() 方法
如果参数对象有自定义的toJSON()方法,那么JSON.stringify()会使用这个方法的返回值作为参数,而忽略原对象的其他属性。
下面是一个普通的对象。
var user = {
  firstName: '三',
  lastName: '张',
  get fullName(){
    return this.lastName + this.firstName;
  }
};
JSON.stringify(user)
// "{"firstName":"三","lastName":"张","fullName":"张三"}"
现在,为这个对象加上toJSON()方法。
var user = {
  firstName: '三',
  lastName: '张',
   toJSON: function () {
    return {
      name: this.lastName + this.firstName
    };
  };
;
JSON.stringify(user);
// "{"name":"张三"}"
上面代码中,JSON.stringify()发现参数对象有toJSON()方法,就直接使用这个方法的返回值作为参数,而忽略原对象的其他参数。
Date对象就有一个自己的toJSON()`方法。
var date = new Date('2015-01-01');
date.toJSON() // "2015-01-01T00:00:00.000Z"
JSON.stringify(date) // ""2015-01-01T00:00:00.000Z""
上面代码中,JSON.stringify()发现处理的是Date对象实例,就会调用这个实例对象的toJSON()方法,将该方法的返回值作为参数。
toJSON()方法的一个应用是,将正则对象自动转为字符串。因为JSON.stringify()默认不能转换正则对象,但是设置了toJSON()方法以后,就可以转换正则对象了。
JSON.parse()
JSON.parse()可以**将一个字符串转为 JSON值 **
JSON.parse('{}') // {}
JSON.parse('true') // true
JSON.parse('"foo"') // "foo"
JSON.parse('[1, 5, "false"]') // [1, 5, "false"]
JSON.parse('null') // null
var o = JSON.parse('{"name": "张三"}');
o.name // 张三
如果传入的字符串不是有效的 JSON 格式,JSON.parse()方法将报错。
JSON.parse("'String'") // illegal single quotes
// SyntaxError: Unexpected token ILLEGAL
上面代码中,双引号字符串中是一个单引号字符串,因为单引号字符串不符合 JSON 格式,所以报错。
为了处理解析错误,可以将JSON.parse()方法放在try...catch代码块中。
try {
  JSON.parse("'String'");
} catch(e) {
  console.log('parsing error');
}
JSON.parse()方法可以接受一个处理函数,作为第二个参数,用法与JSON.stringify()方法类似。
function f(key, value) {
  if (key === 'a') {
    return value + 10;
  }
  return value;
}
JSON.parse('{"a": 1, "b": 2}', f)
// {a: 11, b: 2}
上面代码中,JSON.parse()的第二个参数是一个函数,如果键名是a,该函数会将键值加上10。
总结
1、JSON.parse()可以**将一个字符串转为 JSON值 **
var JSON_parse = '{"name":"张三","age":"18","身高":"1.8"}';
var obj = JSON.parse(JSON_parse);
console.log(obj); //{name: '张三', age: '18', 身高: '1.8'}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eOQsbKIC-1673296587084)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230110002958857.png)]](https://img-blog.csdnimg.cn/701e296466554e6a97cb59a8b89c75b2.png)
2、JSON.stringify()可以将一个值转为 JSON 字符串
var JSON_stringify = '{name:李四, age:28 , 身高:1.8}';
var obj = JSON.stringify(JSON_stringify);
console.log(obj);
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xqMlC1B2-1673296587084)(C:\Users\86155\AppData\Roaming\Typora\typora-user-images\image-20230110003712622.png)]](https://img-blog.csdnimg.cn/facc52ec53f44409813a4d1be8845a52.png)
















![[2023] NAND闪存及控制器的市场趋势](https://img-blog.csdnimg.cn/img_convert/74451631d2ff5c81ba79ba8d4f300e41.jpeg)

