关于Object.create()与原型链的面试题?
原文地址 https://segmentfault.com/q/1010000004670616?utm_source=weekly&utm_medium=email&utm_campaign=email_weekly 本处是转载学习 javascript zhuzi 6 天前提问 · 6 天前更新
关注 15 关注
收藏 3 收藏,284 浏览
问题对人有帮助,内容完整,我也想知道答案1 问题没有实际价值,缺少关键内容,没有改进余地
一: var obj1 = {name:'one'};
obj2 = Object.create(obj1);
obj2.name = 'two';
console.log(obj1.name);
//one
二: var obj1 = {prop:{name:'one'}};
obj2 = Object.create(obj1);
obj2.prop.name = 'two';
console.log(obj1.prop.name);
//two
三: var obj1 = {list:['one','one','one']};
obj2 = Object.create(obj1);
obj2.list[0] = 'two';
console.log(obj1.list[0]);
//two
为什么后面两段代码修改的是原型链上的属性呢? 问题是,为什么二、三中的代码不是像代码一中直接给obj2添加属性,而是修改了原型链上的属性?
求解释下一、二、三的结果?
6 天前提问 评论
默认排序时间排序
8 个回答 答案对人有帮助,有参考价值1 答案没帮助,是错误的答案,答非所问
问题出在赋值name时上了 只解释下一和二,二和三同理,就不多说了 我们可以看出,Object.create(obj1)都是把obj2的__proto__指向了obj1 但是下面的那么赋值是不一样的 一在赋值前可以输出下obj2.name的值,其实是one,赋值的时候obj2.name,会当成属性去找,但是这时候是把自身的name属性赋值成了two,并不会动obj1中的属性,也就是说对象的属性是无法修改其原型链中的同名属性,而只会自身创建一个同名的属性并为其赋值。 而二在赋值的时候,prop.name是当成一个对象去处理,发现自己没有prop对象,就会去原型链里去找,发现在obj1中找到了name,所以变成了'two' 如果一想达到同样的效果,可以使用obj2.__proto__.name去修改obj1中的name值 自己的理解,如有不对,请指出学习~
6 天前回答 · 6 天前更新 3 评论 gismanli
49 声望
答案对人有帮助,有参考价值1 答案没帮助,是错误的答案,答非所问
个人是觉得楼主对一个Object的get和set操作没有理解透彻。 get操作就是查询作用域中/对象中是否存在某个变量/属性,如果存在,则返回其对应的值。对于写代码的人来说,就是获取某个变量/属性的值,即Get。而Set则与之相反,是往作用域中/对象中的某个变量/属性里存值,即设置值(Set)。 第一个例子
obj2.name = 'two'这句话完成了一个get和一个set。
首先是从当前作用域中get到obj2,发现是存在的,于是得到它的值 {__proto__: {name: 'one'}},这里我把它的和这个题相关的原型链写进去了。浏览器里这个的颜色是偏暗的。
接着便是往obj2中的name属性上set了一个'two'这样的字符串值。 至于这个值为啥没有设置到obj1上的name上,你肯定很好奇,且听我慢慢道来。
往obj2的name属性上set值,在内部会转换成 obj2.[[Set]]('name', 'two', obj2)
你多半看不懂这个O.[[Set]](P, V, R)是什么鬼,它会走如下流程: 让 ownDesc = Object.getOwnPropertyDescriptor(O, P);
如果 ownDesc === undefined,则进入下面步骤:
让 parent = Object.getPrototypeOf(O);
如果 parent !== null 则 执行 parent.[[Set]](P, V, R),并返回其结果;
否则让 ownDesc 等于一个值为空,且可枚举,可配置,可修改的数据描述符。然后进入3
如果 ownDesc 是数据描述符,则进入下面步骤:
如果 ownDesc 不可配置,则返回false;
如果 R 的类型不是Object,则返回false;
让 existingDesc = Object.getOwnPropertyDescriptor(R, P);
如果 existingDesc !== undefined 则进入如下步骤:
如果existingDesc是访问器描述符,则直接返回false;
如果existingDesc是不可修改的数据描述符,则返回false;
在 R 上定义 P 属性,且值为 V,并返回该值。
否则在 R 上创建一个新的 P 属性,且值为 V,并返回该值
(进入到这里,说明ownDesc是个访问器描述符),让 setter = ownDesc.set;
如果 setter === undefined, 返回false;
返回 setter.call(R, V);
这里面的你可能不了解的就是什么是数据描述符,什么是访问器描述符。其实区别他们的很简单,就是看有没有get或set函数,如果有get和set之一或都有,则是访问器描述符,否则就是数据描述符,数据描述符一定有value,value的值可以为undefined; 说到这里,第一个例子走的路线就是 1 -> 2 -> 2.a -> 2.b -> 1 -> 3 -> 3.c -> 3.e
于是就在 obj2本身上创建了一个name属性,二并没有修改到obj1的name属性。 第二个例子
obj2.prop.name = 'two';
这是先在作用域中找 obj2,发现是存在的,于是得到它的值 {__proto__: {prop: {name: 'one'}}}
然后再找 obj2 的 prop 属性。这里就是内部的Get操作了,obj2.prop 会在内部转换成
obj2.[[Get]]('prop', obj2),你又看不懂这个O.[[Get]](P, R)了吧?它其实走的是下面的流程。 让 desc = Object.getOwnPropertyDescriptor(O, P);
如果 desc === undefined,则进入下面流程
让 parent = Object.getPrototypeOf(O);
如果 parent === null,返回 undefiend;
返回 parent.[[Get]](P, R)的结果;
如果 desc 是数据描述符,则返会 desc.value;
此时,desc一定是访问器描述符,则让 getter = desc.get;
如果 getter === undefined, 返回 undefined;
返回 getter.call(R);
于是在获取 obj2.prop时,走的路线如下 1 -> 2 -> 2.a -> 2.c -> 1 -> 3
得到 obj2.prop 的值为 obj1.prop 为 {name: 'one'},
即 obj2.prop === obj1.prop === {name: 'one'};
由于 obj2.prop和obj1.prop 都指向了 {name: 'one'},
所以你再修改obj2.prop的name属性时,便修改了obj1.prop的name属性。 第三个例子,这个和第二个例子类似,获取 obj2.list 的时候也是返回的 obj1.list 的引用,所以都能修改。
6 天前回答 · 6 天前更新 3 评论 solar
2.4k 声望
答案对人有帮助,有参考价值0 答案没帮助,是错误的答案,答非所问
obj2 = Object.create(obj1)是把obj1作为obj2的原型,所以obj2访问的是原型链的属性
6 天前回答 评论 LL89757
291 声望
答案对人有帮助,有参考价值0 答案没帮助,是错误的答案,答非所问
http://www.cnblogs.com/shuiyi/p/5305435.html 刚看到的博客 写的不错
6 天前回答 评论 猴年生猴子
17 声望
答案对人有帮助,有参考价值0 答案没帮助,是错误的答案,答非所问
昨天翻来覆去睡不着,现在才明白原来答错一道题,罪过罪过。。 原因是没有弄清楚Object()的作用,把它当构造函数了。。看别人的答案吧,讲得挺细的。 原答案:
什么原型链啊,这根本就是考察基本类型和引用类型的传值方式。。
原型只存在于函数中,原型链才可以存在于所有引用类型中!
你可以打印一下obj1.prototype(原型),obj1.__proto__(原型链)。 关于传值,看下面的例子: a = 1;
b = a;
b = 2;
console.log(a);// a = {val: 1};
b = a;
b.val = 2;
console.log(a.val);// a = {val: 1};
b = a;
b = {val :2}; //注意这里,重写了b,这时b和a没半毛钱关系了!
console.log(a.val);//
只能帮你到这了,自己悟去吧。。
6 天前回答 · 6 天前更新 3 评论 hiYoHoo
1.9k 声望
+1
obj2对象中的prop属性已经在obj2内存中开辟了一块空间,只不过引用了obj1的属性值。换句话说,obj2已经具备了的prop这个属性,它并不需要从原型链上找,即使找,也不会去找obj1对象本身的属性。 hiYoHoo · 6 天前 展开评论
答案对人有帮助,有参考价值0 答案没帮助,是错误的答案,答非所问
自己找不到,就会去原型链上面找。
第一个例子,obj1有name这个属性,value是1,所以就是1.
第二个例子,obj1有一个属性叫prop,obj2没有这个属性,obj1是obj2的原型,是object.create()构造器赋予的,所以obj2的prop就找到了原型的prop,但是prop是个对象,所以这里存储的实际上是一个引用,也就是说,obj2也是找到了这个引用。相当于obj2._proto_.prop,改掉了引用的prop这个对象的name,obj1的引用没变,但是prop的name变了。
第三个例子和第二个也一样。
6 天前回答 · 6 天前更新 评论 zhangway19921221
3 声望
答案对人有帮助,有参考价值0 答案没帮助,是错误的答案,答非所问
Object.create方法指定的第1个参数为新建对象的原型对象
在获取一个对象的属性值时,才会有可能沿着原型链向下寻找,属性赋值没有这个
给一个对象属性赋值时,如果这个属性不存在,那么就直接为这个对象添加这个属性并赋值(不会去理会原型链中的存在,除了某些特殊情况,如原型链中有这个属性的set方法,或这个属性被设置只读不可写的)
obj2.prop.name='two' 先计算obj2.prop的值,在原型链中被发现,然后再计算obj2.prop对应的对象(不检查原型链)中是否存在name属性~~~
obj2.list[0] = 'two';
也就是先计算obj2.list属性的值,然后赋值给obj2.list属性下标为0(属性名为“0”)的属性
那么结果就好理解了吧
6 天前回答 评论
关于Object.create()与原型链的面试题?的更多相关文章
- js关于原型,原型链的面试题
		
