前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >listview优化(中)

listview优化(中)

作者头像
xiangzhihong
发布于 2018-01-30 09:09:28
发布于 2018-01-30 09:09:28
1.2K0
举报
文章被收录于专栏:向治洪向治洪

1,对Imageview使用setTag()方法来解决图片错位问题,这个Tag中设置的是图片的url,然后在加载的时候取得这个url和要加载那position中的url对比,如果不相同就加载,相同就是复用以前的就不加载了

2,对于要加载的图片资源,先在内存缓存中找(原始的方法是使用SoftRefrence,最新的方法是使用android提供的Lrucache),如果找不到,则在本地缓存(可以使用DiskLrucache类)中找(也就是读取原先下载过的本地图片),还找不到,就开启异步线程去下载图片,下载以后,保存在本地,内存缓存也保留一份引用

3,在为imagview装载图片时,先测量需要的图片大小,按比例缩放

4,使用一个Map保存异步线程的引用,key->value为url->AsyncTask,这样可以避免已经开启了线程去加载图片,但是还没有加载完时,又重复开启线程去加载图片的情况

5,在快速滑动的时候不加载图片,取消所有图片加载线程,一旦停下来,继续可见图片的加载线程

下面都是我摘取的网上的一些例子,我分别介绍它们来说明上述的优化思路

第一个例子:

代码语言:js
AI代码解释
复制
 public class MemoryCache {  
  
  private static final String TAG = "MemoryCache";  
  // 放入缓存时是个同步操作 
  // LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列,即LRU 
  // 这样的好处是如果要将缓存中的元素替换,则先遍历出最近最少使用的元素来替换以提高效率 
  private Map<String, Bitmap> cache = Collections  
             .synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true));  
  // 缓存中图片所占用的字节,初始0,将通过此变量严格控制缓存所占用的堆内存 
  private long size = 0;// current allocated size 
  // 缓存只能占用的最大堆内存 
  private long limit = 1000000;// max memory in bytes 
  
  public MemoryCache() {  
  // use 25% of available heap size 
         setLimit(Runtime.getRuntime().maxMemory() / 4);  
     }  
  
  public void setLimit(long new_limit) {   
         limit = new_limit;  
         Log.i(TAG, "MemoryCache will use up to " + limit / 1024. / 1024. + "MB");  
     }  
  
  public Bitmap get(String id) {  
  try {  
  if (!cache.containsKey(id))  
  return null;  
  return cache.get(id);  
         } catch (NullPointerException ex) {  
  return null;  
         }  
     }  
  
  public void put(String id, Bitmap bitmap) {  
  try {  
  if (cache.containsKey(id))  
                 size -= getSizeInBytes(cache.get(id));  
             cache.put(id, bitmap);  
             size += getSizeInBytes(bitmap);  
             checkSize();  
         } catch (Throwable th) {  
             th.printStackTrace();  
         }  
     }  
  
  /** 
      * 严格控制堆内存,如果超过将首先替换最近最少使用的那个图片缓存 
      *  
      */ 
  private void checkSize() {  
         Log.i(TAG, "cache size=" + size + " length=" + cache.size());  
  if (size > limit) {  
  // 先遍历最近最少使用的元素 
             Iterator<Entry<String, Bitmap>> iter = cache.entrySet().iterator();  
  while (iter.hasNext()) {  
                 Entry<String, Bitmap> entry = iter.next();  
                 size -= getSizeInBytes(entry.getValue());  
                 iter.remove();  
  if (size <= limit)  
  break;  
             }  
             Log.i(TAG, "Clean cache. New size " + cache.size());  
         }  
     }  
  
  public void clear() {  
         cache.clear();  
     }  
  
  /** 
      * 图片占用的内存 
      *  
      * @param bitmap 
      * @return 
      */ 
  long getSizeInBytes(Bitmap bitmap) {  
  if (bitmap == null)  
  return 0;  
  return bitmap.getRowBytes() * bitmap.getHeight();  
     }  
 }  

也可以使用SoftReference,代码会简单很多,但是我推荐上面的方法。

代码语言:js
AI代码解释
复制
 public class MemoryCache {  
  
  private Map<String, SoftReference<Bitmap>> cache = Collections  
             .synchronizedMap(new HashMap<String, SoftReference<Bitmap>>());  
  
  public Bitmap get(String id) {  
  if (!cache.containsKey(id))  
  return null;  
         SoftReference<Bitmap> ref = cache.get(id);  
  return ref.get();  
     }  
  
  public void put(String id, Bitmap bitmap) {  
         cache.put(id, new SoftReference<Bitmap>(bitmap));  
     }  
  
  public void clear() {  
         cache.clear();  
     }  
  
 }  

下面是文件缓存类的代码FileCache.java:

代码语言:java
AI代码解释
复制
 public class FileCache {  
  
  private File cacheDir;  
  
  public FileCache(Context context) {  
  // 如果有SD卡则在SD卡中建一个LazyList的目录存放缓存的图片 
  // 没有SD卡就放在系统的缓存目录中 
  if (android.os.Environment.getExternalStorageState().equals(  
                 android.os.Environment.MEDIA_MOUNTED))  
             cacheDir = new File(  
                     android.os.Environment.getExternalStorageDirectory(),  
  "LazyList");  
  else 
             cacheDir = context.getCacheDir();  
  if (!cacheDir.exists())  
             cacheDir.mkdirs();  
     }  
  
  public File getFile(String url) {  
  // 将url的hashCode作为缓存的文件名 
         String filename = String.valueOf(url.hashCode());  
  // Another possible solution 
  // String filename = URLEncoder.encode(url); 
         File f = new File(cacheDir, filename);  
  return f;  
  
     }  
  
  public void clear() {  
         File[] files = cacheDir.listFiles();  
  if (files == null)  
  return;  
  for (File f : files)  
             f.delete();  
     }  
  
 }  

最后最重要的加载图片的类,ImageLoader.java:

