博主入职两个月了,越来越感受到打好基础对于前端工程师的重要性,在向着狂拽酷炫的框架&构建工具狂飚之前,必须有一个坚实的基础打底,才不至于轻易翻车。所以博主最近一直在恶补《JS高级程序设计》,发现了很多第一次读时忽略的、有趣的地方。不愧是经典,常读常新呀!

PART 1  最熟悉的陌生人——动态脚本


对于一些刚接触前端不久的同学来说,“动态脚本”可能是一个有些陌生的字眼,我也是偶然看高程,才想起同桌的你……不,才注意到这个技术。但事实上,这是每个前端每天都会用到的技术,也是从jQuery到各种狂拽酷炫的前端框架得以运行的基础技术。那它到底是谁呢?

来看一行代码:

<script src="jquery.js"></script>

眼熟吧?

写过吧?

恭喜你,你已经是会使用动态脚本技术的前端攻城狮了!

……纳尼?

没错!不要觉得这行代码司空见惯,其实仔细研究下,还颇有点因缺斯艇呢~

记住一点,网页归根到底就是一个HTML页面,除此之外别无他物。其他如JS、CSS、图片等,都是页面上的资源,从属于这个页面。JS代码只有作为script类型的DOM节点的内部文本的形式被添加到网页上,在浏览器解析DOM结构解析到script节点时,才会被执行。动态脚本,顾名思义,是“动态”的JS代码——“动态”的意思是,不是预先写在HTML页面上的,而是在页面解析的过程中被添加上去的。

动态添加脚本有两种方法:一是DOM操作,像插入其他类型的DOM节点一样插入一个script节点到页面,其内部的JS代码会被立即执行;二是如jQuery那个例子所示,从某个路径加载js文件到页面上来,可以理解为文件中的代码被复制粘贴到这个script标签中了,这些代码会在加载完成后被执行。

举个栗子:

<!-- 出于简略,只写body的代码 -->
<body>
<!-- 静态脚本 -->
<script>
console.log(1);
var scriptDOM = document.createElement('script');
scriptDOM.innerHTML = 'console.log(2);'; // 动态脚本的内容
document.body.appendChild(scriptDOM); // 动态插入script DOM节点
console.log(3);
</script>
</body>

这个页面上有一段静态脚本,其在执行时会向body插入一个script子节点。用浏览器打开这个页面,console会顺序打印出“1  2  3”这三个数字。查看页面,变成了这样:

<!-- 出于简略,只写body的代码 -->
<body>
<!-- 静态脚本 -->
<script>
console.log(1);
var scriptDOM = document.createElement('script');
scriptDOM.innerHTML = 'console.log(2);'; // 动态脚本的内容
document.body.appendChild(scriptDOM); // 动态插入script DOM节点
console.log(3);
</script>
<!-- 动态插入的的脚本 -->
<script>console.log(2);</script>
</body>

这个最终页面有趣的地方在于,包裹“console.log(2);”的script标签明明排在原来的标签的后面,但2却比3先打印出来。事实上,往任何地方插入动态脚本,其中的代码都会在插入后立刻执行。通过src属性引入的JS代码也是如此,一旦加载完成就立刻执行。

这是脚本语言灵活性的绝佳体现呀!想想编译型语言如C++、Java,所有代码必须预先编译好才能执行,无法做到像JS这样,不用编译不说,还可以在原本的代码执行到一半时,忽然插进来一堆新代码并且立即得到执行;就好比原本宴会邀请到了99个宾客,饭吃到一半,忽然来了个不速之客,还是个自来熟,坐下就开始与众人谈笑风生、觥筹交错,于是东道主JavaScript顺手就把宾客人数改成了100,毫无违和感;若是换成C++或Java做东,只会在宴会开始后把所有入口全部封死,不再允许任何人进入。

PART 2  动态脚本的应用:JSONP


“跨域”是前端面试中几乎必考的问题,而JSONP是一个比较简单好使的解决方案。

JSONP诞生的背景是,“跨域”只是AJAX所受的安全策略限制,只要域名协议端口这3项有1项不一致,浏览器就禁止发送AJAX请求。而像<script><img><link>这类标签的src属性不受此限,可以填写任意域名的地址(想想jQuery的CDN地址,还有一堆图床网站……)。于是聪明的前端攻城狮们想到了利用动态脚本来获取json数据的套路,名曰JSON Padding,意思是“JSON填充”。

那具体怎么个做法呢?分三步

步骤1

让服务器端略改下代码:当一个get请求的查询参数里有callback一项时,譬如一个URL长这样:

http://someurl.com/data?callback=handler

那么服务器就不要直接把JSON文件作为响应内容了,而是返回一个动态生成的JS文件,其中的代码是

handler({JSON数据});

其实就是一个handler函数的调用,同时把JSON作为参数“填充”进去。

步骤2

回到前端。定义好负责处理JSON数据的handler函数:

function handler(json) {
// 处理json数据
}

步骤3

在需要跨域获取数据时,向页面插入一个script DOM元素:

var script= document.createElement('script');
script.src = 'http://someurl.com/data?callback=handler';
document.body.appendChild(script);

这个script元素的src属性值带有一个callback查询参数,于是服务器会返回步骤1中的代码,这段代码被下载完成后立刻执行,handler恰好是已经定义好的函数,而梦寐以求的跨域JSON数据就这样作为handler的实参被传到了当前页面上!