之前面试的时候遇到过原型和原型链方面的题目,具体的已经忘了,只记得当时回答的稀里糊涂,今天查了一些资料,把自己所理解的写出来,加深记忆. 1,前提 在js中,对象都有__proto__属性,一般这个是 ...
 - JavaScript原型链以及Object,Function之间的关系
		
JavaScript里任何东西都是对象,任何一个对象内部都有另一个对象叫__proto__,即原型,它可以包含任何东西让对象继承.当然__proto__本身也是一个对象,它自己也有自己的__proto ...
 - 探索js原型链和vue构造函数中的奥妙
		
这篇文章首先会讲到原型链以及原型链的一些概念,然后会通过分析vue的源码,来看一下vue的构造函数是如何被创建的,now we go! 一.什么是原型链? 简单回顾下构造函数,原型和实例的关系: ...
 - 前端入门15-JavaScript进阶之原型链
		
声明 本系列文章内容全部梳理自以下几个来源: <JavaScript权威指南> MDN web docs Github:smyhvae/web Github:goddyZhao/Trans ...
 - JavaScript学习总结(四)——this、原型链、javascript面向对象
		
一.this 在JavaScript中this表示:谁调用当前函数this就指向谁,不知道调用者时this指向window. JavaScript是由对象组成的,一切皆为对象,万物皆为对象.this是 ...
 - 简单说一说对JavaScript原型链的理解
		