代码语言:java
AI代码解释
复制
 public class ImageLoader {  
  
     MemoryCache memoryCache = new MemoryCache();  
     FileCache fileCache;  
  private Map<ImageView, String> imageViews = Collections  
             .synchronizedMap(new WeakHashMap<ImageView, String>());  
  // 线程池 
     ExecutorService executorService;  
  
  public ImageLoader(Context context) {  
         fileCache = new FileCache(context);  
         executorService = Executors.newFixedThreadPool(5);  
     }  
  
  // 当进入listview时默认的图片,可换成你自己的默认图片 
  final int stub_id = R.drawable.stub;  
  
  // 最主要的方法 
  public void DisplayImage(String url, ImageView imageView) {  
         imageViews.put(imageView, url);  
  // 先从内存缓存中查找 
  
         Bitmap bitmap = memoryCache.get(url);  
  if (bitmap != null)  
             imageView.setImageBitmap(bitmap);  
  else {  
  // 若没有的话则开启新线程加载图片 
             queuePhoto(url, imageView);  
             imageView.setImageResource(stub_id);  
         }  
     }  
  
  private void queuePhoto(String url, ImageView imageView) {  
         PhotoToLoad p = new PhotoToLoad(url, imageView);  
         executorService.submit(new PhotosLoader(p));  
     }  
  
  private Bitmap getBitmap(String url) {  
         File f = fileCache.getFile(url);  
  
  // 先从文件缓存中查找是否有 
         Bitmap b = decodeFile(f);  
  if (b != null)  
  return b;  
  
  // 最后从指定的url中下载图片 
  try {  
             Bitmap bitmap = null;  
             URL imageUrl = new URL(url);  
             HttpURLConnection conn = (HttpURLConnection) imageUrl  
                     .openConnection();  
             conn.setConnectTimeout(30000);  
             conn.setReadTimeout(30000);  
             conn.setInstanceFollowRedirects(true);  
             InputStream is = conn.getInputStream();  
             OutputStream os = new FileOutputStream(f);  
             CopyStream(is, os);  
             os.close();  
             bitmap = decodeFile(f);  
  return bitmap;  
         } catch (Exception ex) {  
             ex.printStackTrace();  
  return null;  
         }  
     }  
  
  // decode这个图片并且按比例缩放以减少内存消耗,虚拟机对每张图片的缓存大小也是有限制的 
  private Bitmap decodeFile(File f) {  
  try {  
  // decode image size 
             BitmapFactory.Options o = new BitmapFactory.Options();  
             o.inJustDecodeBounds = true;  
             BitmapFactory.decodeStream(new FileInputStream(f), null, o);  
  
  // Find the correct scale value. It should be the power of 2. 
  final int REQUIRED_SIZE = 70;  
  int width_tmp = o.outWidth, height_tmp = o.outHeight;  
  int scale = 1;  
  while (true) {  
  if (width_tmp / 2 < REQUIRED_SIZE  
                         || height_tmp / 2 < REQUIRED_SIZE)  
  break;  
                 width_tmp /= 2;  
                 height_tmp /= 2;  
                 scale *= 2;  
             }  
  
  // decode with inSampleSize 
             BitmapFactory.Options o2 = new BitmapFactory.Options();  
             o2.inSampleSize = scale;  
  return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);  
         } catch (FileNotFoundException e) {  
         }  
  return null;  
     }  
  
  // Task for the queue 
  private class PhotoToLoad {  
  public String url;  
  public ImageView imageView;  
  
  public PhotoToLoad(String u, ImageView i) {  
             url = u;  
             imageView = i;  
         }  
     }  
  
  class PhotosLoader implements Runnable {  
         PhotoToLoad photoToLoad;  
  
         PhotosLoader(PhotoToLoad photoToLoad) {  
  this.photoToLoad = photoToLoad;  
         }  
  
  @Override 
  public void run() {  
  if (imageViewReused(photoToLoad))  
  return;  
             Bitmap bmp = getBitmap(photoToLoad.url);  
             memoryCache.put(photoToLoad.url, bmp);  
  if (imageViewReused(photoToLoad))  
  return;  
             BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);  
  // 更新的操作放在UI线程中 
             Activity a = (Activity) photoToLoad.imageView.getContext();  
             a.runOnUiThread(bd);  
         }  
     }  
  
  /** 
      * 防止图片错位 
      *  
      * @param photoToLoad 
      * @return 
      */ 
  boolean imageViewReused(PhotoToLoad photoToLoad) {  
         String tag = imageViews.get(photoToLoad.imageView);  
  if (tag == null || !tag.equals(photoToLoad.url))  
  return true;  
  return false;  
     }  
  
  // 用于在UI线程中更新界面 
  class BitmapDisplayer implements Runnable {  
         Bitmap bitmap;  
         PhotoToLoad photoToLoad;  
  
  public BitmapDisplayer(Bitmap b, PhotoToLoad p) {  
             bitmap = b;  
             photoToLoad = p;  
         }  
  
  public void run() {  
  if (imageViewReused(photoToLoad))  
  return;  
  if (bitmap != null)  
                 photoToLoad.imageView.setImageBitmap(bitmap);  
  else 
                 photoToLoad.imageView.setImageResource(stub_id);  
         }  
     }  
  
  public void clearCache() {  
         memoryCache.clear();  
         fileCache.clear();  
     }  
  
  public static void CopyStream(InputStream is, OutputStream os) {  
  final int buffer_size = 1024;  
  try {  
  byte[] bytes = new byte[buffer_size];  
  for (;;) {  
  int count = is.read(bytes, 0, buffer_size);  
  if (count == -1)  
  break;  
                 os.write(bytes, 0, count);  
             }  
         } catch (Exception ex) {  
         }  
     }  
 }  

