我正在JavaScript中阅读slice
上的MDN Article。我理解除了第二个例子之外的所有内容,标题为 Array-Like Objects 。
它说我们可以通过将slice
作为我们自己的函数来简化第一个例子:
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
function list() {
return slice(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
我不明白call
在第二行prototype
之后可能会如何发现。
我通常会以Array.prototype.slice.call(arguments)
或类似的形式看到它。
我不了解前两行的流程以及它们如何生成此slice
函数。
答案 0 :(得分:4)
Function.prototype.call()
的{{3}}帮助我解决了这个问题。
我能回答的最简单的方式:
在javascript中,Function有一个名为
call
的方法。功能是一个 对象,所有对象都从它们继承方法和属性 原型。
因此,Array.prototype.slice.call(arguments)
的示例显示您在切片函数上调用了调用方法。
您感到困惑的代码中的第二行:var slice = Function.prototype.call.bind(unboundSlice);
显示属于Function原型的调用方法。
如果您仍然感到困惑,请结帐MDN article。
1函数是对象。
2"每个JavaScript对象都有一个原型。"
3"原型也是一个对象。"
4"所有JavaScript对象都从其原型继承其属性和方法。"
换句话说,回到最简单的方式回答这个问题:在javascript中,一个Function有一个名为call
的方法。
至于理解bind
的作用,JavaScript Prototypes文章中的that = this
vs .bind
示例有助于了解正在发生的事情。
如果这令人困惑,请确保您理解this
答案 1 :(得分:3)
tl;博士:
var slice = Function.prototype.call.bind(unboundSlice);
是一种简短的写作方式:
var slice = function(value, start, end) {
return unboundSlice.call(value, start, end);
};
让我们考虑第二行:
Array.prototype.slice.call(arguments)
.slice
是一种提取数组子集的数组方法。它的值为this
。 .call
是每个函数都有的方法,它允许您为函数执行设置this
值。因此,上述行允许我们执行slice
作为arguments
的方法,而不必改变arguments
本身。我们可以完成
arguments.slice = Array.prototype.slice;
arguments.slice();
但这不是那么干净。
现在看
Function.prototype.call.bind(unboundSlice);
如上所述,.call
是每个函数所具有的方法。它也在this
上运行,预计它将成为一种功能。它调用this
并将该函数的this
值设置为第一个参数。你可以认为call
与
function call(thisValue, arg1, arg2, ...) {
return this.apply(thisValue, [arg1, arg2, ...]);
}
请注意它如何将this
称为函数。
.bind
也是每个函数都有的方法。它返回一个新函数,其this
值固定为您传入的第一个参数。
让我们考虑call.bind(unboundSlice)
的结果函数是什么样的:
function boundCall(thisValue, arg1, arg2, ...) {
return unboundSlice.apply(thisValue, [arg1, arg2, ...]);
}
我们只是将this
替换为unboundSlice
。 boundCall
现在将始终致电unboundSlice
。
答案 2 :(得分:2)
slice
是Array.prototype
的属性,它期望其this
对象与数组类似。您可以在类似于Array的对象(具有length属性并具有可以索引的属性)上使用它,它们没有自己的切片函数,如下所示:
Array.prototype.slice.call(arraylikething);
这是很多打字,所以我们可以做一个功能来做同样的事情:
var slice = function(arraylikething){
return Array.prototype.slice.call(arraylikething);
};
JavaScript提供Function.prototype.bind
将函数绑定到指定的this
对象。所以我们可以更轻松地完成同样的事情:
var slice = Function.prototype.call.bind(Array.prototype.slice);
bind
创建一个新函数,返回call
的结果,其this
对象设置为Array.prototype.slice
,与我们上面手动执行的操作相同,相当于你的代码。
答案 3 :(得分:1)
Chris Dillinger的回答是正确的,内容丰富。但这是考虑它的另一种方式。实质上,您被要求定义
Function.prototype.call.bind(Array.prototype.slice)
你可以这样看:
fn.bind(context)
==> function(...args) {return context.fn(...args);}
// 1. definition of `bind` (oversimplified, but enough for this case)
fn.bind(unboundSlice)
==> function(...args) {return unboundSlice.fn(...args);}
// 2. substitute `unboundSlice` for `context`
Function.prototype.call.bind(unboundSlice)
==> function(...args) {return unboundSlice[Function.prototype.call](...args);}
// 3. substitute `Function.prototype.call` for `fn`.
Function.prototype.call.bind(unboundSlice)
==> function(...args) {return unboundSlice[.call(...args);}
// 4. walk the prototype chain
Function.prototype.call.bind(Array.prototype.slice)
==> function(...args) {return Array.prototype.slice.call(...args);}
// 5. substitue `Array.prototype.slice` for `unboundSlice`
唯一有点棘手的步骤是第4步,你必须意识到所有函数都从其原型链继承call
方法,因此在它们上调用call
仅仅是另一种调用函数本身的方法。
答案 4 :(得分:0)
在第一行中,Array.prototype.slice
(这是一种方法)只是通过unboundSlice
引用。您实际上是从Array.prototype
“提取”切片方法。
在第二行中,同样的事情发生在Function.prototype.call
上,这也是ALL函数的一种方法。 (它在Function.prototype
中定义,并由所有函数继承)。
接下来,通过使用.bind(unboundSlice)
,调用函数的this
值绑定到Array.prototype.slice
的引用,这实际上与Array.prototype.slice.call()
的结果相同,其中调用也是将this
绑定到slice
,因为它是它的一种方法,因为它被调用了。
最后,绑定调用方法通过var slice
;
这里的一般想法是,您可以在另一个上下文(全局范围)中使用数组方法(切片)的功能。
现在,不是在call
已经是slice
的方法时调用slice
,而是将this
绑定为call
// Dataset = list of players and their attributes
private final ArrayList<PlayerData> dataSet;
private final List<PlayerData> filteredList;
private ArrayList<PlayerData> originalItems;
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView textViewName;
TextView textViewPos;
ImageView imageViewFace;
ImageView imageTeamLogo;
TextView textViewTeam;
public MyViewHolder(View itemView) {
super(itemView);
this.textViewName = (TextView) itemView.findViewById(R.id.textViewName);
this.textViewPos = (TextView) itemView.findViewById(R.id.textViewPos);
this.imageViewFace = (ImageView) itemView.findViewById(R.id.imageViewFace);
this.imageTeamLogo = (ImageView) itemView.findViewById(R.id.ImgTeamLogo);
this.textViewTeam = (TextView) itemView.findViewById(R.id.textViewTeam);
}
}
//dataset = data from Main Activity
public CustomAdapter(ArrayList<PlayerData> data) {
this.dataSet = data;
this.filteredList = data;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cards_layout, parent, false);
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int Position) {
// called everytime user scrolls up or down
TextView textViewName = holder.textViewName;
TextView textViewPos = holder.textViewPos;
ImageView imageViewFace = holder.imageViewFace;
ImageView imageViewLogo = holder.imageTeamLogo;
TextView textViewTeam = holder.textViewTeam;
textViewName.setText(dataSet.get(Position).getName());
textViewPos.setText(dataSet.get(Position).getPos());
textViewTeam.setText(dataSet.get(Position).getTeam());
Context context = imageViewFace.getContext();
Context context2 = imageViewLogo.getContext();
Picasso.with(context)
.load(dataSet.get(Position).getFace())
.placeholder(R.drawable.ic_launcher)
.error(R.drawable.ic_3d_rotation)
.into(holder.imageViewFace);
Glide.with(context2).load(dataSet.get(Position).getTeamLogo()).into(holder.imageTeamLogo);
}
@Override
public int getItemCount() {
return dataSet.size();
}
public void animateTo(ArrayList<PlayerData> players) {
//checks what query found and adds / removes results
// problem is, it is not adding back results
applyAndAnimateRemovals(players);
applyAndAnimateAdditions(players);
applyAndAnimateMovedItems(players);
}
private void applyAndAnimateRemovals(ArrayList<PlayerData> newPlayers) {
for (int i = dataSet.size() - 1; i >= 0; i--) {
final PlayerData player = dataSet.get(i);
if (!newPlayers.contains(player)) {
removeItem(i);
}
}
}
private void applyAndAnimateAdditions(ArrayList<PlayerData> newPlayers) {
for (int i = 0, count = newPlayers.size(); i < count; i++) {
final PlayerData player = newPlayers.get(i);
if (!dataSet.contains(player)) {
addItem(i, player);
}
}
}
private void applyAndAnimateMovedItems(ArrayList<PlayerData> newPlayers) {
for (int toPosition = newPlayers.size() - 1; toPosition >= 0; toPosition--) {
final PlayerData player = newPlayers.get(toPosition);
final int fromPosition = dataSet.indexOf(player);
if (fromPosition >= 0 && fromPosition != toPosition) {
moveItem(fromPosition, toPosition);
}
}
}
public PlayerData removeItem(int position) {
final PlayerData player = dataSet.remove(position);
notifyItemRemoved(position);
return player;
}
public void addItem(int position, PlayerData player) {
dataSet.add(position, player);
// this code is not working for whatever reason)
notifyItemInserted(position);
}
public void moveItem(int fromPosition, int toPosition) {
final PlayerData player = dataSet.remove(fromPosition);
dataSet.add(toPosition, player);
notifyItemMoved(fromPosition, toPosition);
}
}
的值public class MainFragment extends Fragment implements SearchView.OnQueryTextListener {
public static MainFragment newInstance() {
return new MainFragment();
}
private static RecyclerView recyclerView;
private static CustomAdapter adapter;
private static ArrayList<PlayerData> data;
private RecyclerView.LayoutManager layoutManager;
static View.OnClickListener myOnClickListener;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_main, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
data = new ArrayList<PlayerData>();
addPlayers();
adapter = new CustomAdapter(data);
recyclerView.setAdapter(adapter);
}
public interface Constants {
String LOG = "com.vogella.testapp";
}
private void addPlayers() {
PlayerData player = new PlayerData("Chris Smith", "#", R.drawable.auser, R.drawable.aquestion, "First", 0);
data.add(0,player);
player = new PlayerData("Bobby Richars","#", R.drawable.auser, R.drawable.aquestion, "Second", 9);
data.add(player);
player = new PlayerData("Steven Williams", "#", R.drawable.auser, R.drawable.aquestion, "Third", 1);
data.add(player);
player = new PlayerData("Tony Lloyd", "#", R.drawable.auser, R.drawable.aquestion, "Fourth", 2);
data.add(player);
player = new PlayerData("Henry Gates", "#", R.drawable.auser,R.drawable.aquestion, "Fifth", 3);
data.add(player);
player = new PlayerData("Robert Marks", "#", R.drawable.auser, R.drawable.aquestion, "Sixth", 4);
data.add(player);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_main, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setOnQueryTextListener(this);
}
@Override
public boolean onQueryTextChange(String query) {
final ArrayList<PlayerData> filteredModelList = filter(data, query);
adapter.animateTo(filteredModelList);
recyclerView.scrollToPosition(0);
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
private ArrayList<PlayerData> filter(ArrayList<PlayerData> players, String query) {
query = query.toLowerCase();
final ArrayList<PlayerData> filteredModelList = new ArrayList<>();
for (PlayerData player : players) {
final String text = player.getName().toLowerCase() + player.getPos().toLowerCase()+ player.getTeam().toLowerCase();
if (text.contains(query)) {
filteredModelList.add(player);
}
}
return filteredModelList;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
return true;
}
}
为了达到同样的行为。