每一个JavaScript对象都和另一个对象相关联,相关联的这个对象就是我们所说的“原型”.每一个对象都会从原型继承属性和方法.有一个特殊的对象没有原型,就是Object,还有一种通过Object.c ...
 - JS基础-该如何理解原型、原型链?
		
JS的原型.原型链一直是比较难理解的内容,不少初学者甚至有一定经验的老鸟都不一定能完全说清楚,更多的"很可能"是一知半解,而这部分内容又是JS的核心内容,想要技术进阶的话肯定不能对 ...
 - JS基础-原型链和继承
		
创建对象的方法 字面量创建 构造函数创建 Object.create() var o1 = {name: 'value'}; var o2 = new Object({name: 'value'}); ...
 - 一篇JavaScript技术栈带你了解继承和原型链
		
作者 | Jeskson 来源 | 达达前端小酒馆 1 在学习JavaScript中,我们知道它是一种灵活的语言,具有面向对象,函数式风格的编程模式,面向对象具有两点要记住,三大特性,六大原则. 那么 ...
 
随机推荐
- Untiy3D按方向键获取值
			
一,如下代码 float h = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical" ...
 - 用URLGather来管理和保存你的页面
			
下载链接:http://url-gather.software.informer.com/download/#downloading 安装的过程简单,这里不一一叙述. 安装成功后,找到软件安装的路径, ...
 - kali优化配置(3)--工具箱
			
1.netcat 收集信息.Telnet/banner.传输文本信息.连接服务器端口. *通过IP,连接服务器端口: *信息通信: *重定向符号:> (e.g:>>ps.txt:重定 ...
 - 【串线篇】spring boot配置文件加载位置
			
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件 (1)–file:./config/ ...
 - 一次Oday提权批量拿取商城服务器root权限
			
此问题影响范围巨大,涉及到所有通过niushop开发的商城,希望通过这篇文章能够引起大家的重视.(注:演示的所用商城已经修复了此漏洞) 严重性:特级 解决方案:1.在用户访问漏洞页时对其身份进行判断: ...
 - Js中window.location.href和window.location.replace的区别
			
href相当于打开一个新页面,replace相当于替换当前页面:这里打开页面都是针对历史记录来说,在页面上看完全相同,只是浏览器的history表现不同如果在1.html中点击链接到2.html,然后 ...
 - hdu 6053: TrickGCD  (2017 多校第二场 1009) 【莫比乌斯 容斥原理】
			
题目链接 定义f[n]表示n是最大公约数情况下的计数,F[n]为n是公约数情况下的计数 (可以和 http://www.cnblogs.com/Just--Do--It/p/7197788.html ...
 - 【leetcode】1051. Height Checker
			
题目如下: Students are asked to stand in non-decreasing order of heights for an annual photo. Return the ...
 - idhttp.get返回403错误解决办法
			
在GET之前,先指定UserAgent参数IdHTTP1.Request.UserAgent := 'Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Ma ...
 - vue 3.0 vue-cli项目搭建要点
			
一.使用vue-cli搭建项目(可使用vue ui图形化界面搭建项目,配置dist时,将名称设为项目名称) 二.项目搭建后 1.配置vue.config.js // 翻阅文档https://cli.v ...