上面代码的思路是这样的,首先是一个MemoryCache类,用来缓存图片应用到内存。这个类包含一个Collectiosn.synchronizedMap(new LinkedHashMap<String,Bitmap>(10,1.5f,true))对象,这个对象就是用来保存url和对应的bitmap的,也就是缓存,最后一个参数设置为true的原因,是代表这个map里的元素将按照最近使用次数由少到多排列,即LRU。这样的好处是如果要将缓存中的元素替换,则先遍历出最近最少使用的元素来替换以提高效率 。

另外设置一个缓存的最大值limit,和一个初始值size=0。每次添加图片缓存,Size就增加相应大小,如果增加以后大小超过limit,就遍历LinkedHashMap清楚使用次数最少的缓存,同时减小size值,直到size<limit。

作者还举了一个使用SoftReference的例子,这样做的好处是android会自动替我们回收适当的bitmap缓存。

接下来是文件缓存,如果有SD卡则在SD卡中建一个LazyList的目录存放缓存的图片,没有SD卡就放在系统的缓存目录中,将url的hashCode作为缓存的文件名。这个类只是根据url名创建并返回了一个File类,没有真正的缓存图片,图片缓存在ImageLoader类中,不过这个类要获取FileCache返回的File来做FileOutputStream的目的地.

最后是负责的ImageLoader,这个类有一个线程池,用于管理下载线程。另外有一个WeakHashMap<ImageView, String>用于保存imageview引用和记录Tag,用于图片更新。它先检查缓存,没有则开启一个线程去下载,下载以后图片保存到缓存(内存,文件),然后缩放图像比例,返回一个合适大小的bitmap,最后开启一个线程去跟新UI(方式是imagview.getContext()获取对应的context,然后context调用runOnUIThread()方法)。

另外,在下载线程开启前,图片下载完成后,跟新UI前,都通过WeakHashMap<ImageView, String>获取下载图片的Tag与对应要设置图片imageview的tag比较,防止图片错位。

上述代码完成了基本的优化思路,甚至使用了一个自己定义的缓存类MemoryCache,使管理变得更加清晰,同时有文件缓存,也通过imagview->url的方式避免了图片错位,还开启了异步线程下载图片,但是又开启了一个UI线程去跟新UI。

缺点是开启了UI线程去更新UI,浪费了资源,其实这个可以使用定义一个回调接口实现。另外也没有考虑到重复开启下载线程的问题。

第二个例子:

先贴上主方法的代码:

代码语言:java
AI代码解释
复制
 package cn.wangmeng.test;  
  
 import java.io.IOException;  
 import java.io.InputStream;  
 import java.lang.ref.SoftReference;  
 import java.net.MalformedURLException;  
 import java.net.URL;  
 import java.util.HashMap;  
  
 import android.graphics.drawable.Drawable;  
 import android.os.Handler;  
 import android.os.Message;  
  
 public class AsyncImageLoader {  
  
  private HashMap<String, SoftReference<Drawable>> imageCache;  
  
  public AsyncImageLoader() {  
              imageCache = new HashMap<String, SoftReference<Drawable>>();  
          }  
  
  public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {  
  if (imageCache.containsKey(imageUrl)) {  
                  SoftReference<Drawable> softReference = imageCache.get(imageUrl);  
                  Drawable drawable = softReference.get();  
  if (drawable != null) {  
  return drawable;  
                  }  
              }  
  final Handler handler = new Handler() {  
  public void handleMessage(Message message) {  
                      imageCallback.imageLoaded((Drawable) message.obj, imageUrl);  
                  }  
              };  
  new Thread() {  
  @Override 
  public void run() {  
                      Drawable drawable = loadImageFromUrl(imageUrl);  
                      imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));  
                      Message message = handler.obtainMessage(0, drawable);  
                      handler.sendMessage(message);  
                  }  
              }.start();  
  return null;  
          }  
  
  public static Drawable loadImageFromUrl(String url) {  
             URL m;  
             InputStream i = null;  
  try {  
                 m = new URL(url);  
                 i = (InputStream) m.getContent();  
             } catch (MalformedURLException e1) {  
                 e1.printStackTrace();  
             } catch (IOException e) {  
                 e.printStackTrace();  
             }  
             Drawable d = Drawable.createFromStream(i, "src");  
  return d;  
         }  
  
  public interface ImageCallback {  
  public void imageLoaded(Drawable imageDrawable, String imageUrl);  
          }  
  
 }  