最后是两点注意事项:

1. 用这种方法可以请求任何类型的数据,不限制为JSON,只是因为JSON最常用,所以命名为JSONP。

2. JSONP是为了帮AJAX绕开跨域限制而使用的一种技巧,它本身跟AJAX没有半毛钱关系,在不支持AJAX的浏览器上照样可以用JSONP技术。

【前端基础】动态脚本与JSONP的更多相关文章

  1. 前端基础面试题(JS部分)

    1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构? 基本数据类型:Undefined.Null.Boolean.Number.String 值类型:数值.布尔值.null.und ...

  2. BAT 前端开发面经 —— 吐血总结 前端相关片段整理——持续更新 前端基础精简总结 Web Storage You don't know js

    BAT 前端开发面经 —— 吐血总结   目录 1. Tencent 2. 阿里 3. 百度 更好阅读,请移步这里 聊之前 最近暑期实习招聘已经开始,个人目前参加了阿里的内推及腾讯和百度的实习生招聘, ...

  3. 前端基础面试题(js部分)

      前端基础面试题(JS部分)   1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构? 基本数据类型:Undefined.Null.Boolean.Number.String值类 ...

  4. web前端基础知识及快速入门指南

    web前端基础知识及快速入门指南 做前端开发有几个月了,虽然说是几个月,但是中间断断续续的上课.考试以及其它杂七杂八的事情,到现在居然一直感觉自己虽然很多前端的知识很眼熟,却也感觉自己貌似也知识在门口 ...

  5. web前端基础学习路线

    1.HTML和CSS的基础知识,完成网页的初步设计 2.JavaScript基础知识和DOM.BOM的学习 3.前端基础框架:CSS框架Bootstrap.JavaScript框架jquery的熟悉使 ...

  6. JS BOM DOM对象 select联动 计时器 时间 css操作 节点(标签 ) 查找标签 {前端基础之BOM和DOM}

    前端基础之BOM和DOM 前戏 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的一些交互,我 ...

  7. 前端基础之BOM和DOM day52

    前端基础之BOM和DOM   前戏 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的一些交互 ...

  8. 前端基础之JavaScript day51

    前端基础之JavaScript   JavaScript概述 JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中) ...

  9. 浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入

    在<浏览器环境下JavaScript脚本加载与执行探析之defer与async特性>中,我们研究了延迟脚本(defer)和异步脚本(async)的执行时机.浏览器支持情况.浏览器bug以及 ...

随机推荐

  1. 记Angular与Django REST框架的一次合作(1):分离 or 不分离,it's the question

    前言:本次尝试源于我们内部的一个项目,由于前端逻辑比较复杂,就打算将前后端分开来开发.由于之前用Django开发过软件,对Angular.js(Angular 1.0版)也有一定的了解,因此就将技术路 ...

  2. .NET 微服务和Docker容器

    .NET 微服务:适用于容器化 .NET 应用的体系结构 容器和 Docker 简介 什么是 Docker? Docker 术语 Docker 容器.映像和注册表 为 Docker 容器选择 .NET ...

  3. jsp页面中某个src,如某个iframe的src,应该填写什么?可以是html、jsp、servlet、action吗?是如何加载的?

    jsp页面中某个src,如某个iframe的src,应该填写什么?可以是html.jsp.servlet.action吗?是如何加载的? 如有个test工程,其某个jsp中有个iframe,代码如下: ...

  4. js prototype 继承

    //继承 function inherits(ctor,superCtor){ ctor.super_ = superCtor; ctor.prototype = Object.create(supe ...

  5. jQuery全选、全不选、反选的简洁写法【实例】

    全选方面的功能几乎是每个需要列表展示的网站所必不可少的,当然此功能也有很多种写法,现在介绍一下,比较简洁易懂的写法: <input type="checkbox" name= ...

  6. 到底什么样的企业才适合实施SAP系统?

    SAP系统作为全宇宙第一的ERP,号称世界500强里面有80%的企业部署了SAP系统,总部位于德国沃尔多夫市,在全球拥有6万多名员工,遍布全球130个国家,并拥有覆盖全球11,500家企业的合作伙伴网 ...

  7. Linux 粘着位(sticky bit)

    当设置粘着位时只有root或者owner才能删除.重命名文件. 示例: 用户apple默认组为fruit. [root@titan ~]# id apple uid=1001(apple) gid=1 ...

  8. oracle函数和存储过程有什么区别

    oracle函数和存储过程有什么区别 1. 返回值的区别,函数有1个返回值,而存储过程是通过参数返回的,可以有多个或者没有 2.调用的区别,函数可以在查询语句中直接调用,而存储过程必须单独调用. 函数 ...

  9. 关于mac下配置mysql心得

    PS:配置一个mysql烦了一天,不过还是有所收获. 首先,下载安装我就不多啰嗦了.关键是在我们安装的最后会有一个临时密码,例如我的PBxsy=ES71(u: 这是非常重要的信息,如果没有得到的话,建 ...

  10. 关于Genymotion无法启动虚拟设备的问题解决

    只针对于该问题的解决,只需要将该虚拟机的网络设为混杂模式即可. 具体原因,未知.,设置如下