instanceof在查找的过程中会遍历左边的原型链,直到找到右边变量的prototype,如果查找失败就返回false
// instanceof的作用是判断当前目标对象是否是指定的类型 // 解决思路是:instanceof在查找的过程中会遍历左边的原型链,直到找到右边变量的prototype,如果查找失败就返回false let myInstanceof = (target, origin) => { while (target) { if (target.__proto__ === origin.prototype) { return true } target = target.__proto__ } return false } let arr = [2, 3, 5] console.log(myInstanceof(arr, Array)) // true console.log(myInstanceof(arr, Object)) // true
<script>
// map() 方法返回一个新数组,新数组中的元素为原始数组中的每个元素调用函数处理后得到的值。
Array.prototype.myMap = function (fn, context) {
let res = [] // 用来保存返回的新数组
context = context || []
let arr = this //由于方法是添加到数组原型上的,所以谁调用这个方法this就指向哪个数组
for (let i = 0; i < arr.length; i++) {
res.push(fn(arr[i]))
}
return res
}
let arr = [1, 2, 3]
let res = arr.myMap((item) => item * 2)
console.log(res)
</script>
Array.prototype.myMap = function (fn, thisValue) { var res = [] thisValue = thisValue || [] // pre:累加的值,cur:当前数组的值,index:当前的值的索引,arr:当前的数组 // this指的是当前调用这个方法是数组 this.reduce(function (pre, cur, index, arr) { return res.push(fn.call(thisValue, cur, index, arr)) }, []) return res } var arr = [2, 3, 1, 4] var res = arr.myMap(function (item, index, arr) { return item + 1 }) console.log(res) // 3,4,2,5
<body>
<!--
reduce方法的使用,
参数1传递一个函数作为参数,函数中有四个参数:
total:累加项的和
currValue:当前循环的项
currIndex:当前循环项的索引
arr:当前的数组
参数2是一个初始值:如果传递了值,它就会作为total的初始值,arr的第一项就会作为currvalue的值
如果没有传递值:arr的第一项就是作为total的值,第二项就会作为currvalue的值
-->
<!-- <script>
var arr = [1, 2, 3, 4]
var i = 0
var y = 0
const res1 = arr.reduce(function (total, currValue, currIndex, arr) {
console.log(i)
i++
return total + currValue
})
const res2 = arr.reduce(function (total, currValue, currIndex, arr) {
console.log(y)
y++
return total + currValue
}, 10)
console.log(res1) // 10
console.log(res2) // 20
</script> -->
<script>
//实现reduce方法
//如果有initValue,那么total的值就是initValue,currValue的值就是arr的第一项
//如果没有initValue,那么total的值就是arr的第一项
var arr = [1, 2, 3, 4]
Array.prototype.myReduce = function (fn, initValue) {
var i = 0
// 1.先判断initValue的值是否存在
if (
Object.prototype.toString.call(initValue) === '[object Undefined]'
) {
// 如果不存在,initvalue的值就是初始值
initValue = this[0]
i = 1
console.log('false')
}
for (i; i < this.length; i++) {
initValue = fn(initValue, this[i], i, this)
}
return initValue
}
const res = arr.myReduce(function (total, currValue, currIndex, arr) {
return total + currValue
}, 10)
console.log(res)
</script>
</body>
<body> 数组扁平化就是将多维数组转为一维数组 <!-- <script> // 方法一:使用flat,这是es6新增方法方法,flat方法的参数是需要转换的维度 var arr = [1, 3, 4, [3, [3, 5, [6, 1, 8]]]] //这是四维数组 console.log(arr.flat()) console.log(arr.flat(Infinity)) // 如果不知到数组的维度可以使用Infinity </script> --> <!-- 利用concat实现数组扁平化,不能和flat一样指定维度,concat可以链接两个数组或者多个数组--> <script> var arr = [1, 3, 4, [3, [3, 5, [6, 1, 8]]]] //这是四维数组 function myFlat(arr) { let res = [] for (let i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { res = res.concat(myFlat(arr[i])) } else { res.push(arr[i]) } } return res } console.log(myFlat(arr)) </script> </body>
(1)使用递归实现深拷贝
<script>
//创建一个引用类型的数据
var oldObj = {
name: 'zs',
happy: ['吃饭', '睡', '打豆豆'],
parent: {
father: 'li',
mather: 'wang'
}
}
//创建一个新对象
var newObject = {}
//创建一个函数用于实现深拷贝,主要使用了递归
function cloneDeep(target, source) {
//先循环获取每一项
for (let i in source) {
let item = source[i]
//判断每一项中的数据是否是数组
if (item instanceof Array) {
target[i] = []
cloneDeep(target[i], item)
} else if (item instanceof Object) {
//如果当前项是对象,就返回
target[i] = {}
cloneDeep(target[i], item)
} else {
target[i] = item
}
}
return target
}
cloneDeep(newObject, oldObj)
oldObj.name = '李四'
console.log(oldObj)
console.log(newObject)
</script>
(2)使用Object.create()方法实现深拷贝
<script>
//创建一个引用类型的数据
// var oldObj = {
// name: "zs",
// happy: ['吃饭', '睡', '打豆豆'],
// parent: {
// father: 'li',
// mather: 'wang'
// }
// };
// //使用方法获取一个拷贝来的方法
// var newObj = Object.create(oldObj);
// console.log(newObj);
// console.log(newObj.__proto__);
//注意使用该方法实现的深拷贝它的属性是放在它的原型上的,这些属性不是newObj自己拥有的
// object.create()方法的实现原理:利用了原型是继承
function create2(o) {
function NewObj() {}
NewObj.prototype = o
return new NewObj()
}
//创建一个引用类型的数据
var oldObj = {
name: 'zs',
happy: ['吃饭', '睡', '打豆豆'],
parent: {
father: 'li',
mather: 'wang'
}
}
//使用方法获取一个拷贝来的方法
var newObj = create2(oldObj)
console.log(newObj)
console.log(newObj.__proto__)
</script>
(3)使用jquery的extend方法实现深拷贝
<script src="./query.js"></script>
<script>
//创建一个引用类型的数据
var oldObj = {
name: "zs",
happy: ['吃饭', '睡', '打豆豆'],
parent: {
father: 'li',
mather: 'wang'
}
};
var newObj = $.extend({}, oldObj);
console.log(newObj);
extend方法的使用方法
// extend(obj1,obj2,obj3):她将obj2,obj3的值复制给obj1,如果有重复的属性就覆盖她
</script>
(4)使用JSON.parse和JSON.stringify方法实现深拷贝
<script>
//创建一个引用类型的数据
var oldObj = {
name: "zs",
happy: ['吃饭', '睡', '打豆豆'],
parent: {
father: 'li',
mather: 'wang'
}
};
var newObj = JSON.parse(JSON.stringify(oldObj));
newObj.name = "李四";
console.log(oldObj);
console.log(newObj)
</script>
(1)使用扩展运算符
<!-- 什么是扩展运算符? 扩展运算符就是三个点,扩展运算符的作用就是将数据或者类数组对象转为用逗号隔开的值 --> <script> var arr = [1, [7, [9]], { a: "1" }, function() {}, null, undefined, NaN]; var result = [...arr]; console.log(result); //修改源对象中的某个值 arr[2].a = "222"; console.log(arr); console.log(result); </script>
(2)使用assgin方法
<script>
var arr = [1, [7, [9]], {
a: "1"
}, function() {}, null, undefined, NaN];
var result = Object.assign(arr);
console.log(result);
//修改源对象中的某个值
arr[2].a = "222";
console.log(arr);
console.log(result);
</script>
<script>
// 手动实现apply(obj, [arg1, arg2, arg3])
Function.prototype.myApply = function (context) {
let obj = context || window
obj.fn = this
const arg = arguments[1] || [] // 如果传递的有参数,那么第二个就是传毒的参数数组
let res = obj.fn(...arg)
delete obj.fn
return res
}
function f(a, b) {
console.log(a, b)
console.log(this.name)
}
let obj = {
name: '这是'
}
f.myApply(obj, [1, 2])
</script>
<script>
// 手动实现call(obj,arg1,arg2)
Function.prototype.myCall = function (context) {
let obj = context || window
obj.fn = this
// 获取参数,由于参数不确定传递过来的个数,就先去掉第一个参数,他就是要指向的this
let arr = [...arguments].slice(1)
res = obj.fn(...arr)
delete obj.fn
return res
}
function f(a, b) {
console.log(a, b)
console.log(this.name)
}
let obj = {
name: '栗色'
}
f.myCall(obj, 1, 2)
</script>
<script>
// 手动实现bind(obj,[arg1,arg2])由于bind函数支持柯里化
Function.prototype.myBind = function (context) {
let obj = context || window
let fn = this
// 获取第一次传递过来的参数
let arg = Array.prototype.slice.call(arguments, 1) // 由于第一位是obj,所以需要将裁剪
return function () {
let arr = Array.prototype.slice.call(arguments)
fn.apply(obj, arg.concat(arr))
}
}
let obj = {
name: '展示'
}
function fn(a, b) {
console.log(a, b)
}
let call = fn.bind(obj, [2, 3])
call(20)
</script>
<body> new的操作: (1)创建一个空对象, (2)将对象的__proto__指向构造函数的原型对象 (3)利用apply改变this的指向, (4)返回结果 <script> function Person(name, age) { this.age = age this.name = name } Person.prototype.sayHi = function () { console.log('hi,' + this.name) } var p1 = new Person('张三', 20) console.log(p1) // 手动实现new function myCreate() { // 创建一个空对象 let obj = {} // 获取传递过来的构造函数 let fn = [].shift.call(arguments) // shift方法将数组的第一项弹出来并且返回弹出的第一项,这里的[]填不填元素都没有关系 // 将空对象的__proto__指向构造函数的prototype(获取构造函数原型上的方法) obj.__proto__ = fn.prototype // 使用apply修改this的指向,将传递过来的参数赋值给obj(获取属性) console.log(arguments) let res = fn.apply(obj, arguments) // 确保返回的是一个对象(以防传递进的fn不是构造函数) return typeof res === 'object' ? res : obj } var p2 = myCreate(Person, '李四', 30) console.log(p2) </script> </body>