Category - 前端技术

如何在 webpack 中引入未模块化的库,如 Zepto

By go - 星期六, 四月 22, 2017

原文链接:https://sebastianblade.com/how-to-import-unmodular-library-like-zepto/最近我在研究多页面 webpack 模块打包的完整解决方案时,发现用 import 导入 Zepto 时,会报 Uncaught TypeError: Cannot read property ‘createElement’ of undefined 错误,导致无法愉快地使用 Zepto。在经过一番调试和搜索后终于找到了解决的办法,并且对于所有不支持模块化的库都可以用这种方法导入模块。 原因Zepto 的源码:/* Zepto v1.2.0 – zepto event ajax form ie – zeptojs.com/license */
(function(global, factory) {
if (typeof define === ‘function’ && define.amd)
define(function() { return factory(global) })
else
factory(global)
}(this, function(window) {
var Zepto = (function() {

// …

return $
})()

window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)

return Zepto
}))
可以看出,它只使用了 AMD 规范的模块导出方法 define,没有用 CommonJs 规范的方法 module.exports 来导出模块,不过这不是造成报错的原因。先来看一下 webpack 运行模块的方法: 再来看一下在 webpack config 中不作任何处理,直接 import $ from ‘zepto’,经过 webpack 转换的 Zepto 的模块闭包:以上代码是模块执行的闭包,化简一下其实就是 webpack 把 AMD 规范的 define 方法转换成了 module.export = factory(global),以此来获取 factory 方法返回的对象。在模块加载(import/require)时,webpack 会通过下面这种方法来执行模块闭包并导入模块:// The require function
function __webpack_require__(moduleId) {

// Check if module is in cache
if(installedModules[moduleId])
return installedModules[moduleId].exports;

// Create a new module (and put it into the cache)
var module = installedModules[moduleId] = {
exports: {},
id: moduleId,
loaded: false,
hot: hotCreateModule(moduleId),
parents: hotCurrentParents,
children: []
}

// Execute the module function
modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));

// Flag the module as loaded
module.loaded = true

// Return the exports of the module
return module.exports
}
其核心在于 modules[moduleId].call,它会传入新初始化的 module.exports 来作为模块闭包的上下文(context),并运行模块闭包来将模块暴露的对象加入到已加载的模块对象(installedModules)中。所以对于 Zepto 来说,它初始化时使用的 this(见下图)其实就是 module.exports,但这个 module.exports 没有赋值过任何变量,即 Zepto 初始化使用的 this 为空对象。所以 factory(global) 中 global 为空对象,Zepto 运行函数中的 window 也就变成了空对象,而 var document = window.document,这个 document 为 undefined,因此会造成 document.createElement 会报 TypeError。解决方法$ npm i -D script-loader exports-loader
要用到两个 loader:exports-loader 和 script-loader。script-loaderrequire(“script!./zepto.js”);
// => execute file.js once in global context
script-loader 可以在我们 import/require 模块时,在全局上下文环境中运行一遍模块 JS 文件(不管 require 几次,模块仅运行一次)。script-loader 把我们指定的模块 JS 文件转成纯字符串,并用 eval.call(null, string) 执行,这样执行的作用域就为全局作用域了。但如果只用 script-loader,我们要导入 Zepto 对象就需要这么写:// entry.js
/*
* 不能使用 `import $ from ‘zepto’`
* 因为 zepto.js 执行后返回值为 undefined
* 因为 module.exports 默认初始为空对象
* 所以 $ 也为空对象
*/

$(function () { })
这样的写法就是:当 webpack 初始化(webpackBootstrap)时,zepto.js 会在全局作用域下执行一遍,将 Zepto 对象赋值给 window.$ 并挂载到 window 上。因此后续的 $、Zepto 变量就都可用了。不过这种持续依赖全局对象的实现方法不太科学,还是将对象以 ES6 Module/CommonJs/AMD 方式暴露出来更好。Note:如果我们用的库没有把对象挂载到全局的话,就没法作为模块使用了(还是趁早提个 PR 模块化一下吧)。exports-loader为了让我们的模块导入更加地「模块化」,可以 import/require,而不是像上面那么「与众不同」,我们还需要 exports-loader 的帮助。exports-loader 可以导出我们指定的对象:require(‘exports?window.Zepto!./zepto.js’)
他的作用就是在模块闭包最后加一句 module.exports = window.Zepto 来导出我们需要的对象,这样我们就可以愉快地 import $ from ‘zepto’ 了。webpack 配置废话说了那么多,终于可以告诉大家怎么直接使用这两个 loader 来「模块化」Zepto 了:// webpack.config
{
// …
module: {
loaders: [{
test: require.resolve(‘zepto’),
loader: ‘exports-loader?window.Zepto!script-loader’
}]
}
}
这样我们在页面入口文件中就可以这么写:// entry.js
import $ from ‘zepto’