以上代码是实现异步获取图片的主方法,SoftReference是软引用,是为了更好的为了系统回收变量,重复的URL直接返回已有的资源,实现回调函数,让数据成功后,更新到UI线程。

几个辅助类文件:

代码语言:java
AI代码解释
复制
 package cn.wangmeng.test;  
  
 public class ImageAndText {  
  private String imageUrl;  
  private String text;  
  
  public ImageAndText(String imageUrl, String text) {  
  this.imageUrl = imageUrl;  
  this.text = text;  
         }  
  public String getImageUrl() {  
  return imageUrl;  
         }  
  public String getText() {  
  return text;  
         }  
 }  
代码语言:java
AI代码解释
复制
 package cn.wangmeng.test;  
  
 import android.view.View;  
 import android.widget.ImageView;  
 import android.widget.TextView;  
  
 public class ViewCache {  
  
  private View baseView;  
  private TextView textView;  
  private ImageView imageView;  
  
  public ViewCache(View baseView) {  
  this.baseView = baseView;  
         }  
  
  public TextView getTextView() {  
  if (textView == null) {  
                 textView = (TextView) baseView.findViewById(R.id.text);  
             }  
  return textView;  
         }  
  
  public ImageView getImageView() {  
  if (imageView == null) {  
                 imageView = (ImageView) baseView.findViewById(R.id.image);  
             }  
  return imageView;  
         }  
  
 }  

ViewCache是辅助获取adapter的子元素布局

代码语言:java
AI代码解释
复制
 package cn.wangmeng.test;  
  
 import java.util.List;  
  
 import cn.wangmeng.test.AsyncImageLoader.ImageCallback;  
  
 import android.app.Activity;  
 import android.graphics.drawable.Drawable;  
 import android.view.LayoutInflater;  
 import android.view.View;  
 import android.view.ViewGroup;  
 import android.widget.ArrayAdapter;  
 import android.widget.ImageView;  
 import android.widget.ListView;  
 import android.widget.TextView;  
  
 public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {  
  
  private ListView listView;  
  private AsyncImageLoader asyncImageLoader;  
  
  public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {  
  super(activity, 0, imageAndTexts);  
  this.listView = listView;  
             asyncImageLoader = new AsyncImageLoader();  
         }  
  
  public View getView(int position, View convertView, ViewGroup parent) {  
             Activity activity = (Activity) getContext();  
  
  // Inflate the views from XML 
             View rowView = convertView;  
             ViewCache viewCache;  
  if (rowView == null) {  
                 LayoutInflater inflater = activity.getLayoutInflater();  
                 rowView = inflater.inflate(R.layout.image_and_text_row, null);  
                 viewCache = new ViewCache(rowView);  
                 rowView.setTag(viewCache);  
             } else {  
                 viewCache = (ViewCache) rowView.getTag();  
             }  
             ImageAndText imageAndText = getItem(position);  
  
  // Load the image and set it on the ImageView 
             String imageUrl = imageAndText.getImageUrl();  
             ImageView imageView = viewCache.getImageView();  
             imageView.setTag(imageUrl);  
             Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() {  
  public void imageLoaded(Drawable imageDrawable, String imageUrl) {  
                     ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);  
  if (imageViewByTag != null) {  
                         imageViewByTag.setImageDrawable(imageDrawable);  
                     }  
                 }  
             });  
  if (cachedImage == null) {  
                 imageView.setImageResource(R.drawable.default_image);  
             }else{  
                 imageView.setImageDrawable(cachedImage);  
             }  
  // Set the text on the TextView 
             TextView textView = viewCache.getTextView();  
             textView.setText(imageAndText.getText());  
  
  return rowView;  
         }  
  
 }  

