js中indexOf的原理
时间: 2023-07-06 18:36:29 浏览: 66
JavaScript中的indexOf()方法是用于查找数组中某个元素第一次出现的位置。其原理是遍历数组中的每个元素,比较元素与传入参数的值是否相等,如果相等则返回元素的下标,否则返回-1。
具体的实现步骤如下:
1. 首先判断传入的数组是否为一个数组对象,如果不是,则抛出一个类型错误;
2. 遍历数组中的每个元素,比较元素与传入参数的值是否相等,如果相等则返回元素的下标;
3. 如果遍历完整个数组都没有找到符合条件的元素,则返回-1。
下面是一个简单的indexOf()方法的实现示例:
```
function indexOf(arr, value) {
if (!Array.isArray(arr)) {
throw new TypeError(arr + ' is not an array');
}
for (var i = 0; i < arr.length; i++) {
if (arr[i] === value) {
return i;
}
}
return -1;
}
```
需要注意的是,indexOf()方法在比较元素与传入参数的值是否相等时使用的是全等(===)比较运算符,因此对于NaN等特殊值需要进行特殊处理。
相关问题
js 找到同一个数组中相同的值
可以使用 JavaScript 的 `indexOf` 函数来找到数组中相同的值。
例如,如果你想要找到数组 `[1, 2, 3, 3, 4, 4, 5]` 中所有重复的值,可以使用以下代码:
```
let arr = [1, 2, 3, 3, 4, 4, 5];
for (let i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) !== i) {
console.log(arr[i]);
}
}
```
这会在控制台输出:
```
3
4
```
这个方法的原理是,对于每个数组中的元素,使用 `indexOf` 函数来查找该元素在数组中的第一次出现的位置。如果该位置不是这个元素的当前索引,那么就说明这个元素在数组中出现了多次,并输出该元素。
vue2实现响应式原理
Vue2 的响应式原理主要是基于 Object.defineProperty() 函数实现的。
Vue2 通过对数据对象的访问拦截,在访问数据对象的时候自动触发依赖收集和派发更新操作。具体实现步骤如下:
1. 遍历数据对象的所有属性,为每个属性创建一个独立的依赖收集器(Dep)对象。
2. 对访问数据对象的方法进行重写,使其在访问数据对象的属性时,将当前正在执行的 Watcher 对象添加到该属性对应的依赖收集器中。
3. 对修改数据对象的方法进行重写,使其在修改数据对象的属性时,触发该属性对应的依赖收集器对象的派发更新操作,通知所有依赖于该属性的 Watcher 对象更新视图。
具体实现代码如下:
```javascript
function defineReactive(obj, key, val) {
const dep = new Dep(); // 创建依赖收集器对象
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
if (Dep.target) {
dep.depend(); // 将当前 Watcher 对象添加到依赖收集器中
}
return val;
},
set: function reactiveSetter(newVal) {
if (newVal === val) {
return;
}
val = newVal;
dep.notify(); // 触发依赖收集器对象的派发更新操作,通知所有 Watcher 对象更新视图
}
});
}
function observe(obj) {
if (!obj || typeof obj !== 'object') {
return;
}
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key]);
});
}
class Watcher {
constructor(vm, expOrFn, cb) {
this.vm = vm;
this.getter = parsePath(expOrFn);
this.cb = cb;
this.value = this.get();
}
get() {
Dep.target = this;
const value = this.getter.call(this.vm, this.vm);
Dep.target = null;
return value;
}
update() {
const oldValue = this.value;
this.value = this.get();
this.cb.call(this.vm, this.value, oldValue);
}
}
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
removeSub(sub) {
remove(this.subs, sub);
}
depend() {
if (Dep.target) {
Dep.target.addDep(this);
}
}
notify() {
const subs = this.subs.slice();
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update();
}
}
}
Dep.target = null;
const targetStack = [];
function pushTarget(target) {
targetStack.push(target);
Dep.target = target;
}
function popTarget() {
targetStack.pop();
Dep.target = targetStack[targetStack.length - 1];
}
function parsePath(path) {
const segments = path.split('.');
return function(obj) {
for (let i = 0; i < segments.length; i++) {
if (!obj) {
return;
}
obj = obj[segments[i]];
}
return obj;
};
}
function remove(arr, item) {
if (arr.length) {
const index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1);
}
}
}
class Vue {
constructor(options) {
this._data = options.data;
observe(this._data);
this._watchers = [];
this._initWatchers(options);
}
_initWatchers(options) {
const watchers = options.watch || {};
for (let key in watchers) {
const handler = watchers[key];
this.$watch(key, handler);
}
}
$watch(expOrFn, cb) {
const watcher = new Watcher(this, expOrFn, cb);
this._watchers.push(watcher);
return function unwatch() {
watcher.teardown();
};
}
}
```
上述代码中,defineReactive 函数用于将一个属性变成响应式的,observe 函数用于遍历数据对象的所有属性并调用 defineReactive 函数,Watcher 类用于封装一个 Watcher 对象,Dep 类用于封装一个依赖收集器对象。Vue 类则用于封装一个 Vue 实例,实现了 $watch 方法用于监听数据的变化,并创建 Watcher 对象。在 Watcher 对象的构造函数中,会调用 parsePath 函数将表达式字符串转换成一个函数,然后调用该函数获取数据对象的值,并触发依赖收集。在数据对象的属性被修改时,会触发该属性对应的依赖收集器对象的派发更新操作,通知所有 Watcher 对象更新视图。