发送传统ajax的几大经典步骤
// 第1步:创建一个xhr对象
let xhr = new XMLHttpRequest();
// 第2步:设置连接
xhr.open("get","http://localhost:3000/api/v1")
// 第4步:监听xhr状态变化
if(xhr.onreadystatechange == 4 && xhr.status == 200){
console.log(xhr.responseText)
}
// 第3步:发出请求
xhr.send(null)
什么是同源策略?
答:同源策略是为了保证用户信息安全,是浏览器的机制,防止恶意的网站窃取别人的数据,只允许访问来自同一个站点的资源
同源是指:协议相同,域名相同,端口相同。这三者相同就是同源。如果不同源,浏览器就会作出限制。
开发android或ios有跨域问题吗?
答:没有
使用RN或flutter开发原生APP,有跨域问题?
答:没有
JSONP原理
JSONP不是ajax发送的请求,是script标签的src发送的请求。
jsonp原理.js
// JSONP原理
function jsonp(options){
// 1)产生一个函数名(函数名随机)
let callBackName = 'wancai'+Math.random().toString().substr(2) + Math.random().toString().substr(2);
// 2)定义函数 全局函数
window[callBackName] = function(params){
if (params !== null){
options.success(params)
}else{
options.failure(params)
}
// 2-1) 删除之前创建的scripte标签
scriptE.remove();
// 2-2) 把创建的全局函数设置为null
window[callBackName] = null;
}
// 3)取出url地址
let jonspUrl;
if(options.data !== undefined){
jonspUrl = options.url + "?" + options.data + "&callBack="+callBackName
}else{
jonspUrl = options.url + "?callBack="+callBackName
}
// 4)创建一个script标签
let scriptE = document.createElement("script");
scriptE.src = jonspUrl
document.body.appendChild(scriptE)
}
let btn = document.getElementById("btn");
btn.addEventListener("click",()=>{
/* // 第1步:创建一个xhr对象
let xhr = new XMLHttpRequest();
// 第2步:设置连接
xhr.open("get","http://localhost:3000/api/v1")
// 第4步:监听xhr状态变化
if(xhr.onreadystatechange == 4 && xhr.status == 200){
console.log(xhr.responseText)
}
// 第3步:发出请求
xhr.send(null)*/
// 使用JSONP发出请求
jsonp({
url:"http://localhost:3000/api/v1",
data:"a=1&b=2",
success:function (data) {
console.log(data)
},
failure:function (data) {
console.log("数据请求失败")
}
})
})
server.js
let express = require("express");
let app = express();
app.get("/api/v1",(req,res)=>{
/* console.log(`${req.query.callBack}(${ JSON.stringify({
"name":"wangcai",
"age":100
}) })`);*/
res.send(`${req.query.callBack}(${ JSON.stringify({
"name":"wangcai",
"age":100
}) })`)
})
app.listen(3000,()=>{
console.log("server is running on 3000~")
})
index.html
<button id="btn">发送JSONP请求</button>
<script src="./jsonp原理.js"></script>
call原理
- 改变this指向
- 让函数立即执行
基本使用:
function fn(num1,num2) {
console.log(this)
return num1+num2;
}
fn(); // => window
fn.call(); // => window // 1)改变this指向 2)让fn执行
let obj = {name:"wc"}
console.log(fn.call(obj,1,2))
// => {name: "wc"} // call也可以传递参数
定义一个函数,函数也是对象,对象就可以 .call ,如果不传递参数或直接调用,函数中的this指向window;传递的第一个参数是obj,函数中的this就指向obj。
模拟call
<script>
;(function(){ //context是obj
function mycall(context){
context = context ? Object(context) : window;
// g调用了mycall,mycall中this指g,所以这个this代表g函数
//context.f表示obj打点调用g函数,所以g函数中的this指向obj
context.f = this;
let args = [];
for(let i = 1; i<arguments.length; i++){
args.push(arguments[i])
}
let res = context.f(...args);
delete context.f;
return res;
}
//每个函数对象上都挂一个mycall方法
Function.prototype.mycall = mycall;
}())
function g(a,b) {
console.log(this);
return a+b;
}
let obj = {name:"wc"}
let r = g.mycall(obj,6,6);
console.log(r)
</script>
apply原理
- 改变this指向
- 让函数立即执行
apply和call的区别:
仅仅是传参的区别,作用一样。apply有参数时,以数组的形式进行传递。
<script>
;(function () {
function myapply(context,args) {
context = context ? Object(context) : window;
context.gn = this;
if(!args){
return context.gn();
}
let res = context.gn(...args)
delete context.gn;
return res;
}
Function.prototype.myapply = myapply;
}())
// 模拟apply的实现
function fn(num1,num2) {
console.log(this)
return num1 + num2;
}
console.log( fn.apply())
let obj = {name:"wc"}
console.log(fn.myapply(obj))
console.log(fn.myapply(obj,[1,2]))
</script>
bind原理
call、apply、bind
三者都是用于改变函数体内this的指向,但是bind与apply和call的最大的区别是:bind不会立即调用,而是返回一个新函数,称为绑定函数,其内的this指向为创建它时传入bind的第一个参数,而传入bind的第二个及以后的参数作为原函数的参数来调用原函数。
bind:
- 改变this指向
- bind前面的函数不执行
- 返回一个绑定this之后的函数
bind的使用
<script>
function fn(num1, num2) {
console.log(this)
console.log(num1 + num2)
return num1 + num2;
}
let obj = { name: "wc" }
let gn = fn.bind(obj, 1, 2)
console.log(gn); //函数fn
gn(); //结果:{name:"wc} 3
console.log(gn()); //结果:{name:"wc} 3 3
</script>
<script>
function fn(num1, num2) {
console.log(this)
console.log(num1 + num2)
return num1 + num2;
}
let obj = { name: "wc" }
let gn = fn.bind(obj)
gn(4,5) //结果 {name:"wc} 9
console.log(gn(4,5)); //结果:{name:"wc} 9 9
</script>
let obj = { name:"wc" }
let gn = fn.bind(obj,6);
console.log(gn(8)); 结果 //结果:{name:"wc} 14 14
分别传给num1和num2,相当于传了[1,2]
let obj = { name:"wc" }
let gn = fn.bind(obj,6,6);
console.log(gn(8,8)); 结果 //结果:{name:"wc} 12 12
相当于传了[6,6,8,8]
bind的原理
<script>
;(function () {
function mybind(context) {
// arguments是伪数组 可以转成数组(slice,1,删除数组的第一个元素)
let bindArgs = Array.prototype.slice.call(arguments,1);
// this指的是下面的fn函数 that指fn
let that = this;
function xxx() {
//args表示可能是在调用gn函数时的传参
let args = Array.prototype.slice.call(arguments);
// this 指window 因为下面是window调用的
//concat 连接数组
return that.apply(context, bindArgs.concat(args)) // [1,3]
}
return xxx; //需要返回一个函数
}
Function.prototype.mybind = mybind;
}())
function fn(num1,num2) {
console.log(this)
console.log(num1+num2)
return num1+num2;
}
let obj = { name:"wc" }
let gn = fn.mybind(obj,1,2)
console.log(gn())
</script>
<script>
;(function () {
function mybind(context){
let bindArgs = Array.prototype.slice.call(arguments,1)
// this就是fn
let that = this;
function Mn() {}
function xxx() {
// console.log(this) 这个this和下面new出的函数o指向一个队形
let args = Array.prototype.slice.call(arguments)
//如果this是xxx构造器构造的,就说明new了,就让fn中this指向new创建的
return that.apply(this instanceof xxx ? this : context,bindArgs.concat(args))
}
// xxx.prototype = this.prototype; // 相当于改变xxx的原型会影响 fn的原型
Mn.prototype = this.prototype;
xxx.prototype = new Mn();
xxx.prototype.m2 = 666;
return xxx;
}
Function.prototype.mybind = mybind;
}())
function fn(a,b) {
console.log(this)
console.log(a+b)
return a+b;
}
fn.prototype.m1 = 888;
let obj = {name:"wc"}
let gn = fn.mybind(obj,1)
// console.log(gn(2));
let o = new gn(2);
console.log(o.m1)
console.log(fn.prototype.m2)
</script>
new原理
内部创建一个对象 让this指向这个对象 返回这个对象
<script>
function Dog(name) {
// 内部创建一个对象 让this指向这个对象 返回这个对象
this.name = name; // 私有属性
// return 123; // 返回基本数据类型没有任何含义
/*return {
age:100
}*/
}
Dog.prototype.say = function(){ // 公有属性
console.log("say...")
}
let wc = new Dog("wangcai")
console.log(wc)
console.log(wc.name)
console.log(wc.say())
</script>
new是运算符,运算符只能使用函数来模拟
<script>
// 模拟new的实现 问:new是什么? 答:运算符 现在要模拟运算符
// 运算符只能使用函数来模拟
function myNew() {
//context等于Dog,shift会删除第一个并返回
// let context = Array.prototype.shift.call(arguments)
let context = [].shift.call(arguments)
let newObj = {};
newObj.__proto__ = context.prototype
let r = context.apply(newObj,arguments)
return r instanceof Object ? r : newObj;
}
function Dog(name) {
this.name = name;
}
Dog.prototype.say = function(){ // 公有属性
console.log("say...")
}
// let wc = new Dog("wangcai",1,2,3)
let wc = myNew(Dog,"wangcai",1,2,3)
console.log(wc)
console.log(wc.name)
console.log(wc.say())
</script>