上述代码的思路是这样的:AsyncImageLoader类里面,使用了一个HashMap<String, SoftReference<Drawable>>用来缓存,然后有一个异步下载线程,还有一个方法内部的handler,线程下载完成后,会发消息给handler,然后handler调用回调接口imageCallback的imageLoaded()方法,这个方法是在adapter里面实现的,所以也就是在主线程跟新UI了。

而ViewCache类的作用其实就是ViewHolder,ImageAndText是一个bean类。

在adapter中,使用mageView.setTag(imageUrl)为imageview提供一个唯一标识Url,所以先图片下载完成以后,imageCallback的imageLoaded()方法中,就可以调用listview的findViewWithTag(imageUrl)来找到对应的imageview,从而不用担心错误的问题,这个方法比较巧妙。

缺点是没有实现文件缓存,另外也没有解决出现多个线程下载同一张图片的问题。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-06-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
前端同学经常忽视的一个 JavaScript 面试题
这几天面试上几次碰上这道经典的题目,特地从头到尾来分析一次答案,这道题的经典之处在于它综合考察了面试者的JavaScript的综合能力,包含了变量定义提升、this指针指向、运算符优先级、原型、继承、全局变量污染、对象属性及原型属性优先级等知识,此题在网上也有部分相关的解释,当然我觉得有部分解释还欠妥,不够清晰,特地重头到尾来分析一次,当然我们会把最终答案放在后面,并把此题再改高一点点难度,改进版也放在最后,方便面试官在出题的时候有个参考,更多详情可关注本文作者@Wscats
前端达人
2020/04/10
4900
前端同学经常忽视的一个 JavaScript 面试题
函数声明与函数表达式
定义一个函数的方法主要有三种 函数声明、函数表达式、new Function构造函数,函数声明与函数表达式定义的函数较为常用,构造函数的方式可以将字符串定义为函数。
WindRunnerMax
2020/08/27
5730
函数表达式在JavaScript中是如何工作的?
在JavaScript中,函数表达式是一种将函数赋值给变量的方法。函数表达式可以出现在代码的任何位置,而不仅仅是函数声明可以出现的位置。函数表达式的语法如下:
王小婷
2023/10/23
4510
JavaScript(js)函数声明与函数表达式的区别
在JavaScript中,函数是经常用到的,在实际开发的时候,我想很多人都没有太在意函数的声明与函数表达式的区别,但是呢,这种细节的东西对于学好js是非常重要的。
全栈学习笔记
2022/03/31
8370
函数表达式
定义函数的方式有两种:第一种是“函数声明”,另一种就是“函数表达式”。 “函数声明”会被提升,意味着把函数声明放在调用它的语句后面。 示例1:
奋飛
2019/08/15
5050
javascript中函数声明与函数表达式
在javascript中,我们经常要声明函数,或者使用函数表达式,今天我们就来说说这两者的区别。
小明爱学习
2020/01/21
5050
【JavaScript】预解析 ① ( 变量预解析 - 变量提升 | 函数预解析 - 函数提升 | 函数表达式预解析 )
JavaScript 代码 是 由 浏览器 的 JavaScript 解析器 执行的 , 执行过程分如下两步 :
韩曙亮
2024/04/09
1820
【JavaScript】预解析 ① ( 变量预解析 - 变量提升 | 函数预解析 - 函数提升 | 函数表达式预解析 )
灵活使用JS函数声明与函数表达式要弄清哪两点?
要弄清函数声明和函数表达式的区别,首先要明白在JS中声明和表达式的行为存在十分微妙而又十分重要的差别。
前端_AWhile
2019/08/29
6840
JavaScript立即执行函数的解释分析(2)—函数表达式与函数声明的区别
上次我们聊了聊表达式与语句的区别,这次我们说说函数表达式与函数声明,上次虽然提到过这两点,但是并没有很详细的讲,这次要专门聊聊了!
FEWY
2019/05/26
5770
JavaScript进阶-函数表达式与闭包
在JavaScript的世界里,函数不仅是执行特定任务的代码块,它们还拥有独特的属性和行为,如函数表达式和闭包,这些特性极大地丰富了语言的功能和灵活性。本文将深入浅出地探讨这两个概念,揭示它们的工作原理、常见问题、易错点及避免策略,并通过实例代码加深理解。
Jimaks
2024/06/19
1120
JavaScript进阶-函数表达式与闭包
javascript中函数声明和函数表达式浅析
记得在面试腾讯实习生的时候,面试官问了我这样一道问题。 //下述两种声明方式有什么不同 function foo(){}; var bar = function foo(){};  当初只知道两种声明方式一个是函数声明一个是函数表达式,具体有什么不同没能说得很好。最近正好看到这方面的书籍,就想好好总结一番。 在ECMAScript中,有两个最常用的创建函数对象的方法,即使用函数表达式或者使用函数声明。对此,ECMAScript规范明确了一点,即是,即函数声明 必须始终带有一个标识符(Identifier)
Sb_Coco
2018/05/28
9562
JS 中的函数表达式和函数声明你混淆了吗?
在 JavaScript 中,function关键字可以完成一个简单的工作:创建一个函数。 但是,使用关键字定义函数的方式可以创建具有不同属性的函数。
前端小智@大迁世界
2022/06/15
7770
学弟的一张图,让我重学了一遍函数声明和函数表达式!
有用过的同学可能看到这里,说我知道,完后写出了上面这段代码,但其实这段代码是不对的,会爆出fn is not a function这个错误。
是乃德也是Ned
2022/08/04
3730
学弟的一张图,让我重学了一遍函数声明和函数表达式!
函数声明与表达式的区别
HTML5学堂:函数有不同的定义方法,一种是函数声明,另一种是函数表达式,那么这两种有何区别呢? 函数声明的基本语法 function functionName(arg0, arg1, ..., argn) { // 函数体 - HTML5学堂 } 函数声明的重要特征:函数声明提升 在执行代码之前,会先读取函数声明,这也就意味着,可以把函数声明放在调用它的语句的后面。 函数表达式的常见语法形式 var functionName = function(arg0, arg1, ..., argn) {
HTML5学堂
2018/03/12
7820
IIFE 立即执行函数表达式
IIFE全称为Immediately Invoked Function Express-立即执行函数(表达式),顾名思义,是在定义之后立即执行的函数。IIFE主要以保护变量范围著称,时候也会被称为“自执行的匿名函数”(self-executing anonymous function)。
泯泷、
2024/03/11
1360
浅谈JavaScript的函数表达式(闭包)
  前文已经简单的介绍了函数的闭包。函数的闭包就是有权访问另一个函数作用域的函数,也就是函数内部又定义了一个函数。 1 var Super=function(num){ 2 var count=num; 3 return function(){ 4 console.log(count); 5 } 6
水击三千
2018/02/27
6520
浅谈自执行函数(立即调用的函数表达式)
既然函数名加上括号fun1()就是执行函数。 思考:直接取赋值符号右侧的内容直接加个括号,是否也能执行? 试验如下,直接加上小括弧:
celineWong7
2020/11/05
3.6K0
Javascript中的函数声明和函数表达式
Javascript有很多有趣的用法,在Google Code Search里能找到不少,举一个例子:
LA0WAN9
2021/12/14
6040
函数声明与函数表达式
函数声明:直接声明一个函数 function fnName() {};function声明必须有方法名,而出现在表达式里的方法名都会被忽略。
meteoric
2018/11/15
7910
【JavaScript】函数 ⑦ ( 函数定义方法 | 命名函数 | 函数表达式 )
在 函数表达式 中 , 可以将 匿名函数 赋值给一个变量 , 上面的语法结构就是 将 匿名函数 赋值给 变量 的 语法 ;
韩曙亮
2024/04/09
2830
【JavaScript】函数 ⑦ ( 函数定义方法 | 命名函数 | 函数表达式 )
推荐阅读
相关推荐
前端同学经常忽视的一个 JavaScript 面试题
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档