-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 46 题:输出以下代码执行的结果并解释为什么 #76
Comments
留下了没技术的泪水 |
求解释. |
以下为个人猜想没有确切的理论依据:
根据MDN的说法理解, 根据这个测试我们发现,
这个时候控制台输出的是一个数组,但是实际上它是一个伪数组,并没有数组的其他属性和方法,我们可以通过这种方法验证: 所以我认为题目的解释应该是:
第一第二步还可以具体解释为:因为每次push只传入了一个参数,所以 obj.length 的长度只增加了 1。push方法本身还可以增加更多参数,详见 MDN |
我的理解是这样的
|
关于 |
留下了没技术的眼泪,求大佬出详细答案。 |
push 是特意设计为通用的,我们可以使用它来获得便利。正如下面的例子所示,Array.prototype.push 可以在一个对象上工作。 注意,我们没有创建一个数组来存储对象的集合。 相反,我们将该集合存储在对象本身上,并使用在 Array.prototype.push 上使用的 call 来调用该方法,使其认为我们正在处理数组,而它只是像平常一样运作。
}; // Let's add some empty objects just to illustrate. 因为obj具有 length 属性和 splice 方法,故将其作为数组进行打印 |
@Moriarty02 同学讲的 |
@kangkai124 我这边试了一下,只要一个对象的 var obj1 = {
length: 1,
splice: function () {},
}; // Object [empty, splice: ƒ]
var obj2 = {
length: '1',
splice: function () {},
}; // {length: "1", splice: ƒ}
var obj3 = {
length: 1,
splice: {},
}; // {length: 1, splice: {…}} |
array-list 拥有length属性 , 属性为数字,即为类数组对象。 后面的 push等属性 是让类数组对象拥有部分数组方法特性。 |
涉及知识点:
一组数据,由数组来存,但是如果要对这组数据进行扩展,会影响到数组原型,ArrayLike的出现则提供了一个中间数据桥梁,ArrayLike有数组的特性, 但是对ArrayLike的扩展并不会影响到原生的数组。
push 方法有意具有通用性。该方法和 call() 或 apply() 一起使用时,可应用在类似数组的对象上。push 方法根据 length 属性来决定从哪里开始插入给定的值。如果 length 不能被转成一个数值,则插入的元素索引为 0,包括 length 不存在时。当 length 不存在时,将会创建它。
Array.from()、splice()、concat()等 因为只是定义了2和3两项,没有定义0和1这两项,所以前面会是empty。
此时的打印结果就是: 原理:此时length长度设置为0,push方法从第0项开始插入,所以填充了第0项的empty |
/**
* @param {?Object} obj
* @return {boolean}
*/
function isArrayLike(obj) {
if (!obj || typeof obj !== 'object')
return false;
try {
if (typeof obj.splice === 'function') {
const len = obj.length;
return typeof len === 'number' && (len >>> 0 === len && (len > 0 || 1 / len > 0));
}
} catch (e) {
}
return false;
} 判断的过程:
|
看文档: 解析: 所以:很得到的答案很明显。 |
涨姿势了,数组的push 方法根据 length 属性来决定从哪里开始插入给定的值以及判断伪数组的方法: |
这一题考察的是伪数组: (以下献丑) 首先搞清楚这一题要搞清楚 push ,其实push的时候会首先查询数组(伪数组)的 length 属性,接着在数组的最后一个添加上新的元素即 arr[length] (数组从零开始),然后length 增加一。 在这一题中,首先 伪数组查到length 是 2 ,就会 直接在 2 这个下标(属性) 上push 1 , 而length 会增加 1 变成 3 ,接着重复这个过程。 题外话: 伪数组 没有 length 的时候默认是 0。 前端小白, 有错勿怪, 欢迎指正。 |
没记错的话,在不同环境下会产生不同结果, |
看了一下运行结果后,有点懵逼,然后去翻了一下v8里array.js的实现代码。
从实现的代码可以看出来,只要是对象拥有Array.prototype.push方法就会按照数组的push去执行。这句话说的直白点。
执行obj.push(1)时,当前length为2,正好替换了obj['2']的值,然后length变为3,obj.push(2)时就是替换obj['3']的值。就出来了浏览器的运行结果 |
var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj) 原题中 obj = {
'0': '',
'1': '',
'2': 1,
'3': 2
} |
function push (arr, item) { |
难道这就是redux可时光倒流的原理吗? |
秀儿又是你 |
数组会根据length来进行push操作。例如以上的obj会根据length==2 来更新下标,也就是push会从2(length==2,意味着在[0,1,***]后添加)开始 |
obj中length为指针 指向索引2 调用 obj.push(1) 等同于 obj[obj.length] = 1 length++ 所以 变为 [,,1,2] |
规范 The arguments are appended to the end of the array, in the order in which they appear. The new length of the array is returned as the result of the call. When the push method is called with zero or more arguments item1, item2, etc., the following steps are taken:
NOTE The push function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. Whether the push function can be applied successfully to a host object is implementation-dependent. 第七步是原因 |
/**
* 1. 当一个对象拥有length属性,并且splice属性是个函数,对我们来说就可以看作是一个类数组
* 2. 既然是类数组,对象的键就是数组的下标,对象的值就是数组当前下标的值
* 3. 此时撇开length属性不管,这个类数组可以看作:[empty, empty, 3, 4]
* 4. 当length属性起作用时,它将这个类数组的长度截断了,此时可以看作:[empty, empty]
* 5. 之后这个类数组进行了两次push操作,结果可以看作:[empty, empty, 1, 2]
* 6. 当然,这个类数组中还包含push和splice函数以及它的length,但并没有数组的其它方法,所以实
* 际上它只是一个对象而已
*/
let obj = {
'2': 3,
'3': 4,
length: 2,
splice: [].splice,
push: [].push
};
obj.push(1);
obj.push(2);
console.log(obj); // [empty, empty, 1, 2]
console.log(Object.prototype.toString.call(obj)); // [object Object] |
我感觉 学了个假的 js |
var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj) |
存在length的值为number类型和splice值为函数类型,将obj变为伪数组;
|
那为什么一开始就有 |
var obj = {
'2': 3,
'3': 4,
length: 2,
splice: Array.prototype.splice,
push: Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj) 数组对象JavaScript 数组的有一些特性是其他对象所没有的:
这些特性让 类数组对象把拥有一个数值 我们定义的 // 判断是否是类数组对象
const isArrayLike = obj =>
obj && // 非 null undefined
typeof obj === 'object' && // 是对象
isFinite(obj.length) && // 是有穷数
obj.length >= 0 && // 为非负数
obj.length === Math.floor(obj.length) && // 整数
obj.length < Math.pow(2, 32) // < 4294967296 同时 JavaScript 数组方法是特意定义为通用的,因此它们不仅应用在真正的数组而且在类数组对象上都能正确的工作。类数组对象没有继承自 那么我们改变一下题目 var obj2 = {
'2': 3,
'3': 4,
length: 2
}
Array.prototype.push.call(obj2, 1)
Array.prototype.push.call(obj2, 2)
// 这样的到的有效结果是一样的 {2: 1, 3: 2, length: 4}
// 通过数组的方法 // 1 2
Array.prototype.forEach.call(obj2, item => console.log(item))
// 其本质还是一个类数组 结果这是题目在 Chrome 浏览器控制台输出结果 我们改变的题目输出结果 我们可以看到有效结果是一样的,那么为什么结果会是如此呢?
so ~ // obj.push(1)
// 等同于
obj['2'] = 1
obj.length++ // length = 3
// obj.push(2)
// 等同于
obj['3'] = 2
obj.length++ // length = 4
// 那么之后的结果就是我们看到的了 但是还是有不一样的地方比如
那么我们接下来继续看 只有当对象 那么为此我又去 Firefox 控制台下面试了一下,结果如下图: 跟 Chrome 没有定义 splice 为 Function 是一致的 所以说可能是 Chrome 对其做的优化吧。 |
不够准确,length应该为自然数,负整数是不行的 |
01-输出以下代码执行的结果并解释为什么var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj) 类(伪)数组(arraylike)
arrayLike.push('sex') // 01.js:20 Uncaught TypeError: arrayLike.push is not a function 形式console.log(array[0]); // name
console.log(arrayLike[0]); // name
array[0] = "new name";
arrayLike[0] = "new name";
console.log(array[0]); // new name
console.log(arrayLike[0]); // new name 间接调用Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"] 转为真正的数组Array.from(arrayLike); 数组的push
大白话 其实push的时候会首先查询数组(伪数组)的 length 属性,接着在数组的最后一个添加上新的元素即 arr[length] var testObj = {
"2": 3,
"3": 4,
length: 2,
push: Array.prototype.push,
};
testObj.push(1)
console.log(testObj) //// {2: 1, 3: 4, length: 3, push: ƒ}
testObj.push(2)
console.log(testObj) //{2: 1, 3: 2, length: 4, push: ƒ}
'splice': Array.prototype.splice /**
* @param {?Object} obj
* @return {boolean}
*/
function isArrayLike(obj) {
if (!obj || typeof obj !== 'object') {
return false;
}
try {
if (typeof obj.splice === 'function') {
const len = obj.length;
return typeof len === 'number' && (len >>> 0 === len && (len > 0 || 1 / len > 0));
}
} catch (e) {
}
return false;
} 为什么对象添加了splice属性后并没有调用就会变成类数组对象这个问题,这是控制台中 DevTools 猜测类数组的一个方式
|
楼上同学都答过了,我说一下个人理解,obj是一个类数组,本质是一个对象,但是拥有了数组的push和slice方法;而push方法其实就是在obj[length] 附上一个值,然而让length++这么一个操作; |
只能说涨姿势了 |
var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj) node环境中运行结果: {
'2': 1,
'3': 2,
length: 4,
splice: [Function: splice],
push: [Function: push]
} 使用浏览器运行代码
let arr = [];
arr[1000] = 1;
console.log(arr.length); // 1001 数组的length属性是可写的,如果人为将length设置的小于当前数组内元素数目,元素数目会自动减少到length设置的大小。 let arr = [1,2,3];
arr.length = 0;
console.log(arr)// []
obj1 = {
splice: Array.prototype.splice,
};
// {splice: ƒ}
obj2 = {
2: 1,
splice: Array.prototype.splice,
};
// {2: 1, splice: ƒ}
obj3 = {
length: 1,
splice: Array.prototype.splice,
};
// Object [empty, splice: ƒ]
obj4 = {
length: 2,
splice: Array.prototype.splice,
};
// Object(2) [empty × 2, splice: ƒ]
obj5 = {
length: 2,
splice: () => {},
};
// Object(2) [empty × 2, splice: ƒ]
obj6 = {
length: 2,
splice: 3,
};
// {length: 2, splice: 3} 对象有length属性和splice函数, splice可以是自定义函数,在Chrome Devtools中就会被判定为类数组对象。 |
这题在我看来是两方面知识的理解:
知道了上面这两点之后先来看
再来看
所以题解也就清晰了: var obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj) 因为指定了类数组的 之后push将改变length,原先的 至于 var obj = {
length: 2,
splice: Array.prototype.splice,
};
console.log(obj);//Object(2) [empty × 2, splice: ƒ]
console.log(Array.isArray(obj));//false 对于 |
想問如何讀 V8 code |
感觉类似这个Array.prototype.push.call(obj, 1,2) |
不得不说,面试是面试,工作是工作。如果代码审查时看到谁写这么难以理解的东西,直接两巴掌 |
这种题是哪些天才想出来的?哈哈 |
push 设计为通用方法 splice 和 length 是 isArrayLike 的判断条件,使其认为为伪数组 |
我将这个代码直接在Chrome浏览器控制台运行,输出结果依然是对象,不是数组啊 |
结果:[,,1,2], length为4
伪数组(ArrayLike)
The text was updated successfully, but these errors were encountered: