getting-started-with-javascript icon indicating copy to clipboard operation
getting-started-with-javascript copied to clipboard

【10.1练习】

Open xugy0926 opened this issue 6 years ago • 19 comments

用typeof obj ==='object' 判断obj是否是一个object。

事例代码

var obj = {
  name: 'xiaoming'
}
    
function output(obj) {
  if (typeof obj === 'object') {
    console.log(obj.name);
  } else {
    console.log('obj is not a object');
  }
}
    
output(obj);

以上代码有缺陷吗?如果有改如何改进?

xugy0926 avatar Oct 01 '17 05:10 xugy0926

把"===" 换成"=="

antarts avatar Oct 01 '17 06:10 antarts

3行'}'后面少了';'

yousl avatar Oct 01 '17 06:10 yousl

我认为。不需要写成函数直接if { } else {} 就可以了

var obj = { name: 'xiaoming' } if (typeof obj === 'object') { console.log(obj.name); } else { console.log('obj is not a object'); } }

choudac avatar Oct 01 '17 06:10 choudac

1、我觉得把这种情况写在前面会比较——obj不是一个object的时候。然后else接下去判断obj是object的情况。 2、当obj是object类型的时候,它有可能是一个空对象,或是对象里面根本就没有name属性,而且如果对象的属性名是数字或是表达式的时候,是不能通过obj.这种形式访问的。 3、开头就定义对象的话,就会把对象给写死。我觉得还是在函数的参数里面输入对象会比较好。 function output(obj) { if (typeof obj !== 'object') { console.log('obj is not a object'); } else { if (Object.getOwnPropertyNames(obj).length === 0) { console.log('obj is an empty object'); } else { console.log(obj); } } } output(2); output(obj = {}); output(obj = {name: 'xiaoming', 5: true});

cicilinwang avatar Oct 01 '17 07:10 cicilinwang

传入 function的时候,不能准确判断类型。(function也是对象,而typeof fucntion 的返回值是'function')

使用instanceof Object 可能更方便些。

var obj = {
  name : 'xiaoming';
}

function output (obj){
  if (obj instanceof Object){
    console.log('obj is a object');
  } else{
    console.log('obj is not a object');
  }
}

output(obj);

测试:

var tester_1 = {name:'xiaoming',sex:'male'};
var tester_2 = function(){return 'this is a function'};
output(tester_1);    //obj is a object
output(tester_2);    //obj is a object

题外话

instanceof 操作符以一个对象和一个构造函数为参数。如果对象是构造函数所指定的类型的一个实例(instance),instanceof 返回 true。否则返回false。 而所有对象都是Object的实例,故使用 Instanceof Object 可以很方便的判断一个变量是否是object。 ——以上知识获取自《Javascript面向对象精要》1.6节

zjutszl avatar Oct 01 '17 08:10 zjutszl

学习过程:

1.一行行研习代码:首先是用“对象直接量”的办法创建了一个对象,犀牛书120页6.1.1,研习了一下什么情况下对象的属性名要加引号,尝试在name上加引号和不加引号都可以运行代码;

2.typeof: 印象中,课上演示的代码里typeof都会加(),尝试了一下是否加()代码都可以运行;

3.函数,if...else...都能看懂了

4.思考为什么,写这段代码的目的是为了干嘛?

这段代码的译文:如果obj是一个对象,则输出这个对象的name属性值,如果不是一个对象,则输出一个结果表示obj不是一个对象。

思考:如果是为了判别一个名字为obj的东西是否是一个对象,首先,作为写代码的人自己得知道自己写的是什么,如果实在不知道,直接输typeof(obj)输出结果就好了吧,为什么要用if...else这么复杂的办法?而且为什么要指定输出属性为name的值?我猜得在上下文的场景下才能理解到这么做的必要性。就像阅读理解中上下文的衔接,不可以断章取义。

5.再看回标题“用typeof obj ==='object' 判断obj是否是一个object”,这样的话直接

console.log(typeof obj ==='object’)

就可以了吧,返回true,不知道这不是是就是所谓的一行代码可以搞定的事情就不要兴师动众。

Ideal-Li avatar Oct 01 '17 08:10 Ideal-Li

1.分析下output的功能:利用typeof判断输入的参数的类型是不是一个对象。 2.问题出现在第7行:object.name。函数的目的是判断参数类型是否为对象,即便它是对象,我们也不能肯定它一定有一个name属性。当对象没有name属性时,会输出一个undefined。所以这里用object.name是不合适的。 3.修改后的代码:

var obj_1 = {
  name: 'xiaoming',
  age:26,
  weight:60
}
var test = 1;

function output(obj) {
  if (typeof obj === 'object') {
    console.log('This is an object.');
    var prop;
    for(prop in obj){
        console.log("It has a " +"'" + prop + "'"+ " property");
    }
  } else {
    console.log('Obj is not an object.');
  }
}

output(obj_1);
output(test);

输出为:

This is an object.
It has a 'name' property
It has a 'age' property
It has a 'weight' property
Obj is not an object.

4.理想的输出结果为:

obj_1 is an object.
test is not an object.

貌似涉及到什么JS反射技术,没搞懂。。。

yanqingmu avatar Oct 01 '17 09:10 yanqingmu

有缺陷。

1、因为typeof null的结果也是object,但在js中null实际上并不是对象,为保证obj = null时也能正确判断,所以需要加上对null的判断if (typeof obj === 'object' && obj !== null) ;

2、如果该函数是用于判断任意变量或直接量是否是对象的,那么使用obj.name就不合逻辑了。因为不是所有对象都有name的属性的。为了和else的结果对应,为对象时输出console.log(‘obj is an object')比较符合写函数的目的。

=> 老师的补充

  1. output函数在接收参数传入时,如果参数正好是null,null也是object类型,而null.name会导致代码运行报错。因此一定要排除特殊情况null。

  2. 至于传入的obj是否有无name,这个最少不会导致代码运行出错,obj.name即使没有也会默认输出一个undefined。是否必要判断obj中存不存在name,可以依据具体的业务情况来定夺。

freedomsky11 avatar Oct 01 '17 11:10 freedomsky11

定义变量obj并赋值,一般后边会加个分号。这个不算问题就不提了 这个主要是参数判断问题 具体讲 本函数的作用 是 输出 对象的 某个属性值。 那就要两个前提:

  1. 是否是对象(对象是否存在)
  2. 是否有某个属性 如果没有属性 那么结果就是 undefined 我认为可以这么写:
function output(obj){
	if (typeof obj === 'object') {
// 如果 name 属性存在 那么打印值
		if (obj.name) {
			console.log(obj.name);
		} else {
			console.log('不存在name属性');
		}

	} else {
		console.log('obj is not a  object');
	}
}

可以简单写成这样

function output(obj) {
	if (obj && obj.name) {
		console.log(obj.name);
	}else{
		console.log('对象 不存在 或者 对象不没有name属性' );
	}
}

我自己有个问题,但是跟这个无关。 我做了个webapp可以在微信中分享,但是分享出去没有缩略图,打开分享过的链接分享就有缩略图了,不知道怎么回事。本来分享的图片是相对路径,不行换成了http链接,此链接在微信配置的域名下。

这是实际项目开发中遇到的问题。链接在微信中打开,没做pc端的兼容和适配。 http://www.id-bear.com/node/moon/moon 核心代码如下, 前提 微信配置是成功的,配置项有:

var = jsApiList = [
      "chooseImage",
      "uploadImage",
      "menuItem:share:appMessage",
      "menuItem:share:timeline",
      "getNetworkType",
      "onMenuShareTimeline",
      "onMenuShareAppMessage",
      "hideMenuItems",
      "checkJsApi"
    ];
  // 微信配置
 wx.config(wxglobleconfig);
wx.ready(function() {
      wx.hideMenuItems({
        menuList: [
          "menuItem:share:qq",
          "menuItem:share:weiboApp",
          "menuItem:favorite",
          "menuItem:share:facebook",
          "menuItem:share:QZone",
          "menuItem:openWithSafari",
          "menuItem:share:brand"
        ], // 要隐藏的菜单项,只能隐藏“传播类”和“保护类”按钮,所有menu项见附录3
        success: function(res) {
          //alert("隐藏");
        }
      });

      wx.showMenuItems({
        menuList: ["onMenuShareAppMessage", "onMenuShareTimeline"] // 要显示的菜单项,所有menu项见附录3
      });
    });

    var initWxShareTimeObj = {
      title: "我有几句话藏在月亮里想对你说", // 分享标题
      link: sharedurl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
      imgUrl: "http://www.id-bear.com/node/moon/images/sharedimg.jpg", // 分享图标
      success: function () {
          // 用户确认分享后执行的回调函数
      },
      cancel: function () {
          // 用户取消分享后执行的回调函数
          alert('您取消了分享');
      }
  };

  var initWxShareAppMessage = {
      title: "我有几句话藏在月亮里想对你说", // 分享标题
      desc: "明月寄相思 天涯共此时 ", // 分享描述
      link: sharedurl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
      imgUrl: "http://www.id-bear.com/node/moon/images/sharedimg.jpg", // 分享图标
      type: "link", // 分享类型,music、video或link,不填默认为link
      dataUrl: "", // 如果type是music或video,则要提供数据链接,默认为空
      success: function () {
          // 用户确认分享后执行的回调函
      },
      cancel: function () {
          // 用户取消分享后执行的回调函数
          alert('您取消了分享');
      }

  };


  setTimeout(function () {

      // 分享到朋友圈
      wx.onMenuShareTimeline(initWxShareTimeObj);
      // 分享给朋友
      wx.onMenuShareAppMessage(initWxShareAppMessage);

  }, 2000);

    wx.error(function(res) {
      console.log("错误",res);
    });
  })

哎,遇到的问题太多了。 安卓用户 在 切换到 新的 href 之后 分享功能就失效了。新的href也是经过配置的。iOS就可以,iOS用户不关在哪个href下都可以。

MyColourfulLife avatar Oct 01 '17 15:10 MyColourfulLife

js 如何准确判断变量是否是对象

typeof

在 js 中,如果需要判断数据类型,可能首先想到用 typeof操作符,但实际上,这并不准确。 这可能跟 js 这门语言在当初被设计的时候,时间比较仓促有关。

下表是各种 value 的数据类型的 typeof 操作符的运算结果。

Value               function   typeof
-------------------------------------
null                Null       object
undefined           Undefined  undefined
"foo"               String     string
new String("foo")   String     object
1.2                 Number     number
new Number(1.2)     Number     object
true                Boolean    boolean
new Boolean(true)   Boolean    object
new Date()          Date       object
new Error()         Error      object
[1,2,3]             Array      object
new Array(1, 2, 3)  Array      object
new Function("")    Function   function
/abc/g              RegExp     object
new RegExp("meow")  RegExp     object
{}                  Object     object
new Object()        Object     object 

可见,null、array 以及所有用类(class)的实例(instance)创建的对象 的 typeof 操作符的运算结果都是 object。 一般来说,typeof 在实际使用过程中,有两个用处,一个是判断变量是否被定义,其次可以判断变量是否是 function。

typeof a !== 'undefined';
typeof b !== 'function';

instanceof

还有一个操作符跟 typeof 类似,叫 Instanceof,实际上,instanceof 常用的场景是可以用来判断一个对象是否是不是一个类(class)的实例。

new String() instanceof String; // true
new Array() instanceof Array; // true

正确的判断数据类型的方法

公认的靠谱的解决方案是 Object.prototype.toString.call(x)

Object.prototype.toString.call([])    // "[object Array]"
Object.prototype.toString.call({})    // "[object Object]"
Object.prototype.toString.call(2)    // "[object Number]"

我的解法

因此我的解法是:

var obj = {
  name: "xiaoming"
};

var a = [1,2,3];
var b = null;
var c = new String("hello,js");

function output(obj) {
  if (Object.prototype.toString.call(obj) === "[object Object]") {
    console.log(obj.name);
  } else {
    console.log("obj is not a object");
  }
}

output(obj);
output(a);
output(b);
output(c);

yammyxing avatar Oct 01 '17 16:10 yammyxing

var obj = { name: 'xiaoming' }

if (typeof obj === 'object') console.log(obj.name); else console.log('obj is not a object')

目前的分析: 这道题的目的是判断obj是不是object。 所以核心部分:

  1. var定义对象obj
  2. typeof()运算符进行判断:typeof运算“任意内置对象(非函数)”后返回值="object" // 犀牛6版P87
  3. if只是为了显示一个代表结果的值,把typeof结果显示出来。

其他部分,能减少就减少。 以下是减少部分及原因:

  1. function()是为了定义一个新的函数,而咬紧题目,只需typeof()判断。
  2. output:是不是有这个函数或语句,先不管它。在题干里,第一个output只是函数名称,如果题目涉及其他运算,考虑保留;实际没有涉及,所以这个output可忽略。第二个output好像有点功能,但是跟console()功能重复,所以选择去掉。
  3. 把if里的花括号也全部去掉了,不知可不可以。考虑去掉的原因:一个是以前看到过if语句没有用花括号(这理由汗么?),另一个是去掉了也能在node里输出。但如果保留,会不会比严谨。

  • 为什么GITHUB不能显示备注的名称的呢........像老师的名字也是XUGY不是XUGAOYANG
  • 是不是 var 也最好放在function()里面? 自言自语:说错。var是应该在function()外面,因为function()的”函数体代码的编译总是会在顶层函数执行“,理解为”function里出现的形参要提前声明,即在function上层声明。// 犀牛6版P95
  • 变量可以这样写吗?不是"var = ___ "这样吗? 无聊的自言自语:艾呀,说错了。 也没说清楚... (犯过的错,印象比较深刻)

黄碧玲

ifoundu avatar Oct 01 '17 16:10 ifoundu

等号用“==”。==可以对等式左右的类型进行灵活转换,但严格模式下(===)并不真的相等。犀牛书P50讲到这点。

shashawang avatar Oct 01 '17 17:10 shashawang

我的补充追记在 @freedomsky11 的回复里。

修正后的代码

var obj = {
  name: 'xiaoming'
}
   
function output(obj) {
  if (!obj && typeof obj === 'object') {
    console.log(obj.name);
  } else {
    console.log('obj is not a object');
  }
}
    
output(obj);

xugy0926 avatar Oct 02 '17 03:10 xugy0926

@Yammmy 你的解法没问题

xugy0926 avatar Oct 02 '17 04:10 xugy0926

@tiandimeihua 总结很到位,object.prototype.toString.call() 来解决也正确。

xugy0926 avatar Oct 02 '17 04:10 xugy0926

用typeof obj ==='object' 判断obj是否是一个object

这道题的关键点在于,用 typeof obj === 'object' 判断object是否是一个object,是否会出现漏洞? 这里有2个难点:

  1. 理解tpyeof
  2. 理解===

解决第一个问题

87页里面有介绍typeof,首先,返回的数据类型是字符串,不过里面显示null,所有内置对象(非函数)都是返回‘’object‘’的值。
这说明:obj的值是 null,array时,typeof都会返回一个object
设置几种情况:
var a = [1,2,3];时,运行,发现是undefined,程序未报错,但name的值undefined。
var b = null;时,运行,程序直接报错,TypeError: Cannot read property 'name' of null.
这里还是有区别的,返回undfined时,是运行了函数,只是没有name属性。

var c = {ab:123};时,如果对象c没有name属性,运行程序,发现也是undefined,说明老师的函数是包容了array的错误,但没有包容null的错误。

老师后面给了答案,就是加上了判定obj是null的情况。

解决第二个问题

74页里面有介绍"===严格相等运算符” 和“==相等运算符”,里面显示,===是不会进行类型转换,而==会进行类型转换,不过typeof返回的数据类型就是字符串,和这里的‘’object”比较,不会进行类型转换,故而都可以,不过也设计一些变量来检查下;

d = ‘abc’; // d是一个字符串时;
e = 5;  // e是一个数值时;
f = undined;  // 假如f的值是一个undfined时

然后把,===变成==,是可以运行下去的,不过依然无法兼容null的错误,故而只需要把null的情况排除即可。
不过还是需要告诉读者,假如obj是一个array,虽然它是会返回一个对象,不过它的name属性未被定义,或obj没有name属性。

var obj = [123,222];
function ouput(obj) {
	// body...
	if (typeof obj === 'object' && obj !== null) {
		console.log('obj is a ' + typeof(obj));
		if ('name' in obj) {
			console.log('obj的name值:' + obj.name);
		} else {
			console.log('obj没有name属性');
		}
	} else {
		console.log('obj is not a object');
	}
};

ouput(obj);

WangZhong2014 avatar Oct 02 '17 05:10 WangZhong2014

看了老师的评论和回复,似乎 重点落在了对 空对象的判断上了。 无论如何这里都用到了条件判断,而条件判断的结果无非就是ture/false(1/0), 可以使用 if(obj === null) 来表示 obj 为null 也可以使用 if(!obj) 来obj为null 当然也可以用if(obj)表示存在,lian。 所以下面的结果 即是赋值了空值,也是不会出问题的。

var obj = null;
output(obj);
// 可以简单写成这样
function output(obj) {
	if (obj && obj.name) {
		console.log(obj.name);
	}else{
		console.log('对象 不存在 或者 对象不没有name属性' );
	}
}

甚至可以排除掉 未定义的值 以及其他非真值。

var obj = undefined;
output(obj);

MyColourfulLife avatar Oct 02 '17 06:10 MyColourfulLife

分析这道题目可以知道,不仅要判断obj是不是对象,还要判断obj是对象的时候,有没有name这个属性。

  1. 根据犀牛书上的知识点可以知道,对于非对象类型的直接量或变量,只有typeof null === 'object' 这个表达式的值为真,也就是说用 typeof 方法来判断一个直接量或变量是否为对象的话,要考虑到 null 这个特殊情况。
  2. 要判断传入的参数是否为 null 很简单,用 !!null 即可,这里是逻辑非运算符相关的知识点。
  3. 还要判断传入的参数是否有 name 属性,这个其实也不难,因为如果传入的对象没有 name 属性的话,obj.name 这个表达式的值就是 undefined,注意这里的 undefined 是数据类型,而不是字符串。这样的话,就可以直接用 obj.name 这个表达式来判断对象是否有指定的属性。 总结以上三点,最后的代码如下所示:
var obj = {
  name: 'xiaoming'
}
    
function output(obj) {
  if (!!obj && typeof obj == 'object' && obj.name) {
    console.log(obj.name);
  } else {
    console.log('obj is not a object');
  }
}
    
output(obj);

PS:再推荐大家看一下阮一峰写的《如何判断Javascript对象是否存在》

Dream4ever avatar Oct 02 '17 23:10 Dream4ever

知识点

  1. Typeof 运算符,返回操作数所对应的类型(字符串)
var i = 3
typeof(i) = 'number'
  1. 属性访问表达式,在对象名称后方跟随一个句点(.),在句点后方跟随要访问的对象的属性名称。例如:
var boy ={                      //构建一个名为boy的对象
       name ='xiaoming',
       height = 175,
}
var nameString =boy.name    //访问boy对象的name属性,并赋值给一个变量。
  1. 逻辑表达式&&(与) &&对两个操作数(布尔值,如果不是布尔值则会进行类型转换)都进行(AND)操作,只有在两个操作数都是true的时候,它才会返回true。
  2. 条件语句if
If (expression){         //如果expression 判断为真值,则执行以下的statement
   Statement
}

解题思路

而从题目的代码可以看出,函数是在判断定义的object是否是一个'object' 但是在犀牛书关于typeof运算符返回值的表格当中,可以看到除了任意对象之后,还有null 会让typeof 返回“objecct”,于是我们在使用条件判断的时候一定要把null这个干扰项排除(使用&&表达式)。 并且题目代码在typeof object ===“object”的值为真的时候,会输出对象name属性的内容,但是我们并不能确保任何对象都存在name属性。

修改后的代码

var obj = {
  name: 'xiaoming'
}
    
function output(obj) {
  if (typeof obj == 'object' &&  obj !==null) {
    console.log('obj is a object ');
  } else {
    console.log('obj is not a object');
  }
}
    
output(obj);

Risexie avatar Oct 22 '17 13:10 Risexie