$(function () {
// …
})
Note:require.resolve() 是 nodejs 用来查找模块位置的方法,返回模块的入口文件,如 zepto 为 ./node_modules/zepto/dist/zepto.js。其他如果你不想写 import $ from ‘zepto’,并且想用其他变量来代替 Zepto。可以使用官方的一个插件:webpack.ProvidePlugin。webpack.ProvidePlugin 是一个依赖注入类型的插件,可以让你在使用指定变量时,比如直接使用 $ 时,自动加载指定的模块 zepto,并将其暴露的对象赋值给 $:// webpack.config
{
// …
plugins: [
new webpack.ProvidePlugin({
$: ‘zepto’,
// 把 Zepto 导入为 abc 变量也可以
abc: ‘zepto’
})
// …
]
}
这样就可以直接使用赋值了 Zepto 对象的 $/abc 变量了~// entry.js
$(function () {
// …
abc(document)
})
如果不想这么麻烦地用两个 loader 来解决问题,可以把不支持模块化的库模块化,比如用这个 npm 包:webpack-zepto。但这个包已经一年多没更新了,所以我更推荐上面比较麻烦的做法来确保引入的模块是最新的。总结由于我们用 npm 下载的模块没有模块化,因此我们要使用:script-loader 全局上下文环境中执行模块 JS 文件; exports-loader 添加 module.exports 来主动暴露需要的对象,使其模块化。这样的方法适用于所有的库,不过最好的解决办法是从根本上让这些让这些库支持模块化。参考 webpack.ProvidePlugin with zeptoexports-loader · webpack指南

超简洁代码 JQuery GoTop(返回顶部)

By Lee - 星期一, 四月 17, 2017

