10-02-复习 jsonp、call、apply、bind、new原理

本文详细介绍了JavaScript中的同源策略,解释了为什么浏览器会有这样的安全机制,并探讨了在Android、iOS以及React Native、Flutter等移动开发中是否存在跨域问题。同时,深入解析了JSONP的工作原理,展示了如何通过JSONP来绕过同源策略的限制。此外,还涵盖了call、apply、bind以及new操作符的原理和用法。
摘要由CSDN通过智能技术生成

发送传统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:

  1. 改变this指向
  2. bind前面的函数不执行
  3. 返回一个绑定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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值