$(function() {
$(window).scroll(function() {
if($(this).scrollTop() != 0) {
$(“#toTop”).fadeIn();
} else {
$(“#toTop”).fadeOut();
}
});
$(“body”).append(“<div id=”toTop” style=”border:1px solid #444;background:#333;color:#fff;text-align:center;padding:10px 13px 7px 13px;position:fixed;bottom:10px;right:10px;cursor:pointer;display:none;font-family:verdana;font-size:22px;”>^</div>”);
$(“#toTop”).click(function() {
$(“body,html”).animate({scrollTop:0},800);
});
});

使用uncss去除无用的CSS

By Lee - 星期日, 四月 16, 2017

从代码的角度讲,你知道什么是比往网站或应用里添加功能更好的事情吗?删除那些没用的东西。也许是一些代码、图片、或相关依赖等,就像扔掉家中储存柜里没用的产生异味的存货。我经常用ImageOptim来优化我的图片的体积,这既能提供页面加载速度,又能减少带宽流量。然而,你知道有什么工具能找到页面中样式文件里无用的CSS吗?之前我介绍过一个用JavaScript找到无用CSS的方法,但事实上,我们并不想知道哪些CSS规则是无用的,我们想要的是一个没有多余CSS的干净的样式文件。所以,这个叫做uncss的NodeJS工具就是我们要找的了。下面我们来看看uncss是如何使用的!一个基本的用法是直接在命令行窗口里输入uncss命令:uncss http://www.webhek.com > styles.css执行输出的结果就是一个你想要的、剔除了所有无用的CSS规则的完整的样式表文件。那uncss究竟是如何做到这些的呢?让我来一步步告诉你:首先PhantomJS会加载整个HTML页面,然后执行JavaScript。
接着从HTML页面里提取页面中所有的CSS样式。
然后用css-parse分析并连接所有的样式规则。
用document.querySelector过滤出哪些CSS选择器是没有用到的。 最后用剩下的CSS规则生成输出文件跟其它NodeJS工具一样,它里面提供了很多JavaScriptAPI,下面是一个使用它的API的例子:var uncss = require(‘uncss’);

var files = [‘my’, ‘array’, ‘of’, ‘HTML’, ‘files’],
options = {
ignore : [‘#added_at_runtime’, /test-[0-9]+/],
media : [‘(min-width: 700px) handheld and (orientation: landscape)’],
csspath : ‘../public/css/’,
raw : ‘h1 { color: green }’,
stylesheets : [‘lib/bootstrap/dist/css/bootstrap.css’, ‘src/public/css/main.css’],
ignoreSheets : [/fonts.googleapis/],
urls : [‘http://localhost:3000/mypage’, ‘…’], // Deprecated
timeout : 1000,
htmlroot : ‘public’
};

uncss(files, options, function (error, output) {
console.log(output);
});

/* Look Ma, no options! */
uncss(files, function (error, output) {
console.log(output);
});

/* Specifying raw HTML */
var raw_html = ‘…’;
uncss(raw_html, options, function (error, output) {
console.log(output);
});一个运行维护多年的网站或Web应用必定会产生很多无用的代码,这是毫无例外的。多余的代码不仅给WEB程序员带来维护的负担,也给使用者造成负面效应。请试一下uncss,真的非常简单,完全自动的帮你清除无用的CSS代码!

jQuery scrollFix滚动定位插件

By Lee - 星期二, 四月 4, 2017

【插件功能】当用户向上或向下滚动页面到一定位置时,目标元素开始固定定位(position:fixed),当回滚到原位置时目标元素恢复到原状态,可以定制触发滚动相对屏幕位置和触发滚动方向,兼容IE6【插件参数】$(“.target_element”).scrollFix( [ “top” | “bottom” | length(可以为负,表示相对bottom), [ “top” | “bottom” ] ]);第一个参数: 可选,默认为”top”,当目标元素到了屏幕相对的位置时开始触发固定,可以填一个数值,如100,-200 ,负值表示相对于屏幕下方第一个参数: 可选,默认为”top”,表示触发固定的滚动方向,”top”表示从上向下滚动时触发,”bottom”表示从下向上滚动时触发【下载插件】下载插件(download)【代码示例】$(“#a”).scrollFix(-200); 滚动到距离下面200px时开始固定,默认从上到下触发   $(“#b”).scrollFix(200,”bottom”); 滚动到距离上面200px时开始固定,指定”bottom”从下到上触发   $(“#c”).scrollFix(“top”,”top”); 滚动到距离上面0时开始固定,指定”top”从上到下触发   $(“#d”).scrollFix(“bottom”,”top”); 滚动到距离下面0时开始固定,指定”bottom”从下到上触发    ;(function($) {
jQuery.fn.scrollFix = function(height, dir) {
height = height || 0;
height = height == “top” ? 0 : height;
return this.each(function() {
if (height == “bottom”) {
height = document.documentElement.clientHeight – this.scrollHeight;
} else if (height < 0) {
height = document.documentElement.clientHeight – this.scrollHeight + height;
}
var that = $(this),
oldHeight = false,
p, r, l = that.offset().left;
dir = dir == “bottom” ? dir : “top”; //默认滚动方向向下
if (window.XMLHttpRequest) { //非ie6用fixed

function getHeight() { //>=0表示上面的滚动高度大于等于目标高度
return (document.documentElement.scrollTop || document.body.scrollTop) + height – that.offset().top;
}
$(window).scroll(function() {
if (oldHeight === false) {
if ((getHeight() >= 0 && dir == “top”) || (getHeight() <= 0 && dir == “bottom”)) {
oldHeight = that.offset().top – height;
that.css({
position: “fixed”,
top: height,
left: l
});
}
} else {
if (dir == “top” && (document.documentElement.scrollTop || document.body.scrollTop) < oldHeight) {
that.css({
position: “static”
});
oldHeight = false;
} else if (dir == “bottom” && (document.documentElement.scrollTop || document.body.scrollTop) > oldHeight) {
that.css({
position: “static”
});
oldHeight = false;
}
}
});
} else { //for ie6
$(window).scroll(function() {
if (oldHeight === false) { //恢复前只执行一次,减少reflow
if ((getHeight() >= 0 && dir == “top”) || (getHeight() <= 0 && dir == “bottom”)) {
oldHeight = that.offset().top – height;
r = document.createElement(“span”);
p = that[0].parentNode;
p.replaceChild(r, that[0]);
document.body.appendChild(that[0]);
that[0].style.position = “absolute”;
}
} else if ((dir == “top” && (document.documentElement.scrollTop || document.body.scrollTop) < oldHeight) || (dir == “bottom” && (document.documentElement.scrollTop || document.body.scrollTop) > oldHeight)) { //结束
that[0].style.position = “static”;
p.replaceChild(that[0], r);
r = null;
oldHeight = false;
} else { //滚动
that.css({
left: l,
top: height + document.documentElement.scrollTop
})
}
});
}
});
};
})(jQuery);
  

Webpack 常见静态资源处理 – 模块加载器(Loaders)+ExtractTextPlugin插件

By Lee - 星期二, 四月 4, 2017

Webpack 常见静态资源处理 – 模块加载器(Loaders)+ExtractTextPlugin插件webpack系列目录webpack 系列 一:模块系统的演进webpack 系列 二:webpack 介绍&安装webpack 系列 三:webpack 如何集成第三方js库webpack 系列 四:webpack 多页面支持 & 公共组件单独打包webpack 系列 五:webpack Loaders 模块加载器webpack 系列 六:前端项目模板-webpack+gulp实现自动构建部署基于webpack搭建纯静态页面型前端工程解决方案模板, 最终形态源码见github: https://github.com/ifengkou/webpack-template正文Webpack将所有静态资源都认为是模块,比如JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,图片等等,从而可以对其进行统一管理。为此Webpack引入了加载器的概念,除了纯JavaScript之外,每一种资源都可以通过对应的加载器处理成模块。和大多数包管理器不一样的是,Webpack的加载器之间可以进行串联,一个加载器的输出可以成为另一个加载器的输入。比如LESS文件先通过less-load处理成css,然后再通过css-loader加载成css模块,最后由style-loader加载器对其做最后的处理,从而运行时可以通过style标签将其应用到最终的浏览器环境。一 常用loader安装css/sass/less loader加载器cnpm install file-loader css-loader style-loader sass-loader ejs-loader html-loader jsx-loader image-webpack-loader –save-devwebpack.config.js配置:module: {
loaders: [
{
test: /.((woff2?|svg)(?v=[0-9].[0-9].[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
loaders: [
// 小于10KB的图片会自动转成dataUrl
‘url?limit=10240&name=img/[hash:8].[name].[ext]’,
‘image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:”65-80″,speed:4}}’
]
},
{
test: /.((ttf|eot)(?v=[0-9].[0-9].[0-9]))|(ttf|eot)$/,
loader: ‘url?limit=10000&name=fonts/[hash:8].[name].[ext]’
},
{test: /.(tpl|ejs)$/, loader: ‘ejs’},
{test: /.css$/, loader: ‘style-loader!css-loader’},
{ test: /.scss$/, loader: ‘style!css!sass’}
]
},index.html 新增两个div<div class=”small-webpack”></div>
<div class=”webpack”></div>index.css 增加两个图片,同时将webpack.png(53kb) 和 small-webpack.png(9.8k).webpack {
background: url(../img/webpack.png) no-repeat center;
height:500px;
}
.small-webpack {
background: url(../img/small-webpack.png) no-repeat center;
height:250px;
}index.js 引入cssrequire(‘../css/index.css’);执行webpack指令$ webpack查看生成的目录结构其中并没有css文件,css被写入到了index.js中,index.js 部分截图总结:图片采用了url-loader加载,如果小于10kb,图片则被转化成 base64 格式的 dataUrl css文件被打包进了js文件中css被打包进了js文件,如果接受不了,可以强制把css从js文件中独立出来。官方文档是以插件形式实现:文档docs点这,插件的github点这二:extract-text-webpack-plugin 插件介绍Extract text from bundle into a file.从bundle中提取出特定的text到一个文件中。使用 extract-text-webpack-plugin就可以把css从js中独立抽离出来安装$ npm install extract-text-webpack-plugin –save-dev使用(css为例)var ExtractTextPlugin = require(“extract-text-webpack-plugin”);
module.exports = {
module: {
loaders: [
{ test: /.css$/, loader: ExtractTextPlugin.extract(“style-loader”, “css-loader”) }
]
},
plugins: [
new ExtractTextPlugin(“styles.css”)
]
}它将从每一个用到了require(“style.css”)的entry chunks文件中抽离出css到单独的output文件APInew ExtractTextPlugin([id: string], filename: string, [options])id Unique ident for this plugin instance. (For advanded usage only, by default automatic generated) filename the filename of the result file. May contain [name], [id] and [contenthash]. [name] the name of the chunk [id] the number of the chunk [contenthash] a hash of the content of the extracted file optionsallChunks extract from all additional chunks too (by default it extracts only from the initial chunk(s)) disable disables the plugin ExtractTextPlugin.extract([notExtractLoader], loader, [options])根据已有的loader,创建一个提取器(loader的再封装)notExtractLoader (可选)当css没有被抽离时,加载器不应该使用(例如:当allChunks:false时,在一个additional 的chunk中) loader 数组,用来转换css资源的加载器s optionspublicPath 重写该加载器(loader)的 publicPath 的设置多入口文件的extract的使用示例:let ExtractTextPlugin = require(‘extract-text-webpack-plugin’);

// multiple extract instances
let extractCSS = new ExtractTextPlugin(‘stylesheets/[name].css’);
let extractLESS = new ExtractTextPlugin(‘stylesheets/[name].less’);

module.exports = {

module: {
loaders: [
{test: /.scss$/i, loader: extractCSS.extract([‘css’,’sass’])},
{test: /.less$/i, loader: extractLESS.extract([‘css’,’less’])},

]
},
plugins: [
extractCSS,
extractLESS
]
};三:改造项目-抽离css安装插件到项目npm install extract-text-webpack-plugin –save-dev配置webpack.config.js,加入ExtractTextPlugin和相关处理:var webpack = require(“webpack”);
var path = require(“path”);
var srcDir = path.resolve(process.cwd(), ‘src’);
var nodeModPath = path.resolve(__dirname, ‘./node_modules’);
var pathMap = require(‘./src/pathmap.json’);
var glob = require(‘glob’)
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
var HtmlWebpackPlugin = require(‘html-webpack-plugin’);
var ExtractTextPlugin = require(‘extract-text-webpack-plugin’);
var entries = function () {
var jsDir = path.resolve(srcDir, ‘js’)
var entryFiles = glob.sync(jsDir + ‘/*.{js,jsx}’)
var map = {};

for (var i = 0; i < entryFiles.length; i++) {
var filePath = entryFiles[i];
var filename = filePath.substring(filePath.lastIndexOf(‘/’) + 1, filePath.lastIndexOf(‘.’));
map[filename] = filePath;
}
return map;
}

var html_plugins = function () {
var entryHtml = glob.sync(srcDir + ‘/*.html’)
var r = []
var entriesFiles = entries()
for (var i = 0; i < entryHtml.length; i++) {
var filePath = entryHtml[i];
var filename = filePath.substring(filePath.lastIndexOf(‘/’) + 1, filePath.lastIndexOf(‘.’));
var conf = {
template: ‘html!’ + filePath,
filename: filename + ‘.html’
}
//如果和入口js文件同名
if (filename in entriesFiles) {
conf.inject = ‘body’
conf.chunks = [‘vendor’, filename]
}
//跨页面引用,如pageA,pageB 共同引用了common-a-b.js,那么可以在这单独处理
//if(pageA|pageB.test(filename)) conf.chunks.splice(1,0,’common-a-b’)
r.push(new HtmlWebpackPlugin(conf))
}
return r
}
var plugins = [];
var extractCSS = new ExtractTextPlugin(‘css/[name].css?[contenthash]’)
var cssLoader = extractCSS.extract([‘css’])
var sassLoader = extractCSS.extract([‘css’, ‘sass’])

plugins.push(extractCSS);

plugins.push(new CommonsChunkPlugin({
name: ‘vendor’,
minChunks: Infinity
}));

module.exports = {
entry: Object.assign(entries(), {
// 用到什么公共lib(例如jquery.js),就把它加进vendor去,目的是将公用库单独提取打包
‘vendor’: [‘jquery’, ‘avalon’]
}),
output: {
path: path.join(__dirname, “dist”),
filename: “[name].js”,
chunkFilename: ‘[chunkhash:8].chunk.js’,
publicPath: “/”
},
module: {
loaders: [
{
test: /.((woff2?|svg)(?v=[0-9].[0-9].[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
loaders: [
//小于10KB的图片会自动转成dataUrl,
‘url?limit=10000&name=img/[hash:8].[name].[ext]’,
‘image?{bypassOnDebug:true, progressive:true,optimizationLevel:3,pngquant:{quality:”65-80″,speed:4}}’
]
},
{
test: /.((ttf|eot)(?v=[0-9].[0-9].[0-9]))|(ttf|eot)$/,
loader: ‘url?limit=10000&name=fonts/[hash:8].[name].[ext]’
},
{test: /.(tpl|ejs)$/, loader: ‘ejs’},
{test: /.css$/, loader: cssLoader},
{test: /.scss$/, loader: sassLoader}
]
},
resolve: {
extensions: [”, ‘.js’, ‘.css’, ‘.scss’, ‘.tpl’, ‘.png’, ‘.jpg’],
root: [srcDir, nodeModPath],
alias: pathMap,
publicPath: ‘/’
},
plugins: plugins.concat(html_plugins())
}其中,用ExtractTextPlugin 来抽离cssvar ExtractTextPlugin = require(‘extract-text-webpack-plugin’);
var extractCSS = new ExtractTextPlugin(‘css/[name].css?[contenthash]’)
var cssLoader = extractCSS.extract([‘css’])
var sassLoader = extractCSS.extract([‘css’, ‘sass’])

plugins.push(extractCSS);
……
//conf – module – loaders
{test: /.css$/, loader: cssLoader},
{test: /.scss$/, loader: sassLoader}注意事项:css中img的路径会出现问题,通过设置publicPath 解决,采用绝对路径output: {
……
publicPath: “/”
},运行:$ webpack期望css单独抽离,打包成单独的css文件 html自动引用css文件 小于10k的图片,转成base64 格式的 dataUrl webpack.png 会被压缩,减少文件大小运行webpack后的项目的目录结构:生成的 dist/index.html 自动引用了 index.css 和相关的js,由于设置了publicPath 所以相应的链接都采用了绝对路径生成的 dist/index.css 小图片被转成了data:image形式:结果:css单独打包到css目录 html自动注入了link 标签 small-webpack.png 小于10k,被打包进了index.css webpack.png 由原来的50+k 被压缩成 10- k最后,运行 webpack-dev-server 看一下运行结果:总结Webpack将所有静态资源都认为是模块,而通过loader,几乎可以处理所有的静态资源,图片、css、sass之类的。并且通过一些插件如extract-text-webpack-plugin,可以将共用的css抽离出来下篇介绍改进webpack.config.js:区分开发环境和生产环境 集成 gulp 实现自动构建打包部署 github 发布 前端自动化构建的项目模板

webpack打包后使用jQuery的问题

By Lee - 星期二, 四月 4, 2017

使用webpack打包了页面上使用的一些js文件
配置文件:var webpack = require(“webpack”);
var path= require(“path”);
module.exports = {
entry: [
“./admin/public/entry/entry.js”
],
output: {
path: path.join(__dirname,”/admin/public/js/out”),
filename:”bundle.js”
},
module: {
loaders: [{
test: /.css$/,
loader:”style!css”
}]
},
plugins: [
new webpack.ProvidePlugin({
$:”jquery”,
jQuery:”jquery”,
“window.jQuery”:”jquery”
})
],
}入口文件:require(‘bootstrap’);
require(‘bootstrap-switch’);
require(‘bootstrap-timepicker’);
require(‘../js/jquery.cookies.js’);
require(‘gritter’);
require(‘../js/datatable.js’);
require(‘../js/custom.js’);
require(‘../js/common.js’);
require(‘../js/tag.js’);
require(‘jquery-ui’);
require(‘cropper’);
require(‘ztree’);打包完之后再网页上使用jQuery会报 Uncaught ReferenceError: $ is not defined 表示理解不能,为何在打包的js插件中使用jq没问题,在网页中却要报错

JavaScript 箭头函数(Lambda表达式)

By Lee - 星期日, 四月 2, 2017

简介

JavaScript 中,函数可以用箭头语法(”=>”)定义,有时候也叫“lambda表达式”。这种语法主要意图是定义轻量级的内联回调函数。例如:

// Arrow function:
[5, 8, 9].map(item => item + 1); // -> [6, 9, 10]

// Classic function equivalent:
[5, 8, 9].map(function(item) {
return item + 1;
}); // -> [6, 9, 10]

当箭头函数有一个参数时,参数两边的括号是可有可无的,但是还是有括号看起来看清楚。

const foo = bar => bar + 1;
const bar = (baz) => baz + 1;

箭头函数不带参数时,必须要用括号,比如:

const foo = () => “foo”;

如果函数体不是只一行,应该用花括号,并显式地返回(如果需要返回值)。

const foo = bar => {
const baz = 5;
return bar + baz;
};
foo(1); // -> 6

arguments object

箭头函数不会暴露 argument 对象,所以,argument 将简单地指向当前scope内的一个变量。

arguments object 是所有函数中的一个本地变量。你可以通过 arguments 对象引用函数的入参。这个对象包含传给这个函数的每个入参的入口,索引从0开始,例如:
arguments[0]
arguments[1]
arguments[2]

const arguments = [true];
const foo = x => console.log(arguments[0]);

foo(false); // -> true

基于此,箭头函数也不知道它的调用者。
当缺少arguments object时,可能会有所限制(极少数情况),其余的参数一般可以做为替代。

const arguments = [true];
const foo = (…arguments) => console.log(arguments[0]);

foo(false); // -> false

绑定this的值

箭头函数是 lexically scoped,这意味着其 this 绑定到了附近scope的上下文。也就是说,不管this指向什么,都可以用一个箭头函数保存。

看下面的例子, Cow 类有一个方法在1秒后输出sound。

class Cow {
constructor() {
this.sound = “moo”;
}
makeSoundLater() {
setTimeout(() => {
console.log(this.sound);
}, 1000);
}
}

var myCow = new Cow();
var yourCow = new Cow();

yourCow.sound = “moooooo”;

myCow.makeSoundLater();
yourCow.makeSoundLater();

在 makeSoundLater() 方法中,this 指向当前 Cow 对象的实例。所以在这个例子中当我们调用 myCow.makeSoundLater(), this 指向 myCow。然后,通过使用箭头函数,我们保存了 this,这样我们就可以在需要时引用 this.sound 了。将会输出 “moo”,而不是yourCow.makeSoundLater()输出的“moooooo”。

隐式返回值

箭头函数可以通过省略掉小括号做到隐式返回值。

const foo = x => x + 1;
foo(1); // -> 2

当使用隐式返回时,Object Literal 必须用花括号括起来。

Object Literal 是用花括号括起来的,分号隔开的 k-v 对象列表。

const foo = () => { bar: 1 } // foo() returns undefined
const foo = () => ({ bar: 1 }) // foo() returns {bar: 1}

显示返回值

const foo = x => {
return x + 1;
}

foo(1); // -> 2

语法

x => y // Implicit return

x => { return y } // Explicit return

(x, y, z) => { … } // Multiple arguments

(() => { … })() // Immediately-invoked function expression

2015 年最棒的 5 个 HTML5 框架

By - 星期五, 八月 7, 2015

摘要: 最近,大量的 HTML5 框架在行业内可免费获得,这使得 HTML5 开发者们不知道哪一个框架才是最好的。本文在下面会列出 2015 年最流行的 5 个框架,让我们一起以一个简单的方式来开始讨论吧。 … 大多数的 web 开发者

JavaScript面试问题:事件委托和this

By - 星期一, 六月 29, 2015

JavaScript不仅门槛低,而且是一门有趣、功能强大和非常重要的语言。各行各业的人发现自己最混乱的选择是JavaSscript编程语言。由于有着各种各样的背景,所以不是每个人都对JavaScript及其基本原理有广泛的认识。通常来书,

HTML5标签使用的常见误区

By Lee - 星期二, 二月 25, 2014

在这篇文章中,我将给大家分享html5构建页面的小错误和不好的实践方法,让我们在以后的工作中避免这些错误。 不 […]

HTML5